unbound: add option for dhcp UCI domain mx srv and cname
authorEric Luehrsen <redacted>
Wed, 10 May 2017 02:46:39 +0000 (22:46 -0400)
committerEric Luehrsen <redacted>
Tue, 23 May 2017 04:14:33 +0000 (00:14 -0400)
Base LEDE/OpenWrt UCI for dnsmasq provides for DNS override in
/etc/config/dhcp. It is desired to be able to use dnsmasq and
Unbound as transparently as possible. Option 'add_extra_dns'
will pull 'domain', 'mxhost', 'srvhost, and 'cname' from base.

netifd/procd have an interaction with DHCPv6/RA on WAN (FS#713).
Minor IP6 parameter updates can cause Unbound reload events every
few minutes. List option 'trigger' selects which interfaces may
cause reload. For example 'lan', 'wan' but not 'wan6'.

Squash other cosmetics.

Signed-off-by: Eric Luehrsen <redacted>
net/unbound/Makefile
net/unbound/files/README.md
net/unbound/files/odhcpd.sh
net/unbound/files/unbound.init
net/unbound/files/unbound.sh
net/unbound/files/unbound.uci

index 7dcd2a60803ef578234e3b8ebe955bc4e6f8b0c9..a7171e59d0783216e5f33d1e5c553cdf6546444d 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=unbound
 PKG_VERSION:=1.6.2
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_LICENSE:=BSD-3-Clause
 PKG_LICENSE_FILES:=LICENSE
index d8bdf958fbc1ef31fcadeb16dac1907981f839c3..db0f5974f49e8522d4a7de940f79d082efb0b7e8 100644 (file)
@@ -73,7 +73,7 @@ config dhcp 'lan'
 ```
 
 ### Unbound and odhcpd
-You may ask can Unbound replace dnsmasq? You can have DHCP-DNS records with Unbound and odhcpd only. The UCI scripts will allow Unbound to act like dnsmasq. When odhcpd configures each DHCP lease, it will call a script. The script provided with Unbound will read the lease file for DHCP-DNS records. You **must install** `unbound-control`, because the lease records are added and removed without starting, stopping, flushing cache, or re-writing conf files. (_restart overhead can be excessive with even a few mobile devices._)
+You may ask, "can Unbound replace dnsmasq?" You can have DHCP-DNS records with Unbound and odhcpd only. The UCI scripts will allow Unbound to act like dnsmasq. When odhcpd configures each DHCP lease, it will call a script. The script provided with Unbound will read the lease file for DHCP-DNS records. You **must install** `unbound-control`, because the lease records are added and removed without starting, stopping, flushing cache, or re-writing conf files. (_restart overhead can be excessive with even a few mobile devices._)
 
 Don't forget to disable or uninstall dnsmasq when you don't intend to use it. Strange results may occur. If you want to use default dnsmasq+odhcpd and add Unbound on top, then use the dnsmasq-serial or dnsmasq-parallel methods above.
 
@@ -106,8 +106,7 @@ config dhcp 'lan'
   option leasetime '12h'
   option ra 'server'
   option ra_management '1'
-  # issue your ULA and avoid default [fe80::]
-  list dns 'fdxx:xxxx:xxxx::1'
+  # odhcpd should issue ULA [fd00::/8] by default
   ...
 
 config odhcpd 'odhcpd'
@@ -146,6 +145,14 @@ The former will be added to the end of the `server:` clause. The later will be a
 config unbound
   Currently only one instance is supported.
 
+  option add_extra_dns '0'
+    Level. Execute traditional DNS overrides found in `/etc/config/dhcp`.
+    Optional so you may use other Unbound conf or redirect to NSD instance.
+    0 - Ignore `/etc/config/dhcp`
+    1 - Use only 'domain' clause (host records)
+    2 - Use 'domain', 'mxhost', and 'srvhost' clauses
+    3 - Use all of 'domain', 'mxhost', 'srvhost', and 'cname' clauses
+
   option add_local_fqdn '0'
     Level. This puts your routers host name in the LAN (local) DNS.
     Each level is more detailed and comprehensive.
@@ -271,9 +278,15 @@ config unbound
     embedded devices don't have a real time power off clock. NTP needs
     DNS to resolve servers. This works around the chicken-and-egg.
 
-  list domain_insecure
-    List. Domains or pointers that you wish to skip DNSSEC. Your DHCP
-    domains and pointers in dnsmasq will get this automatically.
+  list domain_insecure 'www.example.com'
+    Domain. Domains that you wish to skip DNSSEC. Your DHCP
+    domains and pointers will get this automatically.
+
+  list trigger 'lan' 'wan'
+    Interface (logical). This option is a work around for netifd/procd
+    interaction with WAN DHCPv6. Minor RA or DHCP changes in IP6 can
+    cause netifd to execute procd interface reload. Limit Unbound procd
+    triggers to LAN and WAN (IP4 only) to prevent restart @2-3 minutes.
 ```
 
 
index 22a470b4cd6f2c970c42d2d3a09a95f82690c337..c93d280a00a70123d4440443a0706f94d52a5ac5 100644 (file)
@@ -45,7 +45,7 @@ odhcpd_zonedata() {
   local dhcp_ls_old=$UNBOUND_VARDIR/dhcp_lease.old
   local dhcp_ls_add=$UNBOUND_VARDIR/dhcp_lease.add
   local dhcp_ls_del=$UNBOUND_VARDIR/dhcp_lease.del
-  local dhcp_origin=$( uci get dhcp.@odhcpd[0].leasefile )
+  local dhcp_origin=$( uci_get dhcp.@odhcpd[0].leasefile )
 
   config_load unbound
   config_foreach odhcpd_settings unbound
index 1edf9ef80d8804366f5c1323201d0b0010fee26a..5027b79b50ee6952fa037c7f88cfdf800d41d646 100755 (executable)
@@ -47,7 +47,7 @@ start_service() {
 
 stop_service() {
   unbound_stop
-  
+
   # Wait! on restart Unbound may take time writing closure stats to syslog
   pidof $PROG && sleep 1
 }
@@ -55,9 +55,20 @@ stop_service() {
 ##############################################################################
 
 service_triggers() {
-  # use soft reload to prevent continuous stop-start and cache flush
+  local trigger
+  local triggers=$( uci_get unbound.@unbound[0].trigger )
+
+  PROCD_RELOAD_DELAY=2000
   procd_add_reload_trigger "unbound"
-  procd_add_raw_trigger "interface.*.up" 2000 /etc/init.d/unbound reload
+
+  if [ -n "$triggers" ] ; then
+    for trigger in $triggers ; do
+      # due to some netifd/procd interactions with IP6, limit interfaces
+      procd_add_reload_interface_trigger "$trigger"
+    done
+  else
+    procd_add_raw_trigger "interface.*.up" 2000 /etc/init.d/unbound reload
+  fi
 }
 
 ##############################################################################
index 4daefda4d1138c49f6b12742e22fd8ecf32be036..197a06d9718bcd16f333b642eec4a7f1a8a02316 100644 (file)
 #
 ##############################################################################
 #
-# This builds the basic UCI components currently supported for Unbound. It is
-# intentionally NOT comprehensive and bundles a lot of options. The UCI is to
-# be a simpler presentation of the total Unbound conf set.
+# Unbound is a full featured recursive server with many options. The UCI
+# provided tries to simplify and bundle options. This should make Unbound
+# easier to deploy. Even light duty routers may resolve recursively instead of
+# depending on a stub with the ISP. The UCI also attempts to replicate dnsmasq
+# features as used in base LEDE/OpenWrt. If there is a desire for more
+# detailed tuning, then manual conf file overrides are also made available.
 #
 ##############################################################################
 
@@ -36,6 +39,7 @@ UNBOUND_B_QRY_MINST=0
 
 UNBOUND_D_DOMAIN_TYPE=static
 UNBOUND_D_DHCP_LINK=none
+UNBOUND_D_EXTRA_DNS=0
 UNBOUND_D_LAN_FQDN=0
 UNBOUND_D_PROTOCOL=mixed
 UNBOUND_D_RESOURCE=small
@@ -57,6 +61,11 @@ UNBOUND_TXT_HOSTNAME=thisrouter
 
 ##############################################################################
 
+# keep track of local-domain: assignments during inserted resource records
+UNBOUND_LIST_DOMAINS=""
+
+##############################################################################
+
 UNBOUND_LIBDIR=/usr/lib/unbound
 UNBOUND_VARDIR=/var/lib/unbound
 
@@ -69,7 +78,7 @@ UNBOUND_CONFFILE=$UNBOUND_VARDIR/unbound.conf
 
 UNBOUND_KEYFILE=$UNBOUND_VARDIR/root.key
 UNBOUND_HINTFILE=$UNBOUND_VARDIR/root.hints
-UNBOUND_TIMEFILE=$UNBOUND_VARDIR/unbound.time
+UNBOUND_TIMEFILE=$UNBOUND_VARDIR/hotplug.time
 
 ##############################################################################
 
@@ -124,8 +133,8 @@ create_interface_dns() {
 
   ifdashname="${ifname//./-}"
   ipcommand="ip -o address show $ifname"
-  addresses="$($ipcommand | awk '/inet/{sub(/\/.*/,"",$4); print $4}')"
-  ulaprefix="$(uci_get network @globals[0] ula_prefix)"
+  addresses=$( $ipcommand | awk '/inet/{sub(/\/.*/,"",$4); print $4}' )
+  ulaprefix=$( uci_get network.@globals[0].ula_prefix )
   host_fqdn="$UNBOUND_TXT_HOSTNAME.$UNBOUND_TXT_DOMAIN"
   if_fqdn="$ifdashname.$host_fqdn"
 
@@ -223,6 +232,135 @@ create_interface_dns() {
 
 ##############################################################################
 
+create_local_zone() {
+  local target="$1"
+  local partial domain found
+
+
+  if [ -n "$UNBOUND_LIST_DOMAINS" ] ; then
+    for domain in $UNBOUND_LIST_DOMAINS ; do
+      case $target in
+      *"${domain}")
+        found=1
+        break
+        ;;
+
+      [A-Za-z0-9]*.[A-Za-z0-9]*)
+        found=0
+        ;;
+
+      *) # no dots
+        found=1
+        break
+        ;;
+      esac
+    done
+  else
+    found=0
+  fi
+
+
+  if [ $found -eq 0 ] ; then
+    # New Zone! Bundle local-zones: by first two name tiers "abcd.tld."
+    partial=$( echo "$target" | awk -F. '{ j=NF ; i=j-1; print $i"."$j }' )
+    UNBOUND_LIST_DOMAINS="$UNBOUND_LIST_DOMAINS $partial"
+    echo "  local-zone: $partial. transparent" >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+create_host_record() {
+  local cfg="$1"
+  local ip name
+
+  # basefiles dhcp "domain" clause which means host A, AAAA, and PRT record
+  config_get ip   "$cfg" ip
+  config_get name "$cfg" name
+
+
+  if [ -n "$name" -a -n "$ip" ] ; then
+    create_local_zone "$name"
+
+    {
+      case $ip in
+      fe80:*|169.254.*)
+        echo "  # note link address $ip for host $name"
+        ;;
+
+      [1-9a-f]*:*[0-9a-f])
+        echo "  local-data: \"$name. 120 IN AAAA $ip\""
+        echo "  local-data-ptr: \"$ip 120 $name\""
+        ;;
+
+      [1-9]*.*[0-9])
+        echo "  local-data: \"$name. 120 IN A $ip\""
+        echo "  local-data-ptr: \"$ip 120 $name\""
+        ;;
+      esac
+    } >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+create_mx_record() {
+  local cfg="$1"
+  local domain relay pref
+
+  # Insert a static MX record
+  config_get domain "$cfg" domain
+  config_get relay  "$cfg" relay
+  config_get pref   "$cfg" pref 10
+
+
+  if [ -n "$domain" -a -n "$relay" ] ; then
+    create_local_zone "$domain"
+    echo "  local-data: \"$domain. 120 IN MX $pref $relay.\"" \
+          >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+create_srv_record() {
+  local cfg="$1"
+  local srv target port class weight
+
+  # Insert a static SRV record such as SIP server
+  config_get srv    "$cfg" srv
+  config_get target "$cfg" target
+  config_get port   "$cfg" port
+  config_get class  "$cfg" class 10
+  config_get weight "$cfg" weight 10
+
+
+  if [ -n "$srv" -a -n "$target" -a -n "$port" ] ; then
+    create_local_zone "$srv"
+    echo "  local-data: \"$srv. 120 IN SRV $class $weight $port $target.\"" \
+          >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+create_cname_record() {
+  local cfg="$1"
+  local cname target
+
+  # Insert static CNAME record
+  config_get cname  "$cfg" cname
+  config_get target "$cfg" target
+
+
+  if [ -n "$cname" -a -n "$target" ] ; then
+    create_local_zone "$cname"
+    echo "  local-data: \"$cname. 120 IN CNAME $target.\"" >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
 create_access_control() {
   local cfg="$1"
   local subnets subnets4 subnets6
@@ -257,8 +395,8 @@ create_domain_insecure() {
 
 unbound_mkdir() {
   local resolvsym=0
-  local dhcp_origin=$( uci get dhcp.@odhcpd[0].leasefile )
-  local dhcp_dir=$( dirname "$dhcp_origin" )
+  local dhcp_origin=$( uci_get dhcp.@odhcpd[0].leasefile )
+  local dhcp_dir=$( dirname $dhcp_origin )
   local filestuff
 
 
@@ -780,11 +918,35 @@ unbound_hostname() {
 
 ##############################################################################
 
+unbound_records() {
+  if [ "$UNBOUND_D_EXTRA_DNS" -gt 0 ] ; then
+    # Parasite from the uci.dhcp.domain clauses
+    config_load dhcp
+    config_foreach create_host_record domain
+  fi
+
+
+  if [ "$UNBOUND_D_EXTRA_DNS" -gt 1 ] ; then
+    config_foreach create_srv_record srvhost
+    config_foreach create_mx_record mxhost
+  fi
+
+
+  if [ "$UNBOUND_D_EXTRA_DNS" -gt 2 ] ; then
+    config_foreach create_cname_record cname
+  fi
+
+
+  echo >> $UNBOUND_CONFFILE
+}
+
+##############################################################################
+
 unbound_uci() {
   local cfg="$1"
   local dnsmasqpath hostnm
 
-  hostnm="$(uci_get system.@system[0].hostname | awk '{print tolower($0)}')"
+  hostnm=$( uci_get system.@system[0].hostname | awk '{print tolower($0)}' )
   UNBOUND_TXT_HOSTNAME=${hostnm:-thisrouter}
 
   config_get_bool UNBOUND_B_SLAAC6_MAC "$cfg" dhcp4_slaac6 0
@@ -808,6 +970,7 @@ unbound_uci() {
 
   config_get UNBOUND_D_DOMAIN_TYPE "$cfg" domain_type static
   config_get UNBOUND_D_DHCP_LINK   "$cfg" dhcp_link none
+  config_get UNBOUND_D_EXTRA_DNS   "$cfg" add_extra_dns 0
   config_get UNBOUND_D_LAN_FQDN    "$cfg" add_local_fqdn 0
   config_get UNBOUND_D_PROTOCOL    "$cfg" protocol mixed
   config_get UNBOUND_D_RECURSION   "$cfg" recursion passive
@@ -817,6 +980,7 @@ unbound_uci() {
   config_get UNBOUND_TTL_MIN     "$cfg" ttl_min 120
   config_get UNBOUND_TXT_DOMAIN  "$cfg" domain lan
 
+  UNBOUND_LIST_DOMAINS="nowhere $UNBOUND_TXT_DOMAIN"
 
   if [ "$UNBOUND_D_DHCP_LINK" = "none" ] ; then
     config_get_bool UNBOUND_B_DNSMASQ   "$cfg" dnsmasq_link_dns 0
@@ -824,8 +988,8 @@ unbound_uci() {
 
     if [ "$UNBOUND_B_DNSMASQ" -gt 0 ] ; then
       UNBOUND_D_DHCP_LINK=dnsmasq
-      
-      
+
+
       if [ ! -f "$UNBOUND_TIMEFILE" ] ; then
         logger -t unbound -s "Please use 'dhcp_link' selector instead"
       fi
@@ -898,6 +1062,7 @@ unbound_start() {
       dnsmasq_link
     else
       unbound_hostname
+      unbound_records
     fi
 
     unbound_control
index 9e58ac799bb69c72f17f61d97b828a89057ceea2..45022f4080037853934868c1f03ce25c24a95ee5 100644 (file)
@@ -1,4 +1,5 @@
 config unbound
+       option add_extra_dns '0'
        option add_local_fqdn '1'
        option add_wan_fqdn '0'
        option dhcp_link 'none'
@@ -24,5 +25,7 @@ config unbound
        option unbound_control '0'
        option validator '0'
        option validator_ntp '1'
-       #list domain_insecure ''
+       list trigger 'lan'
+       list trigger 'wan'
+       #list domain_insecure 'www.example.com'
 
git clone https://git.99rst.org/PROJECT