Bump dnsmasq version to v2.78 to fix several CVEs Fixes CVE-2017-14491, CVE-2017...
authorRISCi_ATOM <bob@bobcall.me>
Mon, 2 Oct 2017 17:22:32 +0000 (13:22 -0400)
committerRISCi_ATOM <bob@bobcall.me>
Mon, 2 Oct 2017 17:22:32 +0000 (13:22 -0400)
13 files changed:
package/network/services/dnsmasq/Makefile
package/network/services/dnsmasq/files/dhcp-script.sh [new file with mode: 0755]
package/network/services/dnsmasq/files/dhcp.conf
package/network/services/dnsmasq/files/dnsmasq.init
package/network/services/dnsmasq/files/dnsmasq_acl.json [new file with mode: 0644]
package/network/services/dnsmasq/files/rfc6761.conf [new file with mode: 0644]
package/network/services/dnsmasq/patches/010-Tweak-ICMP-ping-check-logic-for-DHCPv4.patch [deleted file]
package/network/services/dnsmasq/patches/011-Remove-ping-check-of-configured-DHCP-address.patch [deleted file]
package/network/services/dnsmasq/patches/020-Try-other-servers-if-first-returns-REFUSED-when-stri.patch [deleted file]
package/network/services/dnsmasq/patches/025-backport-fix-CVE-2017-13704.patch [deleted file]
package/network/services/dnsmasq/patches/030-fix-arcount-edns0-behaviour.patch [deleted file]
package/network/services/dnsmasq/patches/230-fix-poll-h-include-warning-on-musl.patch
package/network/services/dnsmasq/patches/240-ubus.patch [new file with mode: 0644]

index be7a2d1c0fc7709c889cae8fe3722f731149de2c..9a024ceadf302ce6342e5ecc527f07a4db558b54 100644 (file)
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=dnsmasq
-PKG_VERSION:=2.77
-PKG_RELEASE:=6
+PKG_VERSION:=2.78
+PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=http://thekelleys.org.uk/dnsmasq/
-PKG_HASH:=6eac3b1c50ae25170e3ff8c96ddb55236cf45007633fdb8a35b1f3e02f5f8b8a
+PKG_HASH:=89949f438c74b0c7543f06689c319484bd126cc4b1f8c745c742ab397681252b
 
 PKG_LICENSE:=GPL-2.0
 PKG_LICENSE_FILES:=COPYING
@@ -37,6 +37,7 @@ define Package/dnsmasq/Default
   CATEGORY:=Base system
   TITLE:=DNS and DHCP server
   URL:=http://www.thekelleys.org.uk/dnsmasq/
+  DEPENDS:=+libubus
   USERID:=dnsmasq=453:dnsmasq=453
 endef
 
@@ -48,14 +49,14 @@ endef
 define Package/dnsmasq-dhcpv6
 $(call Package/dnsmasq/Default)
   TITLE += (with DHCPv6 support)
-  DEPENDS:=@IPV6
+  DEPENDS+=@IPV6
   VARIANT:=dhcpv6
 endef
 
 define Package/dnsmasq-full
 $(call Package/dnsmasq/Default)
   TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
-  DEPENDS:=+PACKAGE_dnsmasq_full_dnssec:libnettle \
+  DEPENDS+=+PACKAGE_dnsmasq_full_dnssec:libnettle \
        +PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
        +PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
   VARIANT:=full
@@ -137,7 +138,7 @@ endif
 
 MAKE_FLAGS := \
        $(TARGET_CONFIGURE_OPTS) \
-       CFLAGS="$(TARGET_CFLAGS)" \
+       CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
        LDFLAGS="$(TARGET_LDFLAGS)" \
        COPTS="$(COPTS)" \
        PREFIX="/usr"
@@ -150,8 +151,17 @@ define Package/dnsmasq/install
        $(INSTALL_DATA) ./files/dnsmasq.conf $(1)/etc/dnsmasq.conf
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/dnsmasq.init $(1)/etc/init.d/dnsmasq
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/dhcp
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/neigh
        $(INSTALL_DIR) $(1)/etc/hotplug.d/ntp
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/tftp
        $(INSTALL_DATA) ./files/dnsmasqsec.hotplug $(1)/etc/hotplug.d/ntp/25-dnsmasqsec
+       $(INSTALL_DIR) $(1)/usr/share/dnsmasq
+       $(INSTALL_DATA) ./files/rfc6761.conf $(1)/usr/share/dnsmasq/
+       $(INSTALL_DIR) $(1)/usr/lib/dnsmasq
+       $(INSTALL_BIN) ./files/dhcp-script.sh $(1)/usr/lib/dnsmasq/dhcp-script.sh
+       $(INSTALL_DIR) $(1)/usr/share/acl.d
+       $(INSTALL_DATA) ./files/dnsmasq_acl.json $(1)/usr/share/acl.d/
 endef
 
 Package/dnsmasq-dhcpv6/install = $(Package/dnsmasq/install)
diff --git a/package/network/services/dnsmasq/files/dhcp-script.sh b/package/network/services/dnsmasq/files/dhcp-script.sh
new file mode 100755 (executable)
index 0000000..8603269
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+[ -f "$USER_DHCPSCRIPT" ] && . "$USER_DHCPSCRIPT" "$@"
+
+case "$1" in
+       add)
+               export ACTION="add"
+               export MACADDR="$2"
+               export IPADDR="$3"
+               export HOSTNAME="$4"
+               exec /sbin/hotplug-call dhcp
+       ;;
+       del)
+               export ACTION="remove"
+               export MACADDR="$2"
+               export IPADDR="$3"
+               export HOSTNAME="$4"
+               exec /sbin/hotplug-call dhcp
+       ;;
+       old)
+               export ACTION="update"
+               export MACADDR="$2"
+               export IPADDR="$3"
+               export HOSTNAME="$4"
+               exec /sbin/hotplug-call dhcp
+       ;;
+       arp-add)
+               export ACTION="add"
+               export MACADDR="$2"
+               export IPADDR="$3"
+               exec /sbin/hotplug-call neigh
+       ;;
+       arp-del)
+               export ACTION="remove"
+               export MACADDR="$2"
+               export IPADDR="$3"
+               exec /sbin/hotplug-call neigh
+       ;;
+       tftp)
+               export ACTION="add"
+               export TFTP_SIZE="$2"
+               export TFTP_ADDR="$3"
+               export TFTP_PATH="$4"
+               exec /sbin/hotplug-call tftp
+       ;;
+esac
index 362b90a293f497e05682f35bd62a110dab366ad0..360c7d79eeef397d320c1942250d25e7fc125807 100644 (file)
@@ -15,7 +15,7 @@ config dnsmasq
        option leasefile        '/tmp/dhcp.leases'
        option resolvfile       '/tmp/resolv.conf.auto'
        #list server            '/mycompany.local/1.2.3.4'
