dnsmasq: rework network interface ignore
[openwrt/staging/jow.git] / package / network / services / dnsmasq / files / dnsmasq.init
old mode 100644 (file)
new mode 100755 (executable)
index 44e7d2d..c5e6730
@@ -19,6 +19,7 @@ BASEDHCPSTAMPFILE="/var/run/dnsmasq"
 DHCPBOGUSHOSTNAMEFILE="/usr/share/dnsmasq/dhcpbogushostname.conf"
 RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf"
 DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
+DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus"
 
 DNSMASQ_DHCP_VER=4
 
@@ -32,6 +33,7 @@ dnsmasq_ignore_opt() {
                [ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1
                [ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1
                [ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1
+               [ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1
        fi
 
        case "$opt" in
@@ -54,6 +56,8 @@ dnsmasq_ignore_opt() {
                        [ -z "$dnsmasq_has_tftp" ] ;;
                ipset)
                        [ -z "$dnsmasq_has_ipset" ] ;;
+               nftset)
+                       [ -z "$dnsmasq_has_nftset" ] ;;
                *)
                        return 1
        esac
@@ -161,15 +165,15 @@ append_server() {
 }
 
 append_rev_server() {
-        xappend "--rev-server=$1"
+       xappend "--rev-server=$1"
 }
 
 append_address() {
        xappend "--address=$1"
 }
 
-append_ipset() {
-       xappend "--ipset=$1"
+append_connmark_allowlist() {
+       xappend "--connmark-allowlist=$1"
 }
 
 append_interface() {
@@ -186,7 +190,26 @@ append_notinterface() {
        xappend "--except-interface=$ifname"
 }
 
+ismounted() {
+       local filename="$1"
+       local dirname
+       for dirname in $EXTRA_MOUNT ; do
+               case "$filename" in
+                       "${dirname}/"* | "${dirname}" )
+                               return 0
+                               ;;
+               esac
+       done
+
+       return 1
+}
+
+append_extramount() {
+       ismounted "$1" || append EXTRA_MOUNT "$1"
+}
+
 append_addnhosts() {
+       append_extramount "$1"
        xappend "--addn-hosts=$1"
 }
 
@@ -221,7 +244,7 @@ dhcp_subscrid_add() {
        config_get subscriberid "$cfg" subscriberid
        [ -n "$subscriberid" ] || return 0
 
-       xappend "--dhcp-subscrid=$networkid,$subscriberid"
+       xappend "--dhcp-subscrid=set:$networkid,$subscriberid"
 
        config_get_bool force "$cfg" force 0
 
@@ -237,7 +260,7 @@ dhcp_remoteid_add() {
        config_get remoteid "$cfg" remoteid
        [ -n "$remoteid" ] || return 0
 
-       xappend "--dhcp-remoteid=$networkid,$remoteid"
+       xappend "--dhcp-remoteid=set:$networkid,$remoteid"
 
        config_get_bool force "$cfg" force 0
 
@@ -254,7 +277,7 @@ dhcp_circuitid_add() {
        config_get circuitid "$cfg" circuitid
        [ -n "$circuitid" ] || return 0
 
-       xappend "--dhcp-circuitid=$networkid,$circuitid"
+       xappend "--dhcp-circuitid=set:$networkid,$circuitid"
 
        config_get_bool force "$cfg" force 0
 
@@ -270,7 +293,7 @@ dhcp_userclass_add() {
        config_get userclass "$cfg" userclass
        [ -n "$userclass" ] || return 0
 
-       xappend "--dhcp-userclass=$networkid,$userclass"
+       xappend "--dhcp-userclass=set:$networkid,$userclass"
 
        config_get_bool force "$cfg" force 0
 
@@ -287,7 +310,7 @@ dhcp_vendorclass_add() {
        config_get vendorclass "$cfg" vendorclass
        [ -n "$vendorclass" ] || return 0
 
-       xappend "--dhcp-vendorclass=$networkid,$vendorclass"
+       xappend "--dhcp-vendorclass=set:$networkid,$vendorclass"
 
        config_get_bool force "$cfg" force 0
 
@@ -303,7 +326,7 @@ dhcp_match_add() {
        config_get match "$cfg" match
        [ -n "$match" ] || return 0
 
-       xappend "--dhcp-match=$networkid,$match"
+       xappend "--dhcp-match=set:$networkid,$match"
 
        config_get_bool force "$cfg" force 0
 
@@ -312,7 +335,7 @@ dhcp_match_add() {
 
 dhcp_host_add() {
        local cfg="$1"
-       local hosttag nametime addrs duids macs tags
+       local hosttag nametime addrs duids macs tags mtags
 
        config_get_bool force "$cfg" force 0
 
@@ -337,6 +360,11 @@ dhcp_host_add() {
        config_get duid "$cfg" duid
        config_get tag "$cfg" tag
 
+       add_tag() {
+               mtags="${mtags}tag:$1,"
+       }
+       config_list_foreach "$cfg" match_tag add_tag
+
        if [ -n "$mac" ]; then
                # --dhcp-host=00:20:e0:3b:13:af,192.168.0.199,lap
                # many MAC are possible to track a laptop ON/OFF dock
@@ -374,9 +402,9 @@ dhcp_host_add() {
 
        if [ $DNSMASQ_DHCP_VER -eq 6 ]; then
                addrs="${ip:+,$ip}${hostid:+,[::$hostid]}"
-               xappend "--dhcp-host=$macs${duids:+,$duids}$hosttag$addrs$nametime"
+               xappend "--dhcp-host=$mtags$macs${duids:+,$duids}$hosttag$addrs$nametime"
        else
-               xappend "--dhcp-host=$macs$hosttag${ip:+,$ip}$nametime"
+               xappend "--dhcp-host=$mtags$macs$hosttag${ip:+,$ip}$nametime"
        fi
 }
 
@@ -481,7 +509,6 @@ dhcp_boot_add() {
        dhcp_option_add "$cfg" "$networkid" "$force"
 }
 
-
 dhcp_add() {
        local cfg="$1"
        local dhcp6range="::"
@@ -512,23 +539,21 @@ dhcp_add() {
        # Do not support non-static interfaces for now
        [ static = "$proto" ] || return 0
 
+       ipaddr="${subnet%%/*}"
+       prefix_or_netmask="${subnet##*/}"
+
        # Override interface netmask with dhcp config if applicable
-       config_get netmask "$cfg" netmask "${subnet##*/}"
+       config_get netmask "$cfg" netmask
 
-       #check for an already active dhcp server on the interface, unless 'force' is set
-       config_get_bool force "$cfg" force 0
-       [ $force -gt 0 ] || dhcp_check "$ifname" || {
-               logger -t dnsmasq \
-                       "found already running DHCP-server on interface '$ifname'" \
-                       "refusing to start, use 'option force 1' to override"
-               return 0
-       }
+       [ -n "$netmask" ] && prefix_or_netmask="$netmask"
 
        config_get start "$cfg" start 100
        config_get limit "$cfg" limit 150
        config_get leasetime "$cfg" leasetime 12h
        config_get options "$cfg" options
        config_get_bool dynamicdhcp "$cfg" dynamicdhcp 1
+       config_get_bool dynamicdhcpv4 "$cfg" dynamicdhcpv4 $dynamicdhcp
+       config_get_bool dynamicdhcpv6 "$cfg" dynamicdhcpv6 $dynamicdhcp
 
        config_get dhcpv4 "$cfg" dhcpv4
        config_get dhcpv6 "$cfg" dhcpv6
@@ -537,6 +562,7 @@ dhcp_add() {
        config_get ra_management "$cfg" ra_management
        config_get ra_preference "$cfg" ra_preference
        config_get dns "$cfg" dns
+       config_get dns_sl "$cfg" domain
 
        config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname"
 
@@ -552,25 +578,20 @@ dhcp_add() {
 
        nettag="${networkid:+set:${networkid},}"
 
-       if [ "$limit" -gt 0 ] ; then
-               limit=$((limit-1))
-       fi
+       # make sure the DHCP range is not empty
+       if [ "$dhcpv4" != "disabled" ] && ipcalc "$ipaddr/$prefix_or_netmask" "$start" "$limit" ; then
+               [ "$dynamicdhcpv4" = "0" ] && END="static"
 
-       eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
+               xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
+       fi
 
-       if [ "$dynamicdhcp" = "0" ] ; then
-               END="static"
+       if [ "$dynamicdhcpv6" = "0" ] ; then
                dhcp6range="::,static"
        else
                dhcp6range="::1000,::ffff"
        fi
 
 
-       if [ "$dhcpv4" != "disabled" ] ; then
-               xappend "--dhcp-range=$tags$nettag$START,$END,$NETMASK,$leasetime${options:+ $options}"
-       fi
-
-
        if [ $DNSMASQ_DHCP_VER -eq 6 ] && [ "$ra" = "server" ] ; then
                # Note: dnsmasq cannot just be a DHCPv6 server (all-in-1)
                # and let some other machine(s) send RA pointing to it.
@@ -621,6 +642,13 @@ dhcp_add() {
                fi
 
                dhcp_option_append "option6:dns-server,$dnss" "$networkid"
+
+               if [ -n "$dns_sl" ]; then
+                       ddssl=""
+                       for dd in $dns_sl; do append ddssl "$dd" ","; done
+               fi
+
+               dhcp_option_append "option6:domain-search,$ddssl" "$networkid"
        fi
 
        dhcp_option_add "$cfg" "$networkid" 0
@@ -771,49 +799,81 @@ dhcp_relay_add() {
 
 dnsmasq_ipset_add() {
        local cfg="$1"
-       local ipsets domains
+       local ipsets nftsets domains
 
        add_ipset() {
                ipsets="${ipsets:+$ipsets,}$1"
        }
 
+       add_nftset() {
+               local IFS=,
+               for set in $1; do
+                       local fam="$family"
+                       [ -n "$fam" ] || fam=$(echo "$set" | sed -nre \
+                               's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p')
+                       [ -n "$fam" ] || \
+                               fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \
+                               's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p')
+
+                       [ -n "$fam" ] || \
+                               logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'"
+
+                       nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set"
+               done
+       }
+
        add_domain() {
                # leading '/' is expected
                domains="$domains/$1"
        }
 
+       config_get table "$cfg" table 'fw4'
+       config_get table_family "$cfg" table_family 'inet'
+       if [ "$table_family" = "ip" ] ; then
+               family="4"
+       elif [ "$table_family" = "ip6" ] ; then
+               family="6"
+       else
+               config_get family "$cfg" family
+       fi
+
        config_list_foreach "$cfg" "name" add_ipset
+       config_list_foreach "$cfg" "name" add_nftset
        config_list_foreach "$cfg" "domain" add_domain
 
-       if [ -z "$ipsets" ] || [ -z "$domains" ]; then
+       if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then
                return 0
        fi
 
        xappend "--ipset=$domains/$ipsets"
+       xappend "--nftset=$domains/$nftsets"
 }
 
 dnsmasq_start()
 {
        local cfg="$1"
-       local disabled user_dhcpscript
-       local resolvfile resolvdir localuse=0
+       local disabled user_dhcpscript logfacility
+       local resolvfile resolvdir localuse=1
 
        config_get_bool disabled "$cfg" disabled 0
        [ "$disabled" -gt 0 ] && return 0
 
-       # reset list of DOMAINS and DNS servers (for each dnsmasq instance)
+       # reset list of DOMAINS, DNS servers and EXTRA mounts (for each dnsmasq instance)
        DNS_SERVERS=""
        DOMAIN=""
+       EXTRA_MOUNT=""
        CONFIGFILE="${BASECONFIGFILE}.${cfg}"
        CONFIGFILE_TMP="${CONFIGFILE}.$$"
        HOSTFILE="${BASEHOSTFILE}.${cfg}"
        HOSTFILE_TMP="${HOSTFILE}.$$"
+       HOSTFILE_DIR="$(dirname "$HOSTFILE")"
        BASEDHCPSTAMPFILE_CFG="${BASEDHCPSTAMPFILE}.${cfg}"
 
        # before we can call xappend
+       umask u=rwx,g=rx,o=rx
        mkdir -p /var/run/dnsmasq/
        mkdir -p $(dirname $CONFIGFILE)
-       mkdir -p $(dirname $HOSTFILE)
+       mkdir -p "$HOSTFILE_DIR"
        mkdir -p /var/lib/misc
        chown dnsmasq:dnsmasq /var/run/dnsmasq
 
@@ -830,6 +890,12 @@ dnsmasq_start()
                xappend "--conf-file=${dnsmasqconffile}"
        }
 
+       config_get_bool boguspriv "$cfg" boguspriv 1
+       [ "$boguspriv" -gt 0 ] && {
+               xappend "--bogus-priv"
+               [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE"
+       }
+
        $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0
 
 
@@ -878,13 +944,39 @@ dnsmasq_start()
        append_bool "$cfg" noresolv "--no-resolv"
        append_bool "$cfg" localise_queries "--localise-queries"
        append_bool "$cfg" readethers "--read-ethers"
-       append_bool "$cfg" dbus "--enable-dbus"
-       append_bool "$cfg" ubus "--enable-ubus" 1
+
+       local instance_name="dnsmasq.$cfg"
+       if [ "$cfg" = "$DEFAULT_INSTANCE" ]; then
+               instance_name="dnsmasq"
+       fi
+       config_get_bool dbus "$cfg" "dbus" 0
+       [ $dbus -gt 0 ] && xappend "--enable-dbus=uk.org.thekelleys.$instance_name"
+       config_get_bool ubus "$cfg" "ubus" 1
+       [ $ubus -gt 0 ] && xappend "--enable-ubus=$instance_name"
+
        append_bool "$cfg" expandhosts "--expand-hosts"
        config_get tftp_root "$cfg" "tftp_root"
        [ -n "$tftp_root" ] && mkdir -p "$tftp_root" && append_bool "$cfg" enable_tftp "--enable-tftp"
        append_bool "$cfg" tftp_no_fail "--tftp-no-fail"
-       append_bool "$cfg" nonwildcard "--bind-dynamic" 1
+
+       config_get bind "$cfg" "bind"
+       case "$bind" in
+               dynamic|interfaces)
+                       xappend "--bind-$bind"
+                       ;;
+               "")
+                       # for compatibility reasons
+                       append_bool "$cfg" nonwildcard "--bind-dynamic" 1
+                       ;;
+       esac
+
+       config_get dnsfilter "$cfg" "dnsfilter"
+       case "$dnsfilter" in
+               A|AAAA)
+                       xappend "--filter-$dnsfilter"
+                       ;;
+       esac
+
        append_bool "$cfg" fqdn "--dhcp-fqdn"
        append_bool "$cfg" proxydnssec "--proxy-dnssec"
        append_bool "$cfg" localservice "--local-service"
@@ -896,8 +988,11 @@ dnsmasq_start()
        append_bool "$cfg" rapidcommit "--dhcp-rapid-commit"
        append_bool "$cfg" scriptarp "--script-arp"
 
-       append_parm "$cfg" logfacility "--log-facility"
+       append_bool "$cfg" filter_aaaa "--filter-AAAA"
+       append_bool "$cfg" filter_a "--filter-A"
 
+       append_parm "$cfg" logfacility "--log-facility"
+       config_get logfacility "$cfg" "logfacility"
        append_parm "$cfg" cachesize "--cache-size"
        append_parm "$cfg" dnsforwardmax "--dns-forward-max"
        append_parm "$cfg" port "--port"
@@ -907,20 +1002,42 @@ dnsmasq_start()
        append_parm "$cfg" "minport" "--min-port"
        append_parm "$cfg" "maxport" "--max-port"
        append_parm "$cfg" "domain" "--domain"
-       append_parm "$cfg" "local" "--server"
+       append_parm "$cfg" "local" "--local"
        config_list_foreach "$cfg" "listen_address" append_listenaddress
        config_list_foreach "$cfg" "server" append_server
        config_list_foreach "$cfg" "rev_server" append_rev_server
        config_list_foreach "$cfg" "address" append_address
-       config_list_foreach "$cfg" "ipset" append_ipset
+
+       local connmark_allowlist_enable
+       config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0
+       [ "$connmark_allowlist_enable" -gt 0 ] && {
+               append_parm "$cfg" "connmark_allowlist_enable" "--connmark-allowlist-enable"
+               config_list_foreach "$cfg" "connmark_allowlist" append_connmark_allowlist
+       }
+
        [ -n "$BOOT" ] || {
                config_list_foreach "$cfg" "interface" append_interface
                config_list_foreach "$cfg" "notinterface" append_notinterface
        }
+       config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0
+       if [ "$ignore_hosts_dir" = "1" ]; then
+               xappend "--addn-hosts=$HOSTFILE"
+               append EXTRA_MOUNT "$HOSTFILE"
+       else
+               xappend "--addn-hosts=$(dirname $HOSTFILE)"
+               append EXTRA_MOUNT "$(dirname $HOSTFILE)"
+       fi
        config_list_foreach "$cfg" "addnhosts" append_addnhosts
        config_list_foreach "$cfg" "bogusnxdomain" append_bogusnxdomain
        append_parm "$cfg" "leasefile" "--dhcp-leasefile" "/tmp/dhcp.leases"
-       append_parm "$cfg" "serversfile" "--servers-file"
+
+       local serversfile
+       config_get serversfile "$cfg" "serversfile"
+       [ -n "$serversfile" ] && {
+               xappend "--servers-file=$serversfile"
+               append EXTRA_MOUNT "$serversfile"
+       }
+
        append_parm "$cfg" "tftp_root" "--tftp-root"
        append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
        append_parm "$cfg" "local_ttl" "--local-ttl"
@@ -957,7 +1074,7 @@ dnsmasq_start()
                config_get resolvfile "$cfg" resolvfile /tmp/resolv.conf.d/resolv.conf.auto
                [ -n "$resolvfile" ] && [ ! -e "$resolvfile" ] && touch "$resolvfile"
                xappend "--resolv-file=$resolvfile"
-               [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
+               [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0
                resolvdir="$(dirname "$resolvfile")"
        fi
        config_get_bool localuse "$cfg" localuse "$localuse"
@@ -1012,13 +1129,6 @@ dnsmasq_start()
 
        xappend "--dhcp-broadcast=tag:needs-broadcast"
 
-       config_get_bool ignore_hosts_dir "$cfg" ignore_hosts_dir 0
-       if [ "$ignore_hosts_dir" = "1" ]; then
-               xappend "--addn-hosts=$HOSTFILE"
-       else
-               xappend "--addn-hosts=$(dirname $HOSTFILE)"
-       fi
-
        config_get dnsmasqconfdir "$cfg" confdir "/tmp/dnsmasq.d"
        xappend "--conf-dir=$dnsmasqconfdir"
        dnsmasqconfdir="${dnsmasqconfdir%%,*}"
@@ -1060,11 +1170,6 @@ dnsmasq_start()
        config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg"
        echo >> $CONFIGFILE_TMP
 
-       config_get_bool boguspriv "$cfg" boguspriv 1
-       [ "$boguspriv" -gt 0 ] && {
-               xappend "--bogus-priv"
-               [ -r "$RFC6761FILE" ] && xappend "--conf-file=$RFC6761FILE"
-       }
 
        if [ "$DNSMASQ_DHCP_VER" -gt 4 ] ; then
                # Enable RA feature for when/if it is constructed,
@@ -1088,7 +1193,6 @@ dnsmasq_start()
        config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg"
        echo >> $CONFIGFILE_TMP
 
-       echo >> $CONFIGFILE_TMP
        mv -f $CONFIGFILE_TMP $CONFIGFILE
        mv -f $HOSTFILE_TMP $HOSTFILE
 
@@ -1104,15 +1208,30 @@ dnsmasq_start()
                done
        }
 
+       config_list_foreach "$cfg" addnmount append_extramount
+
        procd_open_instance $cfg
        procd_set_param command $PROG -C $CONFIGFILE -k -x /var/run/dnsmasq/dnsmasq."${cfg}".pid
        procd_set_param file $CONFIGFILE
        [ -n "$user_dhcpscript" ] && procd_set_param env USER_DHCPSCRIPT="$user_dhcpscript"
        procd_set_param respawn
 
+       local instance_ifc instance_netdev
+       config_get instance_ifc "$cfg" interface
+       [ -n "$instance_ifc" ] && network_get_device instance_netdev "$instance_ifc" &&
+               [ -n "$instance_netdev" ] && procd_set_param netdev $instance_netdev
+
        procd_add_jail dnsmasq ubus log
-       procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE $DHCPBOGUSHOSTNAMEFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT
+       procd_add_jail_mount $CONFIGFILE $DHCPBOGUSHOSTNAMEFILE $DHCPSCRIPT $DHCPSCRIPT_DEPENDS
+       procd_add_jail_mount $EXTRA_MOUNT $RFC6761FILE $TRUSTANCHORSFILE
+       procd_add_jail_mount $dnsmasqconffile $dnsmasqconfdir $resolvdir $user_dhcpscript
+       procd_add_jail_mount /etc/passwd /etc/group /etc/TZ /etc/hosts /etc/ethers
        procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
+       case "$logfacility" in */*)
+               [ ! -e "$logfacility" ] && touch "$logfacility"
+               procd_add_jail_mount_rw "$logfacility"
+       esac
+       [ -e "$hostsfile" ] && procd_add_jail_mount $hostsfile
 
        procd_close_instance
 }
@@ -1120,12 +1239,12 @@ dnsmasq_start()
 dnsmasq_stop()
 {
        local cfg="$1"
-       local noresolv resolvfile localuse=0
+       local noresolv resolvfile localuse=1
 
        config_get_bool noresolv "$cfg" noresolv 0
        config_get resolvfile "$cfg" "resolvfile"
 
-       [ "$noresolv" = 0 ] && [ "$resolvfile" = "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=1
+       [ "$noresolv" = 0 ] && [ "$resolvfile" != "/tmp/resolv.conf.d/resolv.conf.auto" ] && localuse=0
        config_get_bool localuse "$cfg" localuse "$localuse"
        [ "$localuse" -gt 0 ] && ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf
 
@@ -1134,10 +1253,11 @@ dnsmasq_stop()
 
 add_interface_trigger()
 {
-       local interface ignore
+       local interface ifname ignore
 
        config_get interface "$1" interface
        config_get_bool ignore "$1" ignore 0
+       network_get_device ifname "$interface" || ignore=0
 
        [ -n "$interface" ] && [ $ignore -eq 0 ] && procd_add_interface_trigger "interface.*" "$interface" /etc/init.d/dnsmasq reload
 }
@@ -1160,6 +1280,7 @@ boot()
 start_service() {
        local instance="$1"
        local instance_found=0
+       local first_instance=""
 
        . /lib/functions/network.sh
 
@@ -1170,10 +1291,27 @@ start_service() {
                        if [ -n "$instance" ] && [ "$instance" = "$name" ]; then
                                instance_found=1
                        fi
+                       if [ -z "$DEFAULT_INSTANCE" ]; then
+                               local disabled
+                               config_get_bool disabled "$name" disabled 0
+                               if [ "$disabled" -eq 0 ]; then
+                                       # First enabled section will be assigned default instance name.
+                                       # Unnamed sections get precedence over named sections.
+                                       if expr "$cfg" : 'cfg[0-9a-f]*$' >/dev/null = "9"; then # See uci_fixup_section.
+                                               DEFAULT_INSTANCE="$name" # Unnamed config section.
+                                       elif [ -z "$first_instance" ]; then
+                                               first_instance="$name"
+                                       fi
+                               fi
+                       fi
                fi
        }
 
+       DEFAULT_INSTANCE=""
        config_load dhcp
+       if [ -z "$DEFAULT_INSTANCE" ]; then
+               DEFAULT_INSTANCE="$first_instance" # No unnamed config section was found.
+       fi
 
        if [ -n "$instance" ]; then
                [ "$instance_found" -gt 0 ] || return