OSDN Git Service

firewall4: refresh fullcone patch
[immortalwrt/immortalwrt.git] / package / network / services / dnsmasq / files / dnsmasq.init
1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2007-2012 OpenWrt.org
3
4 START=19
5
6 USE_PROCD=1
7 PROG=/usr/sbin/dnsmasq
8
9 ADD_LOCAL_DOMAIN=1
10 ADD_LOCAL_HOSTNAME=1
11 ADD_WAN_FQDN=0
12 ADD_LOCAL_FQDN=""
13
14 BASECONFIGFILE="/var/etc/dnsmasq.conf"
15 BASEHOSTFILE="/tmp/hosts/dhcp"
16 TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf"
17 TIMEVALIDFILE="/var/state/dnsmasqsec"
18 BASEDHCPSTAMPFILE="/var/run/dnsmasq"
19 DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf"
20 RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf"
21 DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
22 DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus"
23
24 DNSMASQ_DHCP_VER=4
25
26 dnsmasq_ignore_opt() {
27         local opt="$1"
28
29         if [ -z "$dnsmasq_features" ]; then
30                 dnsmasq_features="$(dnsmasq --version | grep -m1 'Compile time options:' | cut -d: -f2) "
31                 [ "${dnsmasq_features#* DHCP }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp=1
32                 [ "${dnsmasq_features#* DHCPv6 }" = "$dnsmasq_features" ] || dnsmasq_has_dhcp6=1
33                 [ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1
34                 [ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1
35                 [ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1
36         fi
37
38         case "$opt" in
39                 dhcp-duid|\
40                 ra-param)
41                         [ -z "$dnsmasq_has_dhcp6" ] ;;
42                 dhcp-*|\
43                 bootp-*|\
44                 pxe-*)
45                         [ -z "$dnsmasq_has_dhcp" ] ;;
46                 dnssec*|\
47                 trust-anchor)
48                         if [ -z "$dnsmasq_has_dnssec" ]; then
49                                 echo "dnsmasq: \"$opt\" requested, but dnssec support is not available" >&2
50                                 exit 1
51                         fi
52                         return 1
53                         ;;
54                 tftp-*)
55                         [ -z "$dnsmasq_has_tftp" ] ;;
56                 ipset)
57                         [ -z "$dnsmasq_has_ipset" ] ;;
58                 *)
59                         return 1
60         esac
61 }
62
63 xappend() {
64         local value="${1#--}"
65         local opt="${value%%=*}"
66
67         if ! dnsmasq_ignore_opt "$opt"; then
68                 echo "$value" >>$CONFIGFILE_TMP
69         fi
70 }
71
72 hex_to_hostid() {
73         local var="$1"
74         local hex="${2#0x}" # strip optional "0x" prefix
75
76         if [ -n "${hex//[0-9a-fA-F]/}" ]; then
77                 # is invalid hex literal
78                 return 1
79         fi
80
81         # convert into host id
82         export "$var=$(
83                 printf "%0x:%0x" \
84                 $(((0x$hex >> 16) % 65536)) \
85                 $(( 0x$hex        % 65536))
86                 )"
87
88         return 0
89 }
90
91 dhcp_calc() {
92         local ip="$1"
93         local res=0
94
95         while [ -n "$ip" ]; do
96                 part="${ip%%.*}"
97                 res="$(($res * 256))"
98                 res="$(($res + $part))"
99                 [ "${ip%.*}" != "$ip" ] && ip="${ip#*.}" || ip=
100         done
101         echo "$res"
102 }
103
104 dhcp_check() {
105         local ifname="$1"
106         local stamp="${BASEDHCPSTAMPFILE_CFG}.${ifname}.dhcp"
107         local rv=0
108
109         [ -s "$stamp" ] && return $(cat "$stamp")
110
111         # If interface is down, skip it.
112         # The init script will be called again once the link is up
113         case "$(devstatus "$ifname" | jsonfilter -e @.up)" in
114                 false) return 1;;
115         esac
116
117         udhcpc -n -q -s /bin/true -t 1 -i "$ifname" >&- && rv=1 || rv=0
118
119         echo $rv > "$stamp"
120         return $rv
121 }
122
123 log_once() {
124         pidof dnsmasq >/dev/null || \
125                 logger -t dnsmasq "$@"
126 }
127
128 has_handler() {
129         local file
130
131         for file in /etc/hotplug.d/dhcp/* /etc/hotplug.d/tftp/* /etc/hotplug.d/neigh/*; do
132                 [ -f "$file" ] && return 0
133         done
134
135         return 1
136 }
137
138 append_bool() {
139         local section="$1"
140         local option="$2"
141         local value="$3"
142         local default="$4"
143         local _loctmp
144         [ -z "$default" ] && default="0"
145         config_get_bool _loctmp "$section" "$option" "$default"
146         [ $_loctmp -gt 0 ] && xappend "$value"
147 }
148
149 append_parm() {
150         local section="$1"
151         local option="$2"
152         local switch="$3"
153         local default="$4"
154         local _loctmp
155         config_get _loctmp "$section" "$option" "$default"
156         [ -z "$_loctmp" ] && return 0
157         xappend "$switch=$_loctmp"
158 }
159
160 append_server() {
161         xappend "--server=$1"
162 }
163
164 append_rev_server() {
165         xappend "--rev-server=$1"
166 }
167
168 append_address() {
169         xappend "--address=$1"
170 }
171
172 append_ipset() {
173         xappend "--ipset=$1"
174 }
175
176 append_connmark_allowlist() {
177         xappend "--connmark-allowlist=$1"
178 }
179
180 append_interface() {
181         network_get_device ifname "$1" || ifname="$1"
182         xappend "--interface=$ifname"
183 }
184
185 append_listenaddress() {
186         xappend "--listen-address=$1"
187 }
188
189 append_notinterface() {
190         network_get_device ifname "$1" || ifname="$1"
191         xappend "--except-interface=$ifname"
192 }
193
194 ismounted() {
195         local filename="$1"
196         local dirname
197         for dirname in $EXTRA_MOUNT ; do
198                 case "$filename" in
199                         "${dirname}/"* | "${dirname}" )
200                                 return 0
201                                 ;;
202                 esac
203         done
204
205         return 1
206 }
207
208 append_addnhosts() {
209         ismounted "$1" || append EXTRA_MOUNT "$1"
210         xappend "--addn-hosts=$1"
211 }
212
213 append_bogusnxdomain() {
214         xappend "--bogus-nxdomain=$1"
215 }
216
217 append_pxe_service() {
218         xappend "--pxe-service=$1"
219 }
220
221 append_interface_name() {
222         xappend "--interface-name=$1,$2"
223 }
224
225 filter_dnsmasq() {
226         local cfg="$1" func="$2" match_cfg="$3" found_cfg
227
228         # use entry when no instance entry set, or if it matches
229         config_get found_cfg "$cfg" "instance"
230         if [ -z "$found_cfg" ] || [ "$found_cfg" = "$match_cfg" ]; then
231                 $func $cfg
232         fi
233 }
234
235 dhcp_subscrid_add() {
236         local cfg="$1"
237
238         config_get networkid "$cfg" networkid
239         [ -n "$networkid" ] || return 0
240
241         config_get subscriberid "$cfg" subscriberid
242         [ -n "$subscriberid" ] || return 0
243
244         xappend "--dhcp-subscrid=set:$networkid,$subscriberid"
245
246         config_get_bool force "$cfg" force 0
247
248         dhcp_option_add "$cfg" "$networkid" "$force"
249 }
250
251 dhcp_remoteid_add() {
252         local cfg="$1"
253
254         config_get networkid "$cfg" networkid
255         [ -n "$networkid" ] || return 0
256
257         config_get remoteid "$cfg" remoteid
258         [ -n "$remoteid" ] || return 0
259
260         xappend "--dhcp-remoteid=set:$networkid,$remoteid"
261
262         config_get_bool force "$cfg" force 0
263
264         dhcp_option_add "$cfg" "$networkid" "$force"
265 }
266
267 dhcp_circuitid_add() {
268         # TODO: DHCPV6 does not have circuitid; catch "option6:"
269         local cfg="$1"
270
271         config_get networkid "$cfg" networkid
272         [ -n "$networkid" ] || return 0
273
274         config_get circuitid "$cfg" circuitid
275         [ -n "$circuitid" ] || return 0
276
277         xappend "--dhcp-circuitid=set:$networkid,$circuitid"
278
279         config_get_bool force "$cfg" force 0
280
281         dhcp_option_add "$cfg" "$networkid" "$force"
282 }
283
284 dhcp_userclass_add() {
285         local cfg="$1"
286
287         config_get networkid "$cfg" networkid
288         [ -n "$networkid" ] || return 0
289
290         config_get userclass "$cfg" userclass
291         [ -n "$userclass" ] || return 0
292
293         xappend "--dhcp-userclass=set:$networkid,$userclass"
294
295         config_get_bool force "$cfg" force 0
296
297         dhcp_option_add "$cfg" "$networkid" "$force"
298 }
299
300 dhcp_vendorclass_add() {
301         # TODO: DHCPV6 vendor class has stricter definitions; catch? fixup?
302         local cfg="$1"
303
304         config_get networkid "$cfg" networkid
305         [ -n "$networkid" ] || return 0
306
307         config_get vendorclass "$cfg" vendorclass
308         [ -n "$vendorclass" ] || return 0
309
310         xappend "--dhcp-vendorclass=set:$networkid,$vendorclass"
311
312         config_get_bool force "$cfg" force 0
313
314         dhcp_option_add "$cfg" "$networkid" "$force"
315 }
316
317 dhcp_match_add() {
318         local cfg="$1"
319
320         config_get networkid "$cfg" networkid
321         [ -n "$networkid" ] || return 0
322
323         config_get match "$cfg" match
324         [ -n "$match" ] || return 0
325
326         xappend "--dhcp-match=set:$networkid,$match"
327
328         config_get_bool force "$cfg" force 0
329
330         dhcp_option_add "$cfg" "$networkid" "$force"
331 }
332
333 dhcp_host_add() {
334         local cfg="$1"
335         local hosttag nametime addrs duids macs tags mtags
336
337         config_get_bool force "$cfg" force 0
338
339         config_get networkid "$cfg" networkid
340         [ -n "$networkid" ] && dhcp_option_add "$cfg" "$networkid" "$force"
341
342         config_get_bool enable "$cfg" enable 1
343         [ "$enable" = "0" ] && return 0
344
345         config_get name "$cfg" name
346         config_get ip "$cfg" ip
347         config_get hostid "$cfg" hostid
348
349         [ -z "$ip" ] && [ -z "$name" ] && [ -z "$hostid" ] && return 0
350
351         config_get_bool dns "$cfg" dns 0
352         [ "$dns" = "1" ] && [ -n "$ip" ] && [ -n "$name" ] && {
353                 echo "$ip $name${DOMAIN:+.$DOMAIN}" >> $HOSTFILE_TMP
354         }
355
356         config_get mac "$cfg" mac
357         config_get duid "$cfg" duid
358         config_get tag "$cfg" tag
359
360         add_tag() {
361                 mtags="${mtags}tag:$1,"
362         }
363         config_list_foreach "$cfg" match_tag add_tag
364
365         if [ -n "$mac" ]; then
366                 # --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap
367                 # many MAC are possible to track a laptop ON/OFF dock
368                 for m in $mac; do append macs "$m" ","; done
369         fi
370
371         if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ -n "$duid" ]; then
372                 # --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap
373                 # one (virtual) machine gets one DUID per RFC3315
374                 duids="id:${duid// */}"
375         fi
376
377         if [ -z "$macs" ] && [ -z "$duids" ]; then
378                 # --dhcp-host=lap,192.168.0.199,[::beef]
379                 [ -n "$name" ] || return 0
380                 macs="$name"
381                 name=""
382         fi
383
384         if [ -n "$hostid" ]; then
385                 hex_to_hostid hostid "$hostid"
386         fi
387
388         if [ -n "$tag" ]; then
389                 for t in $tag; do append tags "$t" ",set:"; done
390         fi
391
392         config_get_bool broadcast "$cfg" broadcast 0
393         config_get leasetime "$cfg" leasetime
394
395         [ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast"
396
397         hosttag="${networkid:+,set:${networkid}}${tags:+,set:${tags}}$broadcast"
398         nametime="${name:+,$name}${leasetime:+,$leasetime}"
399
400         if [ $DNSMASQ_DHCP_VER -eq 6 ]; then
401                 addrs="${ip:+,$ip}${hostid:+,[::$hostid]}"
402                 xappend "--dhcp-host=$mtags$macs${duids:+,$duids}$hosttag$addrs$nametime"
403         else
404                 xappend "--dhcp-host=$mtags$macs$hosttag${ip:+,$ip}$nametime"
405         fi
406 }
407
408 dhcp_this_host_add() {
409         local net="$1"
410         local ifname="$2"
411         local mode="$3"
412         local routerstub routername ifdashname
413         local lanaddr lanaddr6 lanaddrs6 ulaprefix
414
415         if [ "$mode" -gt 0 ] ; then
416                 ifdashname="${ifname//./-}"
417                 routerstub="$( md5sum /etc/os-release )"
418                 routerstub="router-${routerstub// */}"
419                 routername="$( uci_get system @system[0] hostname $routerstub )"
420
421                 if [ "$mode" -gt 1 ] ; then
422                         if [ "$mode" -gt 2 ] ; then
423                                 if [ "$mode" -gt 3 ] ; then
424                                         append_interface_name "$ifdashname.$routername.$DOMAIN" "$ifname"
425                                 fi
426
427                                 append_interface_name "$routername.$DOMAIN" "$ifname"
428                         fi
429
430                         # All IP addresses discovered by dnsmasq will be labeled (except fe80::)
431                         append_interface_name "$routername" "$ifname"
432
433                 else
434                         # This uses a static host file entry for only limited addresses.
435                         # Use dnsmasq option "--expandhosts" to enable FQDN on host files.
436                         ulaprefix="$(uci_get network @globals[0] ula_prefix)"
437                         network_get_ipaddr lanaddr "$net"
438                         network_get_ipaddrs6 lanaddrs6 "$net"
439
440                         if [ -n "$lanaddr" ] ; then
441                                 dhcp_domain_add "" "$routername" "$lanaddr"
442                         fi
443
444                         if [ -n "$ulaprefix" ] && [ -n "$lanaddrs6" ] ; then
445                                 for lanaddr6 in $lanaddrs6 ; do
446                                         case "$lanaddr6" in
447                                         "${ulaprefix%%:/*}"*)
448                                                 dhcp_domain_add "" "$routername" "$lanaddr6"
449                                                 ;;
450                                         esac
451                                 done
452                         fi
453                 fi
454         fi
455 }
456
457 dhcp_tag_add() {
458         # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
459         local cfg="$1"
460
461         tag="$cfg"
462
463         [ -n "$tag" ] || return 0
464
465         config_get_bool force "$cfg" force 0
466         [ "$force" = "0" ] && force=
467
468         config_get option "$cfg" dhcp_option
469         for o in $option; do
470                 xappend "--dhcp-option${force:+-force}=tag:$tag,$o"
471         done
472 }
473
474 dhcp_mac_add() {
475         local cfg="$1"
476
477         config_get networkid "$cfg" networkid
478         [ -n "$networkid" ] || return 0
479
480         config_get mac "$cfg" mac
481         [ -n "$mac" ] || return 0
482
483         xappend "--dhcp-mac=$networkid,$mac"
484
485         dhcp_option_add "$cfg" "$networkid"
486 }
487
488 dhcp_boot_add() {
489         # TODO: BOOTURL is different between DHCPv4 and DHCPv6
490         local cfg="$1"
491
492         config_get networkid "$cfg" networkid
493
494         config_get filename "$cfg" filename
495         [ -n "$filename" ] || return 0
496
497         config_get servername "$cfg" servername
498         config_get serveraddress "$cfg" serveraddress
499
500         [ -n "$serveraddress" ] && [ ! -n "$servername" ] && return 0
501
502         xappend "--dhcp-boot=${networkid:+net:$networkid,}${filename}${servername:+,$servername}${serveraddress:+,$serveraddress}"
503
504         config_get_bool force "$cfg" force 0
505
506         dhcp_option_add "$cfg" "$networkid" "$force"
507 }
508
509
510 dhcp_add() {
511         local cfg="$1"
512         local dhcp6range="::"
513         local nettag
514         local tags
515
516         config_get net "$cfg" interface
517         [ -n "$net" ] || return 0
518
519         config_get networkid "$cfg" networkid
520         [ -n "$networkid" ] || networkid="$net"
521
522         network_get_device ifname "$net" || return 0
523
524         [ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && {
525                 DNS_SERVERS="$DNS_SERVERS $dnsserver"
526         }
527
528         append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && {
529                 # Many ISP do not have useful names for DHCP customers (your WAN).
530                 dhcp_this_host_add "$net" "$ifname" "$ADD_WAN_FQDN"
531                 return 0
532         }
533
534         network_get_subnet subnet "$net" || return 0
535         network_get_protocol proto "$net" || return 0
536
537         # Do not support non-static interfaces for now
538         [ static = "$proto" ] || return 0
539
540         # Override interface netmask with dhcp config if applicable
541         config_get netmask "$cfg" netmask "${subnet##*/}"
542
543         #check for an already active dhcp server on the interface, unless 'force' is set
544         config_get_bool force "$cfg" force 0
545         [ $force -gt 0 ] || dhcp_check "$ifname" || {
546                 logger -t dnsmasq \
547                         "found already running DHCP-server on interface '$ifname'" \
548                         "refusing to start, use 'option force 1' to override"
549                 return 0
550         }
551
552         config_get start "$cfg" start 100
553         config_get limit "$cfg" limit 150
554         config_get leasetime "$cfg" leasetime 12h
555         config_get options "$cfg" options
556         config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1
557
558         config_get dhcpv4 "$cfg" dhcpv4
559         config_get dhcpv6 "$cfg" dhcpv6
560
561         config_get ra "$cfg" ra
562         config_get ra_management "$cfg" ra_management
563         config_get ra_preference "$cfg" ra_preference
564         config_get dns "$cfg" dns
565
566         config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname"
567
568         # Put the router host name on this DHCP served interface address(es)
569         dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN"
570
571         start="$( dhcp_calc "$start" )"
572
573         add_tag() {
574                 tags="${tags}tag:$1,"
575         }
576         config_list_foreach "$cfg" tag add_tag
577
578         nettag="${networkid:+set:${networkid},}"
579
580         if [ "$limit" -gt 0 ] ; then
581                 limit=$((limit-1))
582         fi
583
584         eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
585
586         if [ "$dynamicdhcp" = "0" ] ; then
587                 END="static"
588                 dhcp6range="::,static"
589         else
590                 dhcp6range="::1000,::ffff"
591         fi
592
593
594         if [ "$dhcpv4" != "disabled" ] ; then
595                 xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
596         fi
597
598
599         if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then
600                 # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1)
601                 # and let some other machine(s) send RA pointing to it.
602
603                 case $ra_preference in
604                 *high*)
605                         xappend "--ra-param=$ifname,high,0,7200"
606                         ;;
607                 *low*)
608                         xappend "--ra-param=$ifname,low,0,7200"
609                         ;;
610                 *)
611                         # Send UNSOLICITED RA at default interval and live for 2 hours.
612                         # TODO: convert flexible lease time into route life time (only seconds).
613                         xappend "--ra-param=$ifname,0,7200"
614                         ;;
615                 esac
616
617                 if [ "$dhcpv6" = "disabled" ] ; then
618                         ra_management="3"
619                 fi
620
621
622                 case $ra_management in
623                 0)
624                         # SLACC with DCHP for extended options
625                         xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names"
626                         ;;
627                 2)
628                         # DHCP address and RA only for management redirection
629                         xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime"
630                         ;;
631                 3)
632                         # SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC
633                         xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names"
634                         ;;
635                 *)
636                         # SLAAC and full DHCP
637                         xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime"
638                         ;;
639                 esac
640
641                 if [ -n "$dns" ]; then
642                         dnss=""
643                         for d in $dns; do append dnss "[$d]" ","; done
644                 else
645                         dnss="[::]"
646                 fi
647
648                 dhcp_option_append "option6:dns-server,$dnss" "$networkid"
649         fi
650
651         dhcp_option_add "$cfg" "$networkid" 0
652         dhcp_option_add "$cfg" "$networkid" 2
653 }
654
655 dhcp_option_append() {
656         local option="$1"
657         local networkid="$2"
658         local force="$3"
659
660         xappend "--dhcp-option${force:+-force}=${networkid:+$networkid,}$option"
661 }
662
663 dhcp_option_add() {
664         # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
665         local cfg="$1"
666         local networkid="$2"
667         local force="$3"
668         local opt="dhcp_option"
669
670         [ "$force" = "0" ] && force=
671         [ "$force" = "2" ] && opt="dhcp_option_force"
672
673         local list_len
674         config_get list_len "$cfg" "${opt}_LENGTH"
675
676         if [ -n "$list_len" ]; then
677                 config_list_foreach "$cfg" "$opt" dhcp_option_append "$networkid" "$force"
678         else
679                 config_get dhcp_option "$cfg" "$opt"
680
681                 [ -n "$dhcp_option" ] && echo "Warning: the 'option $opt' syntax is deprecated, use 'list $opt'" >&2
682
683                 local option
684                 for option in $dhcp_option; do
685                         dhcp_option_append "$option" "$networkid" "$force"
686                 done
687         fi
688 }
689
690 dhcp_domain_add() {
691         local cfg="$1"
692         local ip name names record
693
694         config_get names "$cfg" name "$2"
695         [ -n "$names" ] || return 0
696
697         config_get ip "$cfg" ip "$3"
698         [ -n "$ip" ] || return 0
699
700         for name in $names; do
701                 record="${record:+$record }$name"
702         done
703
704         echo "$ip $record" >> $HOSTFILE_TMP
705 }
706
707 dhcp_srv_add() {
708         local cfg="$1"
709
710         config_get srv "$cfg" srv
711         [ -n "$srv" ] || return 0
712
713         config_get target "$cfg" target
714         [ -n "$target" ] || return 0
715
716         config_get port "$cfg" port
717         [ -n "$port" ] || return 0
718
719         config_get class "$cfg" class
720         config_get weight "$cfg" weight
721
722         local service="$srv,$target,$port${class:+,$class${weight:+,$weight}}"
723
724         xappend "--srv-host=$service"
725 }
726
727 dhcp_mx_add() {
728         local cfg="$1"
729         local domain relay pref
730
731         config_get domain "$cfg" domain
732         [ -n "$domain" ] || return 0
733
734         config_get relay "$cfg" relay
735         [ -n "$relay" ] || return 0
736
737         config_get pref "$cfg" pref 0
738
739         local service="$domain,$relay,$pref"
740
741         xappend "--mx-host=$service"
742 }
743
744 dhcp_cname_add() {
745         local cfg="$1"
746         local cname target
747
748         config_get cname "$cfg" cname
749         [ -n "$cname" ] || return 0
750
751         config_get target "$cfg" target
752         [ -n "$target" ] || return 0
753
754         xappend "--cname=${cname},${target}"
755 }
756
757 dhcp_hostrecord_add() {
758         local cfg="$1"
759         local names addresses record val
760
761         config_get names "$cfg" name "$2"
762         if [ -z "$names" ]; then
763                 return 0
764         fi
765
766         config_get addresses "$cfg" ip "$3"
767         if [ -z "$addresses" ]; then
768                 return 0
769         fi
770
771         for val in $names $addresses; do
772                 record="${record:+$record,}$val"
773         done
774
775         xappend "--host-record=$record"
776 }
777
778 dhcp_relay_add() {
779         local cfg="$1"
780         local local_addr server_addr interface
781
782         config_get local_addr "$cfg" local_addr
783         [ -n "$local_addr" ] || return 0
784
785         config_get server_addr "$cfg" server_addr
786         [ -n "$server_addr" ] || return 0
787
788         config_get interface "$cfg" interface
789         if [ -z "$interface" ]; then
790                 xappend "--dhcp-relay=$local_addr,$server_addr"
791         else
792                 network_get_device ifname "$interface" || return
793                 xappend "--dhcp-relay=$local_addr,$server_addr,$ifname"
794         fi
795 }
796
797 dnsmasq_ipset_add() {
798         local cfg="$1"
799         local ipsets domains
800
801         add_ipset() {
802                 ipsets="${ipsets:+$ipsets,}$1"
803         }
804
805         add_domain() {
806                 # leading '/' is expected
807                 domains="$domains/$1"
808         }
809
810         config_list_foreach "$cfg" "name" add_ipset
811         config_list_foreach "$cfg" "domain" add_domain
812
813         if [ -z "$ipsets" ] || [ -z "$domains" ]; then
814                 return 0
815         fi
816
817         xappend "--ipset=$domains/$ipsets"
818 }
819
820 dnsmasq_start()
821 {
822         local cfg="$1"
823         local disabled user_dhcpscript logfacility
824         local resolvfile resolvdir localuse=0
825
826         config_get_bool disabled "$cfg" disabled 0
827         [ "$disabled" -gt 0 ] && return 0
828
829         # reset list of DOMAINS, DNS servers and EXTRA mounts (for each dnsmasq instance)
830         DNS_SERVERS=""
831         DOMAIN=""
832         EXTRA_MOUNT=""
833         CONFIGFILE="${BASECONFIGFILE}.${cfg}"
834         CONFIGFILE_TMP="${CONFIGFILE}.$$"
835         HOSTFILE="${BASEHOSTFILE}.${cfg}"
836         HOSTFILE_TMP="${HOSTFILE}.$$"
837         HOSTFILE_DIR="$(dirname "$HOSTFILE")"
838         BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}"
839
840         # before we can call xappend
841         umask u=rwx,g=rx,o=rx
842         mkdir -p /var/run/dnsmasq/
843         mkdir -p $(dirname $CONFIGFILE)
844         mkdir -p "$HOSTFILE_DIR"
845         mkdir -p /var/lib/misc
846         chown dnsmasq:dnsmasq /var/run/dnsmasq
847
848         echo "# auto-generated config file from /etc/config/dhcp" > $CONFIGFILE_TMP
849         echo "# auto-generated config file from /etc/config/dhcp" > $HOSTFILE_TMP
850
851         local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf"
852         if [ ! -r "$dnsmasqconffile" ]; then
853                 dnsmasqconffile=/etc/dnsmasq.conf
854         fi
855
856         # if we did this last, we could override auto-generated config
857         [ -f "${dnsmasqconffile}" ] && {
858                 xappend "--conf-file=${dnsmasqconffile}"
859         }
860
861         $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0
862
863
864         if [ -x /usr/sbin/odhcpd ] && [ -x /etc/init.d/odhcpd ] ; then
865                 local odhcpd_is_main odhcpd_is_enabled
866                 config_get odhcpd_is_main odhcpd maindhcp 0
867                 /etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0
868
869
870                 if [ "$odhcpd_is_enabled" -eq 0 ] && [ "$DHCPv6CAPABLE" -eq 1 ] ; then
871                         # DHCP V4 and V6 in DNSMASQ
872                         DNSMASQ_DHCP_VER=6
873                 elif [ "$odhcpd_is_main" -gt 0 ] ; then
874                         # ODHCPD is doing it all
875                         DNSMASQ_DHCP_VER=0
876                 else
877                         # You have ODHCPD but use DNSMASQ for DHCPV4
878                         DNSMASQ_DHCP_VER=4
879                 fi
880
881         elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then
882                 # DHCP V4 and V6 in DNSMASQ
883                 DNSMASQ_DHCP_VER=6
884         else
885                 DNSMASQ_DHCP_VER=4
886         fi
887
888         # Allow DHCP/DHCPv6 to be handled by ISC DHCPD
889         if [ -x /usr/sbin/dhcpd ] ; then
890                 if [ -x /etc/init.d/dhcpd ] ; then
891                         /etc/init.d/dhcpd enabled && DNSMASQ_DHCP_VER=0
892                 fi
893                 if [ -x /etc/init.d/dhcpd6 ] && [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then
894                         /etc/init.d/dhcpd6 enabled && DNSMASQ_DHCP_VER=4
895                 fi
896         fi
897
898         append_bool "$cfg" authoritative "--dhcp-authoritative"
899         append_bool "$cfg" nodaemon "--no-daemon"
900         append_bool "$cfg" domainneeded "--domain-needed"
901         append_bool "$cfg" filterwin2k "--filterwin2k"
902         append_bool "$cfg" nohosts "--no-hosts"
903         append_bool "$cfg" nonegcache "--no-negcache"
904         append_bool "$cfg" strictorder "--strict-order"
905         append_bool "$cfg" logqueries "--log-queries=extra"
906         append_bool "$cfg" noresolv "--no-resolv"
907         append_bool "$cfg" localise_queries "--localise-queries"
908         append_bool "$cfg" readethers "--read-ethers"
909
910         local instance_name="dnsmasq.$cfg"
911         if [ "$cfg" = "$DEFAULT_INSTANCE" ]; then
912                 instance_name="dnsmasq"
913         fi
914         config_get_bool dbus "$cfg" "dbus" 0
915         [ $dbus -gt 0 ] && xappend "--enable-dbus=uk.org.thekelleys.$instance_name"
916         config_get_bool ubus "$cfg" "ubus" 1
917         [ $ubus -gt 0 ] && xappend "--enable-ubus=$instance_name"
918
919         append_bool "$cfg" expandhosts "--expand-hosts"
920         config_get tftp_root "$cfg" "tftp_root"
921         [ -n "$tftp_root" ] && mkdir -p "$tftp_root" && append_bool "$cfg" enable_tftp "--enable-tftp"
922         append_bool "$cfg" tftp_no_fail "--tftp-no-fail"
923         append_bool "$cfg" nonwildcard "--bind-dynamic" 1
924         append_bool "$cfg" fqdn "--dhcp-fqdn"
925         append_bool "$cfg" proxydnssec "--proxy-dnssec"
926         append_bool "$cfg" localservice "--local-service"
927         append_bool "$cfg" logdhcp "--log-dhcp"
928         append_bool "$cfg" quietdhcp "--quiet-dhcp"
929         append_bool "$cfg" sequential_ip "--dhcp-sequential-ip"
930         append_bool "$cfg" allservers "--all-servers"
931         append_bool "$cfg" noping "--no-ping"
932         append_bool "$cfg" rapidcommit "--dhcp-rapid-commit"
933         append_bool "$cfg" scriptarp "--script-arp"
934
935         append_bool "$cfg" filter_aaaa "--filter-aaaa"
936
937         append_parm "$cfg" logfacility "--log-facility"
938
939         append_parm "$cfg" mini_ttl "--min-ttl"
940
941         config_get logfacility "$cfg" "logfacility"
942         append_parm "$cfg" cachesize "--cache-size"
943         append_parm "$cfg" dnsforwardmax "--dns-forward-max"
944         append_parm "$cfg" port "--port"
945         append_parm "$cfg" ednspacket_max "--edns-packet-max"
946         append_parm "$cfg" dhcpleasemax "--dhcp-lease-max"
947         append_parm "$cfg" "queryport" "--query-port"
948         append_parm "$cfg" "minport" "--min-port"
949         append_parm "$cfg" "maxport" "--max-port"
950         append_parm "$cfg" "domain" "--domain"
951         append_parm "$cfg" "local" "--local"
952         config_list_foreach "$cfg" "listen_address" append_listenaddress
953         config_list_foreach "$cfg" "server" append_server
954         config_list_foreach "$cfg" "rev_server" append_rev_server
955         config_list_foreach "$cfg" "address" append_address
956         config_list_foreach "$cfg" "ipset" append_ipset
957
958         local connmark_allowlist_enable
959         config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0
960         [ "$connmark_allowlist_enable" -gt 0 ] && {
961                 append_parm "$cfg" "connmark_allowlist_enable" "--connmark-allowlist-enable"
962                 config_list_foreach "$cfg" "connmark_allowlist" append_connmark_allowlist
963         }
964
965         [ -n "$BOOT" ] || {
966                 config_list_foreach "$cfg" "interface" append_interface
967                 config_list_foreach "$cfg" "notinterface" append_notinterface
968         }
969         config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0
970         if [ "$ignore_hosts_dir" = "1" ]; then
971                 xappend "--addn-hosts=$HOSTFILE"
972                 append EXTRA_MOUNT "$HOSTFILE"
973         else
974                 xappend "--addn-hosts=$HOSTFILE_DIR"
975                 append EXTRA_MOUNT "$HOSTFILE_DIR"
976         fi
977         config_list_foreach "$cfg" "addnhosts" append_addnhosts
978         config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain
979         append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases"
980
981         local serversfile
982         config_get serversfile "$cfg" "serversfile"
983         [ -n "$serversfile" ] && {
984                 xappend "--servers-file=$serversfile"
985                 append EXTRA_MOUNT "$serversfile"
986         }
987
988         append_parm "$cfg" "tftp_root" "--tftp-root"
989         append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
990         append_parm "$cfg" "local_ttl" "--local-ttl"
991         append_parm "$cfg" "max_ttl" "--max-ttl"
992         append_parm "$cfg" "min_cache_ttl" "--min-cache-ttl"
993         append_parm "$cfg" "max_cache_ttl" "--max-cache-ttl"
994         append_parm "$cfg" "pxe_prompt" "--pxe-prompt"
995         append_parm "$cfg" "tftp_unique_root" "--tftp-unique-root"
996         config_list_foreach "$cfg" "pxe_service" append_pxe_service
997         config_get DOMAIN "$cfg" domain
998
999         config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1
1000         config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1
1001         config_get ADD_LOCAL_FQDN "$cfg" add_local_fqdn ""
1002         config_get ADD_WAN_FQDN "$cfg" add_wan_fqdn 0
1003
1004         if [ -z "$ADD_LOCAL_FQDN" ] ; then
1005                 # maintain support for previous UCI
1006                 ADD_LOCAL_FQDN="$ADD_LOCAL_HOSTNAME"
1007         fi
1008
1009         config_get user_dhcpscript $cfg dhcpscript
1010         if has_handler || [ -n "$user_dhcpscript" ]; then
1011                 xappend "--dhcp-script=$DHCPSCRIPT"
1012                 xappend "--script-arp"
1013         fi
1014
1015         config_get leasefile $cfg leasefile "/tmp/dhcp.leases"
1016         [ -n "$leasefile" ] && [ ! -e "$leasefile" ] && touch "$leasefile"
1017         config_get_bool cachelocal "$cfg" cachelocal 1
1018
1019         config_get_bool noresolv "$cfg" noresolv 0
1020         if [ "$noresolv" != "1" ]; then
1021                 config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto
1022                 [ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile"
1023                 xappend "--resolv-file=$resolvfile"
1024                 [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
1025                 resolvdir="$(dirname "$resolvfile")"
1026         fi
1027         config_get_bool localuse "$cfg" localuse "$localuse"
1028
1029         config_get hostsfile "$cfg" dhcphostsfile
1030         [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile"
1031
1032         local rebind
1033         config_get_bool rebind "$cfg" rebind_protection 1
1034         [ $rebind -gt 0 ] && {
1035                 log_once \
1036                         "DNS rebinding protection is active," \
1037                         "will discard upstream RFC1918 responses!"
1038                 xappend "--stop-dns-rebind"
1039
1040                 local rebind_localhost
1041                 config_get_bool rebind_localhost "$cfg" rebind_localhost 0
1042                 [ $rebind_localhost -gt 0 ] && {
1043                         log_once "Allowing 127.0.0.0/8 responses"
1044                         xappend "--rebind-localhost-ok"
1045                 }
1046
1047                 append_rebind_domain() {
1048                         log_once "Allowing RFC1918 responses for domain $1"
1049                         xappend "--rebind-domain-ok=$1"
1050                 }
1051
1052                 config_list_foreach "$cfg" rebind_domain append_rebind_domain
1053         }
1054
1055         config_get_bool dnssec "$cfg" dnssec 0
1056         [ "$dnssec" -gt 0 ] && {
1057                 xappend "--conf-file=$TRUSTANCHORSFILE"
1058                 xappend "--dnssec"
1059                 [ -x /etc/init.d/sysntpd ] && {
1060                         if /etc/init.d/sysntpd enabled || [ "$(uci_get system.ntp.enabled)" = "1" ] ; then
1061                                 [ -f "$TIMEVALIDFILE" ] || xappend "--dnssec-no-timecheck"
1062                         fi
1063                 }
1064                 config_get_bool dnsseccheckunsigned "$cfg" dnsseccheckunsigned 1
1065                 [ "$dnsseccheckunsigned" -eq 0 ] && xappend "--dnssec-check-unsigned=no"
1066         }
1067
1068         config_get addmac "$cfg" addmac 0
1069         [ "$addmac" != "0" ] && {
1070                 [ "$addmac" = "1" ] && addmac=
1071                 xappend "--add-mac${addmac:+="$addmac"}"
1072         }
1073
1074         dhcp_option_add "$cfg" "" 0
1075         dhcp_option_add "$cfg" "" 2
1076
1077         xappend "--dhcp-broadcast=tag:needs-broadcast"
1078
1079
1080         config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d"
1081         xappend "--conf-dir=$dnsmasqconfdir"
1082         dnsmasqconfdir="${dnsmasqconfdir%%,*}"
1083         [ ! -d "$dnsmasqconfdir" ] && mkdir -p $dnsmasqconfdir
1084         xappend "--user=dnsmasq"
1085         xappend "--group=dnsmasq"
1086         echo >> $CONFIGFILE_TMP
1087
1088         config_get_bool enable_tftp "$cfg" enable_tftp 0
1089         [ "$enable_tftp" -gt 0 ] && {
1090                 config_get tftp_root "$cfg" tftp_root
1091                 append EXTRA_MOUNT $tftp_root
1092         }
1093
1094         config_foreach filter_dnsmasq host dhcp_host_add "$cfg"
1095         echo >> $CONFIGFILE_TMP
1096
1097         config_get_bool dhcpbogushostname "$cfg" dhcpbogushostname 1
1098         [ "$dhcpbogushostname" -gt 0 ] && {
1099                 xappend "--dhcp-ignore-names=tag:dhcp_bogus_hostname"
1100                 [ -r "$DHCPBOGUSHOSTNAMEFILE" ] && xappend "--conf-file=$DHCPBOGUSHOSTNAMEFILE"
1101         }
1102
1103         config_foreach filter_dnsmasq boot dhcp_boot_add "$cfg"
1104         config_foreach filter_dnsmasq mac dhcp_mac_add "$cfg"
1105         config_foreach filter_dnsmasq tag dhcp_tag_add "$cfg"
1106         config_foreach filter_dnsmasq vendorclass dhcp_vendorclass_add "$cfg"
1107         config_foreach filter_dnsmasq userclass dhcp_userclass_add "$cfg"
1108         config_foreach filter_dnsmasq circuitid dhcp_circuitid_add "$cfg"
1109         config_foreach filter_dnsmasq remoteid dhcp_remoteid_add "$cfg"
1110         config_foreach filter_dnsmasq subscrid dhcp_subscrid_add "$cfg"
1111         config_foreach filter_dnsmasq match dhcp_match_add "$cfg"
1112         config_foreach filter_dnsmasq domain dhcp_domain_add "$cfg"
1113         config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg"
1114         [ -n "$BOOT" ] || config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg"
1115
1116         echo >> $CONFIGFILE_TMP
1117         config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg"
1118         config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg"
1119         echo >> $CONFIGFILE_TMP
1120
1121         config_get_bool boguspriv "$cfg" boguspriv 1
1122         [ "$boguspriv" -gt 0 ] && {
1123                 xappend "--bogus-priv"
1124                 [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE"
1125         }
1126
1127         if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then
1128                 # Enable RA feature for when/if it is constructed,
1129                 # and RA is selected per interface pool (RA, DHCP, or both),
1130                 # but no one (should) want RA broadcast in syslog
1131                 [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
1132                 xappend "--enable-ra"
1133                 xappend "--quiet-ra"
1134                 append_bool "$cfg" quietdhcp "--quiet-dhcp6"
1135
1136         elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then
1137                 [ -n "$BOOT" ] || config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
1138         fi
1139
1140
1141         echo >> $CONFIGFILE_TMP
1142         config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg"
1143         echo >> $CONFIGFILE_TMP
1144
1145         echo >> $CONFIGFILE_TMP
1146         config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg"
1147         echo >> $CONFIGFILE_TMP
1148
1149         echo >> $CONFIGFILE_TMP
1150         mv -f $CONFIGFILE_TMP $CONFIGFILE
1151         mv -f $HOSTFILE_TMP $HOSTFILE
1152
1153         [ "$localuse" -gt 0 ] && {
1154                 rm -f /tmp/resolv.conf
1155                 [ $ADD_LOCAL_DOMAIN -eq 1 ] && [ -n "$DOMAIN" ] && {
1156                         echo "search $DOMAIN" >> /tmp/resolv.conf
1157                 }
1158                 DNS_SERVERS="$DNS_SERVERS 127.0.0.1"
1159                 [ -e /proc/sys/net/ipv6 ] && DNS_SERVERS="$DNS_SERVERS ::1"
1160                 for DNS_SERVER in $DNS_SERVERS ; do
1161                         echo "nameserver $DNS_SERVER" >> /tmp/resolv.conf
1162                 done
1163         }
1164
1165         procd_open_instance $cfg
1166         procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid
1167         procd_set_param file $CONFIGFILE
1168         [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript"
1169         procd_set_param respawn
1170
1171         local instance_ifc instance_netdev
1172         config_get instance_ifc "$cfg" interface
1173         [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" &&
1174                 [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev
1175
1176         procd_add_jail dnsmasq ubus log
1177         procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS
1178         procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE
1179         procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript
1180         procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers
1181         procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
1182         case "$logfacility" in */*)
1183                 [ ! -e "$logfacility" ] && touch "$logfacility"
1184                 procd_add_jail_mount_rw "$logfacility"
1185         esac
1186
1187         procd_close_instance
1188
1189         config_get_bool dns_redirect "$cfg" dns_redirect 0
1190         config_get dns_port "$cfg" port 53
1191         if [ "$dns_redirect" = 1 ]; then
1192                 cat > /etc/nftables.d/11-dnsmasq-dns-redirect.nft <<EOF
1193                 chain dstnat_lan{
1194                         udp dport 53 counter redirect to :$dns_port comment "!fw4: DNSMASQ"
1195                 }
1196 EOF
1197                 fw4 reload
1198         fi
1199 }
1200
1201 dnsmasq_stop()
1202 {
1203         local cfg="$1"
1204         local noresolv resolvfile localuse=0
1205
1206         config_get_bool noresolv "$cfg" noresolv 0
1207         config_get resolvfile "$cfg" "resolvfile"
1208
1209         [ "$noresolv" = 0 ] && [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
1210         config_get_bool localuse "$cfg" localuse "$localuse"
1211         [ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf
1212
1213         rm -f ${BASEDHCPSTAMPFILE}.${cfg}.*.dhcp
1214 }
1215
1216 nftables_clear()
1217 {
1218         [ -f "/etc/nftables.d/11-dnsmasq-dns-redirect.nft" ] && rm -f /etc/nftables.d/11-dnsmasq-dns-redirect.nft
1219         fw4 reload
1220 }
1221
1222 add_interface_trigger()
1223 {
1224         local interface ignore
1225
1226         config_get interface "$1" interface
1227         config_get_bool ignore "$1" ignore 0
1228
1229         [ -n "$interface" ] && [ $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload
1230 }
1231
1232 service_triggers()
1233 {
1234         procd_add_reload_trigger "dhcp" "system"
1235
1236         config_load dhcp
1237         config_foreach add_interface_trigger dhcp
1238         config_foreach add_interface_trigger relay
1239 }
1240
1241 boot()
1242 {
1243         BOOT=1
1244         start "$@"
1245 }
1246
1247 start_service() {
1248         local instance="$1"
1249         local instance_found=0
1250         local first_instance=""
1251
1252         . /lib/functions/network.sh
1253
1254         config_cb() {
1255                 local type="$1"
1256                 local name="$2"
1257                 if [ "$type" = "dnsmasq" ]; then
1258                         if [ -n "$instance" ] && [ "$instance" = "$name" ]; then
1259                                 instance_found=1
1260                         fi
1261                         if [ -z "$DEFAULT_INSTANCE" ]; then
1262                                 local disabled
1263                                 config_get_bool disabled "$name" disabled 0
1264                                 if [ "$disabled" -eq 0 ]; then
1265                                         # First enabled section will be assigned default instance name.
1266                                         # Unnamed sections get precedence over named sections.
1267                                         if expr "$cfg" : 'cfg[0-9a-f]*$' >/dev/null = "9"; then # See uci_fixup_section.
1268                                                 DEFAULT_INSTANCE="$name" # Unnamed config section.
1269                                         elif [ -z "$first_instance" ]; then
1270                                                 first_instance="$name"
1271                                         fi
1272                                 fi
1273                         fi
1274                 fi
1275         }
1276
1277         DEFAULT_INSTANCE=""
1278         config_load dhcp
1279         if [ -z "$DEFAULT_INSTANCE" ]; then
1280                 DEFAULT_INSTANCE="$first_instance" # No unnamed config section was found.
1281         fi
1282
1283         if [ -n "$instance" ]; then
1284                 [ "$instance_found" -gt 0 ] || return
1285                 dnsmasq_start "$instance"
1286         else
1287                 config_foreach dnsmasq_start dnsmasq
1288         fi
1289 }
1290
1291 reload_service() {
1292         nftables_clear
1293         rc_procd start_service "$@"
1294         procd_send_signal dnsmasq "$@"
1295 }
1296
1297 stop_service() {
1298         local instance="$1"
1299         local instance_found=0
1300
1301         config_cb() {
1302                 local type="$1"
1303                 local name="$2"
1304                 if [ "$type" = "dnsmasq" ]; then
1305                         if [ -n "$instance" ] && [ "$instance" = "$name" ]; then
1306                                 instance_found=1
1307                         fi
1308                 fi
1309         }
1310
1311         config_load dhcp
1312
1313         if [ -n "$instance" ]; then
1314                 [ "$instance_found" -gt 0 ] || return
1315                 dnsmasq_stop "$instance"
1316         else
1317                 config_foreach dnsmasq_stop dnsmasq
1318         fi
1319         nftables_clear
1320 }