-       #option nonwildcard     1
+       option nonwildcard      1 # bind to & keep track of interfaces
        #list interface         br-lan
        #list notinterface      lo
        #list bogusnxdomain     '64.94.110.11'
index a762cd3309a5a951e0947541d8e2ada587d209d2..0149643959761f46fa1e59ab8609c4e7f2c93a3f 100644 (file)
@@ -8,6 +8,8 @@ PROG=/usr/sbin/dnsmasq
 
 ADD_LOCAL_DOMAIN=1
 ADD_LOCAL_HOSTNAME=1
+ADD_WAN_FQDN=0
+ADD_LOCAL_FQDN=""
 
 BASECONFIGFILE="/var/etc/dnsmasq.conf"
 BASEHOSTFILE="/tmp/hosts/dhcp"
@@ -15,6 +17,10 @@ BASETIMESTAMPFILE="/etc/dnsmasq.time"
 TRUSTANCHORSFILE="/usr/share/dnsmasq/trust-anchors.conf"
 TIMEVALIDFILE="/var/state/dnsmasqsec"
 BASEDHCPSTAMPFILE="/var/run/dnsmasq"
+RFC6761FILE="/usr/share/dnsmasq/rfc6761.conf"
+DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
+
+DNSMASQ_DHCP_VER=4
 
 xappend() {
        local value="$1"
@@ -83,12 +89,24 @@ log_once() {
                logger -t dnsmasq "$@"
 }
 
+has_handler() {
+       local file
+
+       for file in /etc/hotplug.d/dhcp/* /etc/hotplug.d/tftp/* /etc/hotplug.d/neigh/*; do
+               [ -f "$file" ] && return 0
+       done
+
+       return 1
+}
+
 append_bool() {
        local section="$1"
        local option="$2"
        local value="$3"
+       local default="$4"
        local _loctmp
-       config_get_bool _loctmp "$section" "$option" 0
+       [ -z "$default" ] && default="0"
+       config_get_bool _loctmp "$section" "$option" "$default"
        [ $_loctmp -gt 0 ] && xappend "$value"
 }
 
@@ -107,6 +125,10 @@ append_server() {
        xappend "--server=$1"
 }
 
+append_rev_server() {
+        xappend "--rev-server=$1"
+}
+
 append_address() {
        xappend "--address=$1"
 }
@@ -116,12 +138,12 @@ append_ipset() {
 }
 
 append_interface() {
-       network_get_device ifname "$1" || return
+       network_get_device ifname "$1" || ifname="$1"
        xappend "--interface=$ifname"
 }
 
 append_notinterface() {
-       network_get_device ifname "$1" || return
+       network_get_device ifname "$1" || ifname="$1"
        xappend "--except-interface=$ifname"
 }
 
@@ -137,6 +159,10 @@ append_pxe_service() {
        xappend "--pxe-service=$1"
 }
 
+append_interface_name() {
+       xappend "--interface-name=$1,$2"
+}
+
 filter_dnsmasq() {
        local cfg="$1" func="$2" match_cfg="$3" found_cfg
 
@@ -180,6 +206,7 @@ dhcp_remoteid_add() {
 }
 
 dhcp_circuitid_add() {
+       # TODO: DHCPV6 does not have circuitid; catch "option6:"
        local cfg="$1"
 
        config_get networkid "$cfg" networkid
@@ -212,6 +239,7 @@ dhcp_userclass_add() {
 }
 
 dhcp_vendorclass_add() {
+       # TODO: DHCPV6 vendor class has stricter definitions; catch? fixup?
        local cfg="$1"
 
        config_get networkid "$cfg" networkid
@@ -245,6 +273,7 @@ dhcp_match_add() {
 
 dhcp_host_add() {
        local cfg="$1"
+       local hosttag nametime addrs duids
 
        config_get_bool force "$cfg" force 0
 
@@ -256,7 +285,9 @@ dhcp_host_add() {
 
        config_get name "$cfg" name
        config_get ip "$cfg" ip
-       [ -n "$ip" -o -n "$name" ] || return 0
+       config_get hostid "$cfg" hostid
+
+       [ -n "$ip" -o -n "$name" -o -n "$hostid" ] || return 0
 
        config_get_bool dns "$cfg" dns 0
        [ "$dns" = "1" -a -n "$ip" -a -n "$name" ] && {
@@ -264,36 +295,105 @@ dhcp_host_add() {
        }
 
        config_get mac "$cfg" mac
+       config_get duid "$cfg" duid
+       config_get tag "$cfg" 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
                macs=""
                for m in $mac; do append macs "$m" ","; done
-       else
-               # --dhcp-host=lap,192.168.0.199
+       fi
+
+       if [ $DNSMASQ_DHCP_VER -eq 6 -a -n "$duid" ]; then
+               # --dhcp-host=id:00:03:00:01:12:00:00:01:02:03,[::beef],lap
+               # one (virtual) machine gets one DUID per RFC3315
+               duids="id:${duid// */}"
+       fi
+
+       if [ -z "$macs" -a -z "$duids" ]; then
+               # --dhcp-host=lap,192.168.0.199,[::beef]
                [ -n "$name" ] || return 0
                macs="$name"
                name=""
        fi
 
-       config_get tag "$cfg" tag
+       if [ -n "$hostid" ]; then
+               hex_to_hostid hostid "$hostid"
+       fi
 
-       if [ "$DHCPv6CAPABLE" -eq 1 ]; then
-               config_get duid "$cfg" duid
-               config_get hostid "$cfg" hostid
-               if [ -n "$hostid" ]; then
-                       hex_to_hostid hostid "$hostid"
-               fi
+       tags=""
+       if [ -n "$tag" ]; then
+               for t in $tag; do append tags "$t" ",set:"; done
        fi
 
        config_get_bool broadcast "$cfg" broadcast 0
-       [ "$broadcast" = "0" ] && broadcast=
-
        config_get leasetime "$cfg" leasetime
 
-       xappend "--dhcp-host=$macs${duid:+,id:$duid}${networkid:+,net:$networkid}${broadcast:+,set:needs-broadcast}${tag:+,set:$tag}${ip:+,$ip${hostid:+,[::$hostid]}}${name:+,$name}${leasetime:+,$leasetime}"
+       [ "$broadcast" = "0" ] && broadcast= || broadcast=",set:needs-broadcast"
+
+       hosttag="${networkid:+,set:${networkid}}${tags:+,set:${tags}}$broadcast"
+       nametime="${name:+,$name}${leasetime:+,$leasetime}"
+
+       if [ $DNSMASQ_DHCP_VER -eq 6 ]; then
+               addrs="${ip:+,$ip}${hostid:+,[::$hostid]}"
+               xappend "--dhcp-host=$macs${duids:+,$duids}$hosttag$addrs$nametime"
+       else
+               xappend "--dhcp-host=$macs$hosttag${ip:+,$ip}$nametime"
+       fi
+}
+
+dhcp_this_host_add() {
+       local net="$1"
+       local ifname="$2"
+       local mode="$3"
+       local routerstub routername ifdashname
+       local lanaddr lanaddr6 lanaddrs6 ulaprefix
+
+       if [ "$mode" -gt 0 ] ; then
+               ifdashname="${ifname//./-}"
+               routerstub="$( md5sum /etc/os-release )"
+               routerstub="router-${routerstub// */}"
+               routername="$( uci_get system @system[0] hostname $routerstub )"
+
+               if [ "$mode" -gt 1 ] ; then
+                       if [ "$mode" -gt 2 ] ; then
+                               if [ "$mode" -gt 3 ] ; then
+                                       append_interface_name "$ifdashname.$routername.$DOMAIN" "$ifname"
+                               fi
+
+                               append_interface_name "$routername.$DOMAIN" "$ifname"
+                       fi
+
+                       # All IP addresses discovered by dnsmasq will be labeled (except fe80::)
+                       append_interface_name "$routername" "$ifname"
+
+               else
+                       # This uses a static host file entry for only limited addresses.
+                       # Use dnsmasq option "--expandhosts" to enable FQDN on host files.
+                       ulaprefix="$(uci_get network @globals[0] ula_prefix)"
+                       network_get_ipaddr lanaddr "$net"
+                       network_get_ipaddrs6 lanaddrs6 "$net"
+
+                       if [ -n "$lanaddr" ] ; then
+                               dhcp_domain_add "" "$routername" "$lanaddr"
+                       fi
+
+                       if [ -n "$ulaprefix" -a -n "$lanaddrs6" ] ; then
+                               for lanaddr6 in $lanaddrs6 ; do
+                                       case "$lanaddr6" in
+                                       "${ulaprefix%%:/*}"*)
+                                               dhcp_domain_add "" "$routername" "$lanaddr6"
+                                               ;;
+                                       esac
+                               done
+                       fi
+               fi
+       fi
 }
 
 dhcp_tag_add() {
+       # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
        local cfg="$1"
 
        tag="$cfg"
@@ -324,6 +424,7 @@ dhcp_mac_add() {
 }
 
 dhcp_boot_add() {
+       # TODO: BOOTURL is different between DHCPv4 and DHCPv6
        local cfg="$1"
 
        config_get networkid "$cfg" networkid
@@ -346,24 +447,30 @@ dhcp_boot_add() {
 
 dhcp_add() {
        local cfg="$1"
+       local dhcp6range="::"
+       local nettag
+       local tags
+
        config_get net "$cfg" interface
        [ -n "$net" ] || return 0
 
-       config_get dhcpv4 "$cfg" dhcpv4
-       [ "$dhcpv4" != "disabled" ] || return 0
-
        config_get networkid "$cfg" networkid
        [ -n "$networkid" ] || networkid="$net"
 
-       network_get_subnet subnet "$net" || return 0
        network_get_device ifname "$net" || return 0
-       network_get_protocol proto "$net" || return 0
 
        [ "$cachelocal" = "0" ] && network_get_dnsserver dnsserver "$net" && {
                DNS_SERVERS="$DNS_SERVERS $dnsserver"
        }
 
-       append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && return 0
+       append_bool "$cfg" ignore "--no-dhcp-interface=$ifname" && {
+               # Many ISP do not have useful names for DHCP customers (your WAN).
+               dhcp_this_host_add "$net" "$ifname" "$ADD_WAN_FQDN"
+               return 0
+       }
+
+       network_get_subnet subnet "$net" || return 0
+       network_get_protocol proto "$net" || return 0
 
        # Do not support non-static interfaces for now
        [ static = "$proto" ] || return 0
@@ -375,21 +482,107 @@ dhcp_add() {
        config_get_bool force "$cfg" force 0
        [ $force -gt 0 ] || dhcp_check "$ifname" || return 0
 
-       config_get start "$cfg" start
-       config_get limit "$cfg" limit
-       config_get leasetime "$cfg" leasetime
+       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
 
-       leasetime="${leasetime:-12h}"
-       start="$(dhcp_calc "${start:-100}")"
-       limit="${limit:-150}"
-       [ "$limit" -gt 0 ] && limit=$((limit-1))
+       config_get dhcpv4 "$cfg" dhcpv4
+       config_get dhcpv6 "$cfg" dhcpv6
+
+       config_get ra "$cfg" ra
+       config_get ra_management "$cfg" ra_management
+       config_get ra_preference "$cfg" ra_preference
+       config_get dns "$cfg" dns
+
+       config_list_foreach "$cfg" "interface_name" append_interface_name "$ifname"
+
+       # Put the router host name on this DHCP served interface address(es)
+       dhcp_this_host_add "$net" "$ifname" "$ADD_LOCAL_FQDN"
+
+       start="$( dhcp_calc "$start" )"
+
+       add_tag() {
+               tags="${tags}tag:$1,"
+       }
+       config_list_foreach "$cfg" tag add_tag
+
+       nettag="${networkid:+set:${networkid},}"
+
+       if [ "$limit" -gt 0 ] ; then
+               limit=$((limit-1))
+       fi
+
        eval "$(ipcalc.sh "${subnet%%/*}" $netmask $start $limit)"
-       if [ "$dynamicdhcp" = "0" ]; then END="static"; fi
-       xappend "--dhcp-range=$networkid,$START,$END,$NETMASK,$leasetime${options:+ $options}"
 
-       dhcp_option_add "$cfg" "$networkid"
+       if [ "$dynamicdhcp" = "0" ] ; then
+               END="static"
+               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 -a "$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.
+
+               case $ra_preference in
+               *high*)
+                       xappend "--ra-param=$ifname,high,0,7200"
+                       ;;
+               *low*)
+                       xappend "--ra-param=$ifname,low,0,7200"
+                       ;;
+               *)
+                       # Send UNSOLICITED RA at default interval and live for 2 hours.
+                       # TODO: convert flexible lease time into route life time (only seconds).
+                       xappend "--ra-param=$ifname,0,7200"
+                       ;;
+               esac
+
+               if [ "$dhcpv6" = "disabled" ] ; then
+                       ra_management="3"
+               fi
+
+
+               case $ra_management in
+               0)
+                       # SLACC with DCHP for extended options
+                       xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-stateless,ra-names"
+                       ;;
+               2)
+                       # DHCP address and RA only for management redirection
+                       xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,$leasetime"
+                       ;;
+               3)
+                       # SLAAC only but dnsmasq attempts to link HOSTNAME, DHCPv4 MAC, and SLAAC
+                       xappend "--dhcp-range=$nettag::,constructor:$ifname,ra-only,ra-names"
+                       ;;
+               *)
+                       # SLAAC and full DHCP
+                       xappend "--dhcp-range=$nettag$dhcp6range,constructor:$ifname,slaac,ra-names,$leasetime"
+                       ;;
+               esac
+
+               if [ -n "$dns" ]; then
+                       dnss=""
+                       for d in $dns; do append dnss "[$d]" ","; done
+               else
+                       dnss="[::]"
+               fi
+
+               dhcp_option_append "option6:dns-server,$dnss" "$networkid"
+       fi
+
+       dhcp_option_add "$cfg" "$networkid" 0
+       dhcp_option_add "$cfg" "$networkid" 2
 }
 
 dhcp_option_append() {
@@ -401,21 +594,24 @@ dhcp_option_append() {
 }
 
 dhcp_option_add() {
+       # NOTE: dnsmasq has explicit "option6:" prefix for DHCPv6 so no collisions
        local cfg="$1"
        local networkid="$2"
        local force="$3"
+       local opt="dhcp_option"
 
        [ "$force" = "0" ] && force=
+       [ "$force" = "2" ] && opt="dhcp_option_force"
 
        local list_len
-       config_get list_len "$cfg" dhcp_option_LENGTH
+       config_get list_len "$cfg" "${opt}_LENGTH"
 
        if [ -n "$list_len" ]; then
-               config_list_foreach "$cfg" dhcp_option dhcp_option_append "$networkid" "$force"
+               config_list_foreach "$cfg" "$opt" dhcp_option_append "$networkid" "$force"
        else
-               config_get dhcp_option "$cfg" dhcp_option
+               config_get dhcp_option "$cfg" "$opt"
 
-               [ -n "$dhcp_option" ] && echo "Warning: the 'option dhcp_option' syntax is deprecated, use 'list dhcp_option'" >&2
+               [ -n "$dhcp_option" ] && echo "Warning: the 'option $opt' syntax is deprecated, use 'list $opt'" >&2
 
                local option
                for option in $dhcp_option; do
@@ -533,7 +729,7 @@ dhcp_relay_add() {
 
 dnsmasq_start()
 {
-       local cfg="$1" disabled
+       local cfg="$1" disabled resolvfile user_dhcpscript
 
        config_get_bool disabled "$cfg" disabled 0
        [ "$disabled" -gt 0 ] && return 0
@@ -566,6 +762,41 @@ dnsmasq_start()
 
        $PROG --version | grep -osqE "^Compile time options:.* DHCPv6( |$)" && DHCPv6CAPABLE=1 || DHCPv6CAPABLE=0
 
+
+       if [ -x /usr/sbin/odhcpd -a -x /etc/init.d/odhcpd ] ; then
+               local odhcpd_is_main odhcpd_is_enabled
+               config_get odhcpd_is_main odhcpd maindhcp 0
+               /etc/init.d/odhcpd enabled && odhcpd_is_enabled=1 || odhcpd_is_enabled=0
+
+
+               if [ "$odhcpd_is_enabled" -eq 0 -a "$DHCPv6CAPABLE" -eq 1 ] ; then
+                       # DHCP V4 and V6 in DNSMASQ
+                       DNSMASQ_DHCP_VER=6
+               elif [ "$odhcpd_is_main" -gt 0 ] ; then
+                       # ODHCPD is doing it all
+                       DNSMASQ_DHCP_VER=0
+               else
+                       # You have ODHCPD but use DNSMASQ for DHCPV4
+                       DNSMASQ_DHCP_VER=4
+               fi
+
+       elif [ "$DHCPv6CAPABLE" -eq 1 ] ; then
+               # DHCP V4 and V6 in DNSMASQ
+               DNSMASQ_DHCP_VER=6
+       else
+               DNSMASQ_DHCP_VER=4
+       fi
+
+       # Allow DHCP/DHCPv6 to be handled by ISC DHCPD
+       if [ -x /usr/sbin/dhcpd ] ; then
+               if [ -x /etc/init.d/dhcpd ] ; then
+                       /etc/init.d/dhcpd enabled && DNSMASQ_DHCP_VER=0
+               fi
+               if [ -x /etc/init.d/dhcpd6 -a "$DNSMASQ_DHCP_VER" -gt 0 ] ; then
+                       /etc/init.d/dhcpd6 enabled && DNSMASQ_DHCP_VER=4
+               fi
+       fi
+
        append_bool "$cfg" authoritative "--dhcp-authoritative"
        append_bool "$cfg" nodaemon "--no-daemon"
        append_bool "$cfg" domainneeded "--domain-needed"
@@ -578,12 +809,11 @@ dnsmasq_start()
        append_bool "$cfg" localise_queries "--localise-queries"
        append_bool "$cfg" readethers "--read-ethers"
        append_bool "$cfg" dbus "--enable-dbus"
-       append_bool "$cfg" boguspriv "--bogus-priv"
        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"
+       append_bool "$cfg" nonwildcard "--bind-dynamic" 1
        append_bool "$cfg" fqdn "--dhcp-fqdn"
        append_bool "$cfg" proxydnssec "--proxy-dnssec"
        append_bool "$cfg" localservice "--local-service"
@@ -594,7 +824,7 @@ dnsmasq_start()
        append_bool "$cfg" noping "--no-ping"
 
        append_parm "$cfg" logfacility "--log-facility"
-       append_parm "$cfg" dhcpscript "--dhcp-script"
+
        append_parm "$cfg" cachesize "--cache-size"
        append_parm "$cfg" dnsforwardmax "--dns-forward-max"
        append_parm "$cfg" port "--port"
@@ -606,6 +836,7 @@ dnsmasq_start()
        append_parm "$cfg" "domain" "--domain"
        append_parm "$cfg" "local" "--server"
        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
        config_list_foreach "$cfg" "interface" append_interface
@@ -613,7 +844,6 @@ dnsmasq_start()
        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" "resolvfile" "--resolv-file" "/tmp/resolv.conf.auto"
        append_parm "$cfg" "serversfile" "--servers-file"
        append_parm "$cfg" "tftp_root" "--tftp-root"
        append_parm "$cfg" "dhcp_boot" "--dhcp-boot"
@@ -624,12 +854,21 @@ dnsmasq_start()
 
        config_get_bool ADD_LOCAL_DOMAIN "$cfg" add_local_domain 1
        config_get_bool ADD_LOCAL_HOSTNAME "$cfg" add_local_hostname 1
+       config_get ADD_LOCAL_FQDN "$cfg" add_local_fqdn ""
+       config_get ADD_WAN_FQDN "$cfg" add_wan_fqdn 0
+
+       if [ -z "$ADD_LOCAL_FQDN" ] ; then
+               # maintain support for previous UCI
+               ADD_LOCAL_FQDN="$ADD_LOCAL_HOSTNAME"
+       fi
 
        config_get_bool readethers "$cfg" readethers
        [ "$readethers" = "1" -a \! -e "/etc/ethers" ] && touch /etc/ethers
 
-       config_get resolvfile $cfg resolvfile
-       config_get dhcpscript $cfg dhcpscript
+       config_get user_dhcpscript $cfg dhcpscript
+       if has_handler || [ -n "$user_dhcpscript" ]; then
+               xappend "--dhcp-script=$DHCPSCRIPT"
+       fi
 
        config_get leasefile $cfg leasefile "/tmp/dhcp.leases"
        [ -n "$leasefile" -a \! -e "$leasefile" ] && touch "$leasefile"
@@ -642,6 +881,8 @@ dnsmasq_start()
                [ -n "$resolvfile" -a \! -e "$resolvfile" ] && touch "$resolvfile"
        fi
 
+       [ -n "$resolvfile" ] && xappend "--resolv-file=$resolvfile"
+
        config_get hostsfile "$cfg" dhcphostsfile
        [ -e "$hostsfile" ] && xappend "--dhcp-hostsfile=$hostsfile"
 
@@ -688,6 +929,7 @@ dnsmasq_start()
        }
 
        dhcp_option_add "$cfg" "" 0
+       dhcp_option_add "$cfg" "" 2
 
        xappend "--dhcp-broadcast=tag:needs-broadcast"
 
@@ -721,37 +963,31 @@ dnsmasq_start()
        config_foreach filter_dnsmasq hostrecord dhcp_hostrecord_add "$cfg"
        config_foreach filter_dnsmasq relay dhcp_relay_add "$cfg"
 
-       # add own hostname
-       [ $ADD_LOCAL_HOSTNAME -eq 1 ] && {
-               local lanaddr lanaddr6
-               local ulaprefix="$(uci_get network @globals[0] ula_prefix)"
-               local hostname="$(uci_get system @system[0] hostname Lede)"
-
-               network_get_ipaddr lanaddr "lan" && {
-                       dhcp_domain_add "" "$hostname" "$lanaddr"
-               }
-
-               [ -n "$ulaprefix" ] && network_get_ipaddrs6 lanaddr6 "lan" && {
-                       for lanaddr6 in $lanaddr6; do
-                               case "$lanaddr6" in
-                                       "${ulaprefix%%:/*}"*)
-                                               dhcp_domain_add "" "$hostname" "$lanaddr6"
-                                       ;;
-                               esac
-                       done
-               }
-       }
-
        echo >> $CONFIGFILE_TMP
        config_foreach filter_dnsmasq srvhost dhcp_srv_add "$cfg"
        config_foreach filter_dnsmasq mxhost dhcp_mx_add "$cfg"
        echo >> $CONFIGFILE_TMP
 
-       config_get odhcpd_is_active odhcpd maindhcp
-       if [ "$odhcpd_is_active" != "1" ]; then
+       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,
+               # and RA is selected per interface pool (RA, DHCP, or both),
+               # but no one (should) want RA broadcast in syslog
+               config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
+               xappend "--enable-ra"
+               xappend "--quiet-ra"
+               append_bool "$cfg" quietdhcp "--quiet-dhcp6"
+
+       elif [ "$DNSMASQ_DHCP_VER" -gt 0 ] ; then
                config_foreach filter_dnsmasq dhcp dhcp_add "$cfg"
        fi
 
+
        echo >> $CONFIGFILE_TMP
        config_foreach filter_dnsmasq cname dhcp_cname_add "$cfg"
        echo >> $CONFIGFILE_TMP
@@ -773,6 +1009,7 @@ dnsmasq_start()
        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 dnsmasqconffile="/etc/dnsmasq.${cfg}.conf"
@@ -781,7 +1018,7 @@ dnsmasq_start()
        fi
 
        procd_add_jail dnsmasq ubus log
-       procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvfile $dhcpscript /etc/hosts /etc/ethers $EXTRA_MOUNT
+       procd_add_jail_mount $CONFIGFILE $TRUSTANCHORSFILE $HOSTFILE $RFC6761FILE /etc/passwd /etc/group /etc/TZ /dev/null /dev/urandom $dnsmasqconffile $dnsmasqconfdir $resolvfile $user_dhcpscript /etc/hosts /etc/ethers /sbin/hotplug-call $EXTRA_MOUNT $DHCPSCRIPT
        procd_add_jail_mount_rw /var/run/dnsmasq/ $leasefile
 
        procd_close_instance
diff --git a/package/network/services/dnsmasq/files/dnsmasq_acl.json b/package/network/services/dnsmasq/files/dnsmasq_acl.json
new file mode 100644 (file)
index 0000000..00ec7d0
--- /dev/null
@@ -0,0 +1,4 @@
+{
+       "user": "dnsmasq",
+       "publish": [ "dnsmasq" ]
+}
diff --git a/package/network/services/dnsmasq/files/rfc6761.conf b/package/network/services/dnsmasq/files/rfc6761.conf
new file mode 100644 (file)
index 0000000..ebc1a12
--- /dev/null
@@ -0,0 +1,15 @@
+# RFC6761 included configuration file for dnsmasq
+#
+# includes a list of domains that should not be forwarded to Internet name servers
+# to reduce burden on them, asking questions that they won't know the answer to.
+
+server=/bind/
+server=/example/
+server=/example.com/
+server=/example.org/
+server=/example.net/
+server=/invalid/
+server=/local/
+server=/localhost/
+server=/onion/
+server=/test/
diff --git a/package/network/services/dnsmasq/patches/010-Tweak-ICMP-ping-check-logic-for-DHCPv4.patch b/package/network/services/dnsmasq/patches/010-Tweak-ICMP-ping-check-logic-for-DHCPv4.patch
deleted file mode 100644 (file)
index 571ff36..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 4bb68866a8aeb31db8100492bceae051e33be5d0 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 15 Jun 2017 23:18:44 +0100
-Subject: [PATCH] Tweak ICMP ping check logic for DHCPv4.
-
----
- src/rfc2131.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/rfc2131.c b/src/rfc2131.c
-index 1c850e5..75792da 100644
---- a/src/rfc2131.c
-+++ b/src/rfc2131.c
-@@ -1040,7 +1040,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
-                 else if (have_config(config, CONFIG_DECLINED) &&
-                          difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
-                   my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
--                else if (!do_icmp_ping(now, config->addr, 0, loopback))
-+                else if ((!lease || lease->addr.s_addr != config->addr.s_addr) && !do_icmp_ping(now, config->addr, 0, loopback))
-                   my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
-                 else
-                   conf = config->addr;
--- 
-1.9.1
-
diff --git a/package/network/services/dnsmasq/patches/011-Remove-ping-check-of-configured-DHCP-address.patch b/package/network/services/dnsmasq/patches/011-Remove-ping-check-of-configured-DHCP-address.patch
deleted file mode 100644 (file)
index 67f90e1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From 1d224949cced9e82440d00b3dbaf32c262bac2ff Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Sat, 8 Jul 2017 20:52:55 +0100
-Subject: [PATCH 1/2] Remove ping-check of configured DHCP address.
-
-This was added in 5ce3e76fbf89e942e8c54ef3e3389facf0d9067a but
-it trips over too many buggy clients that leave an interface configured
-even in DHCPDISCOVER case.
----
- src/rfc2131.c | 2 --
- 1 file changed, 2 deletions(-)
-
-diff --git a/src/rfc2131.c b/src/rfc2131.c
-index 86230b4..785e15c 100644
---- a/src/rfc2131.c
-+++ b/src/rfc2131.c
-@@ -1040,8 +1040,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
-                 else if (have_config(config, CONFIG_DECLINED) &&
-                          difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
-                   my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
--                else if ((!lease || lease->addr.s_addr != config->addr.s_addr) && !do_icmp_ping(now, config->addr, 0, loopback))
--                  my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
-                 else
-                   conf = config->addr;
-               }
--- 
-2.13.2
-
diff --git a/package/network/services/dnsmasq/patches/020-Try-other-servers-if-first-returns-REFUSED-when-stri.patch b/package/network/services/dnsmasq/patches/020-Try-other-servers-if-first-returns-REFUSED-when-stri.patch
deleted file mode 100644 (file)
index cdab607..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 9396752c115b3ab733fa476b30da73237e12e7ba Mon Sep 17 00:00:00 2001
-From: Hans Dedecker <dedeckeh@gmail.com>
-Date: Tue, 27 Jun 2017 22:08:47 +0100
-Subject: [PATCH] Try other servers if first returns REFUSED when
- --strict-order active.
-
-If a DNS server replies REFUSED for a given DNS query in strict order mode
-no failover to the next DNS server is triggered as the failover logic only
-covers non strict mode.
-As a result the client will be returned the REFUSED reply without first
-falling back to the secondary DNS server(s).
-
-Make failover support work as well for strict mode config in case REFUSED is
-replied by deleting the strict order check and rely only on forwardall being
-equal to 0 which is the case in non strict mode when a single server has been
-contacted or when strict order mode has been configured.
----
- CHANGELOG     | 4 ++++
- src/forward.c | 1 -
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -790,7 +790,6 @@ void reply_query(int fd, int family, tim
-   /* Note: if we send extra options in the EDNS0 header, we can't recreate
-      the query from the reply. */
-   if (RCODE(header) == REFUSED &&
--      !option_bool(OPT_ORDER) &&
-       forward->forwardall == 0 &&
-       !(forward->flags & FREC_HAS_EXTRADATA))
-     /* for broken servers, attempt to send to another one. */
diff --git a/package/network/services/dnsmasq/patches/025-backport-fix-CVE-2017-13704.patch b/package/network/services/dnsmasq/patches/025-backport-fix-CVE-2017-13704.patch
deleted file mode 100644 (file)
index bba9a08..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-From 63437ffbb58837b214b4b92cb1c54bc5f3279928 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Wed, 6 Sep 2017 22:34:21 +0100
-Subject: [PATCH] Fix CVE-2017-13704, which resulted in a crash on a large DNS
- query.
-
-A DNS query recieved by UDP which exceeds 512 bytes (or the EDNS0 packet size,
-if different.) is enough to cause SIGSEGV.
----
- CHANGELOG     |    7 +++++++
- src/auth.c    |    5 -----
- src/forward.c |    8 ++++++++
- src/rfc1035.c |    5 -----
- 4 files changed, 15 insertions(+), 10 deletions(-)
-
-diff --git a/CHANGELOG b/CHANGELOG
-index 3a640f3..7e65912 100644
---- a/CHANGELOG
-+++ b/CHANGELOG
-@@ -17,6 +17,13 @@ version 2.78
-       --strict-order active. Thanks to Hans Dedecker
-       for the patch
-+      Fix regression in 2.77, ironically added as a security
-+      improvement, which resulted in a crash when a DNS
-+      query exceeded 512 bytes (or the EDNS0 packet size,
-+      if different.) Thanks to Christian Kujau, Arne Woerner
-+      Juan Manuel Fernandez and Kevin Darbyshire-Bryant for
-+      chasing this one down.  CVE-2017-13704 applies.
-+
-       
- version 2.77
-       Generate an error when configured with a CNAME loop,
-diff --git a/src/auth.c b/src/auth.c
-index 2c24e16..7f95f98 100644
---- a/src/auth.c
-+++ b/src/auth.c
-@@ -119,11 +119,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
-   struct cname *a, *candidate;
-   unsigned int wclen;
-   
--  /* Clear buffer beyond request to avoid risk of
--     information disclosure. */
--  memset(((char *)header) + qlen, 0, 
--       (limit - ((char *)header)) - qlen);
--  
-   if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
-     return 0;
-diff --git a/src/forward.c b/src/forward.c
-index f22556a..e3fa94b 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -1188,6 +1188,10 @@ void receive_query(struct listener *listen, time_t now)
-       (msg.msg_flags & MSG_TRUNC) ||
-       (header->hb3 & HB3_QR))
-     return;
-+
-+  /* Clear buffer beyond request to avoid risk of
-+     information disclosure. */
-+  memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
-   
-   source_addr.sa.sa_family = listen->family;
-   
-@@ -1688,6 +1692,10 @@ unsigned char *tcp_request(int confd, time_t now,
-   
-       if (size < (int)sizeof(struct dns_header))
-       continue;
-+
-+      /* Clear buffer beyond request to avoid risk of
-+       information disclosure. */
-+      memset(payload + size, 0, 65536 - size);
-       
-       query_count++;
-diff --git a/src/rfc1035.c b/src/rfc1035.c
-index 26f5301..af2fe46 100644
---- a/src/rfc1035.c
-+++ b/src/rfc1035.c
-@@ -1223,11 +1223,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
-   struct mx_srv_record *rec;
-   size_t len;
--  /* Clear buffer beyond request to avoid risk of
--     information disclosure. */
--  memset(((char *)header) + qlen, 0, 
--       (limit - ((char *)header)) - qlen);
--  
-   if (ntohs(header->ancount) != 0 ||
-       ntohs(header->nscount) != 0 ||
-       ntohs(header->qdcount) == 0 || 
--- 
-1.7.10.4
-
diff --git a/package/network/services/dnsmasq/patches/030-fix-arcount-edns0-behaviour.patch b/package/network/services/dnsmasq/patches/030-fix-arcount-edns0-behaviour.patch
deleted file mode 100644 (file)
index fffc8de..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From a3303e196e5d304ec955c4d63afb923ade66c6e8 Mon Sep 17 00:00:00 2001
-From: Simon Kelley <simon@thekelleys.org.uk>
-Date: Thu, 7 Sep 2017 20:45:00 +0100
-Subject: [PATCH] Don't return arcount=1 if EDNS0 RR won't fit in the packet.
-
-Omitting the EDNS0 RR but setting arcount gives a malformed packet.
-Also, don't accept UDP packet size less than 512 in recieved EDNS0.
----
- src/edns0.c   |    5 ++++-
- src/forward.c |    2 ++
- 2 files changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/edns0.c b/src/edns0.c
-index 3fde17f..f5b798c 100644
---- a/src/edns0.c
-+++ b/src/edns0.c
-@@ -208,7 +208,10 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
-         free(buff);
-         p += rdlen;
-       }
--      header->arcount = htons(ntohs(header->arcount) + 1);
-+      
-+      /* Only bump arcount if RR is going to fit */ 
-+      if (((ssize_t)optlen) <= (limit - (p + 4)))
-+      header->arcount = htons(ntohs(header->arcount) + 1);
-     }
-   
-   if (((ssize_t)optlen) > (limit - (p + 4)))
-diff --git a/src/forward.c b/src/forward.c
-index e3fa94b..942b02d 100644
---- a/src/forward.c
-+++ b/src/forward.c
-@@ -1412,6 +1412,8 @@ void receive_query(struct listener *listen, time_t now)
-        defaults to 512 */
-       if (udp_size > daemon->edns_pktsz)
-       udp_size = daemon->edns_pktsz;
-+      else if (udp_size < PACKETSZ)
-+      udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
-     }
- #ifdef HAVE_AUTH
--- 
-1.7.10.4
-
index 19300f7d66b80c832f3bf30a2a4d189082c3adfd..37b11abc1de075a87196e8e5609d56eea9f400cc 100644 (file)
@@ -7,7 +7,7 @@ Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
 
 --- a/src/dnsmasq.h
 +++ b/src/dnsmasq.h
-@@ -82,7 +82,7 @@ typedef unsigned long long u64;
+@@ -88,7 +88,7 @@ typedef unsigned long long u64;
  #if defined(HAVE_SOLARIS_NETWORK)
  #  include <sys/sockio.h>
  #endif
diff --git a/package/network/services/dnsmasq/patches/240-ubus.patch b/package/network/services/dnsmasq/patches/240-ubus.patch
new file mode 100644 (file)
index 0000000..2d37b5d
--- /dev/null
@@ -0,0 +1,126 @@
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -19,6 +19,8 @@
+ #include "dnsmasq.h"
++#include <libubus.h>
++
+ struct daemon *daemon;
+ static volatile pid_t pid = 0;
+@@ -32,6 +34,62 @@ static void fatal_event(struct event_des
+ static int read_event(int fd, struct event_desc *evp, char **msg);
+ static void poll_resolv(int force, int do_reload, time_t now);
++static struct ubus_context *ubus;
++static struct blob_buf b;
++
++static struct ubus_object_type ubus_object_type = {
++      .name = "dnsmasq",
++};
++
++static struct ubus_object ubus_object = {
++      .name = "dnsmasq",
++      .type = &ubus_object_type,
++};
++
++void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name)
++{
++      if (!ubus || !ubus_object.has_subscribers)
++              return;
++
++      blob_buf_init(&b, 0);
++      if (mac)
++              blobmsg_add_string(&b, "mac", mac);
++      if (ip)
++              blobmsg_add_string(&b, "ip", ip);
++      if (name)
++              blobmsg_add_string(&b, "name", name);
++      ubus_notify(ubus, &ubus_object, type, b.head, -1);
++}
++
++static void set_ubus_listeners(void)
++{
++      if (!ubus)
++              return;
++
++      poll_listen(ubus->sock.fd, POLLIN);
++      poll_listen(ubus->sock.fd, POLLERR);
++      poll_listen(ubus->sock.fd, POLLHUP);
++}
++
++static void check_ubus_listeners()
++{
++      if (!ubus) {
++              ubus = ubus_connect(NULL);
++              if (ubus)
++                      ubus_add_object(ubus, &ubus_object);
++              else
++                      return;
++      }
++
++      if (poll_check(ubus->sock.fd, POLLIN))
++              ubus_handle_event(ubus);
++
++      if (poll_check(ubus->sock.fd, POLLHUP)) {
++              ubus_free(ubus);
++              ubus = NULL;
++      }
++}
++
+ int main (int argc, char **argv)
+ {
+   int bind_fallback = 0;
+@@ -911,6 +969,7 @@ int main (int argc, char **argv)
+       set_dbus_listeners();
+ #endif        
+   
++      set_ubus_listeners();
+ #ifdef HAVE_DHCP
+       if (daemon->dhcp || daemon->relay4)
+       {
+@@ -1041,6 +1100,8 @@ int main (int argc, char **argv)
+       check_dbus_listeners();
+ #endif
+       
++      check_ubus_listeners();
++
+       check_dns_listeners(now);
+ #ifdef HAVE_TFTP
+--- a/Makefile
++++ b/Makefile
+@@ -85,7 +85,7 @@ all : $(BUILDDIR)
+       @cd $(BUILDDIR) && $(MAKE) \
+  top="$(top)" \
+  build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
+- build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
++ build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) -lubox -lubus" \
+  -f $(top)/Makefile dnsmasq 
+ mostly_clean :
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -1397,6 +1397,8 @@ void emit_dbus_signal(int action, struct
+ #  endif
+ #endif
++void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name);
++
+ /* ipset.c */
+ #ifdef HAVE_IPSET
+ void ipset_init(void);
+--- a/src/rfc2131.c
++++ b/src/rfc2131.c
+@@ -1621,6 +1621,10 @@ static void log_packet(char *type, void
+             daemon->namebuff,
+             string ? string : "",
+             err ? err : "");
++  if (!strcmp(type, "DHCPACK"))
++        ubus_event_bcast("dhcp.ack", addr ? inet_ntoa(a) : NULL, daemon->namebuff, string ? string : NULL);
++  else if (!strcmp(type, "DHCPRELEASE"))
++        ubus_event_bcast("dhcp.release", addr ? inet_ntoa(a) : NULL, daemon->namebuff, string ? string : NULL);
+ }
+ static void log_options(unsigned char *start, u32 xid)