Unbound: Update scripts to build conf file from UCI 3440/head
authorEric Luehrsen <ericluehrsen@hotmail.com>
Fri, 28 Oct 2016 02:04:00 +0000 (22:04 -0400)
committerEric Luehrsen <ericluehrsen@hotmail.com>
Wed, 30 Nov 2016 01:49:46 +0000 (20:49 -0500)
-unbound.sh implements the majority of requirements in README.md
-rootzone.sh reloads a small subset for alternate trigger maintenance
-unbound.init sets procd triggers on Unbound and dnsmasq (dhcp) UCI
-two part commit squashed with Makefile included

Signed-off-by: Eric Luehrsen <ericluehrsen@hotmail.com>
net/unbound/Makefile
net/unbound/files/rootzone.sh
net/unbound/files/unbound.init
net/unbound/files/unbound.sh

index 62367f758fb70ec4aa0fa3e0770fe785097614bd..eb82db766fe82575bcb434b5d7bc25416a5da22f 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=unbound
 PKG_VERSION:=1.5.10
-PKG_RELEASE:=3
+PKG_RELEASE:=4
 
 PKG_LICENSE:=BSD-3-Clause
 PKG_LICENSE_FILES:=LICENSE
@@ -120,6 +120,7 @@ CONFIGURE_ARGS += \
        --with-user=unbound
 
 define Package/unbound/conffiles
+/etc/config/unbound
 /etc/unbound/unbound.conf
 endef
 
@@ -141,13 +142,19 @@ define Package/unbound/install
                $(PKG_INSTALL_DIR)/etc/unbound/unbound.conf \
                $(1)/etc/unbound/unbound.conf
        $(INSTALL_DATA) ./files/root.key $(1)/etc/unbound/root.key
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_DATA) ./files/unbound.uci $(1)/etc/config/unbound
        $(INSTALL_DIR) $(1)/etc/hotplug.d/iface
        $(INSTALL_BIN) ./files/unbound.iface $(1)/etc/hotplug.d/iface/25-unbound
+       $(INSTALL_DIR) $(1)/etc/hotplug.d/ntp
+       $(INSTALL_BIN) ./files/unbound.ntpd $(1)/etc/hotplug.d/ntp/25-unbound
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/unbound.init $(1)/etc/init.d/unbound
        $(INSTALL_DIR) $(1)/usr/lib/unbound
-       $(INSTALL_DATA) ./files/unbound.sh $(1)/usr/lib/unbound/unbound.sh
+       $(INSTALL_DATA) ./files/dnsmasq.sh $(1)/usr/lib/unbound/dnsmasq.sh
+       $(INSTALL_DATA) ./files/iptools.sh $(1)/usr/lib/unbound/iptools.sh
        $(INSTALL_DATA) ./files/rootzone.sh $(1)/usr/lib/unbound/rootzone.sh
+       $(INSTALL_DATA) ./files/unbound.sh $(1)/usr/lib/unbound/unbound.sh
 endef
 
 define Package/unbound-anchor/install
index fe71f3ef2d61d15d2cbdefd08c58a9de832ec2eb..143c0560f65715cf5e5f786e9b8752ce807613a9 100644 (file)
@@ -7,9 +7,9 @@
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
-# 
+#
 # Copyright (C) 2016 Eric Luehrsen
 #
 ##############################################################################
 ##############################################################################
 
 rootzone_uci() {
-  # TODO: Just structure to real UCI coming soon.
-  echo
+  local cfg=$1
+
+  # This will likely be called outside of "start_service()" context
+  config_get_bool UNBOUND_B_DNSSEC "$cfg" validator 0
+  config_get_bool UNBOUND_B_NTP_BOOT "$cfg" validator_ntp 1
+  config_get UNBOUND_N_ROOT_AGE "$cfg" root_age 30
 }
 
 ##############################################################################
 
 roothints_update() {
-  # TODO: Maybe this will not be implemented.
-  echo
+  # TODO: Might not be implemented. Unbound doesn't natively update hints.
+  # Unbound philosophy is built in root hints are good for machine life.
+  return 0
 }
 
 ##############################################################################
@@ -37,34 +42,38 @@ roothints_update() {
 rootkey_update() {
   local basekey_date rootkey_date rootkey_age filestuff
 
-  # TODO: Just structure to real UCI coming soon.
+
   if [ "$UNBOUND_N_ROOT_AGE" -gt 90 -o "$UNBOUND_B_DNSSEC" -lt 1 ] ; then
     # Feature disabled
     return 0
+
+  elif [ "$UNBOUND_B_NTP_BOOT" -gt 0 -a ! -f "$UNBOUND_TIMEFILE" ] ; then
+    # We don't have time yet
+    return 0
   fi
-   
-  
+
+
   if [ -f /etc/unbound/root.key ] ; then
     basekey_date=$( date -r /etc/unbound/root.key +%s )
-    
+
   else
     # No persistent storage key
     basekey_date=$( date -d 2000-01-01 +%s )
   fi
-  
-  
+
+
   if [ -f "$UNBOUND_KEYFILE" ] ; then
     # Unbound maintains it itself
     rootkey_date=$( date -r $UNBOUND_KEYFILE +%s )
     rootkey_age=$(( (rootkey_date - basekey_date) / 86440 ))
-    
+
   elif [ -x "$UNBOUND_ANCHOR" ] ; then
     # No tmpfs key - use unbound-anchor
     rootkey_date=$( date -I +%s )
-    rootkey_age=$(( (rootkey_date - basekey_date) / 86440 )) 
+    rootkey_age=$(( (rootkey_date - basekey_date) / 86440 ))
     $UNBOUND_ANCHOR -a $UNBOUND_KEYFILE
-    
-  else 
+
+  else
     # give up
     rootkey_age=0
   fi
@@ -72,23 +81,23 @@ rootkey_update() {
 
   if [ "$rootkey_age" -gt "$UNBOUND_N_ROOT_AGE" ] ; then
     filestuff=$( cat $UNBOUND_KEYFILE )
-    
-      
+
+
     case "$filestuff" in
       *NOERROR*)
         # Header comment for drill and dig
         logger -t unbound -s "root.key updated after $rootkey_age days"
         cp -p $UNBOUND_KEYFILE /etc/unbound/root.key
         ;;
-        
+
       *"state=2 [  VALID  ]"*)
         # Comment inline to key for unbound-anchor
         logger -t unbound -s "root.key updated after $rootkey_age days"
         cp -p $UNBOUND_KEYFILE /etc/unbound/root.key
         ;;
-        
-      *) 
-        logger -t unbound -s "root.key still $rootkey_age days old" 
+
+      *)
+        logger -t unbound -s "root.key still $rootkey_age days old"
         ;;
     esac
   fi
@@ -97,7 +106,11 @@ rootkey_update() {
 ##############################################################################
 
 rootzone_update() {
-  rootzone_uci
+  # Partial UCI fetch for this functional group
+  config_load unbound
+  config_foreach rootzone_uci unbound
+
+  # You need root.hints and root.key to boot strap recursion
   roothints_update
   rootkey_update
 }
index 119289449a0c3c54ffe208dd1bd0f0f09b5e7c10..0f5049d0c51d27aaa3439acfb1599580404abf36 100755 (executable)
@@ -36,3 +36,11 @@ stop_service() {
 
 ##############################################################################
 
+service_triggers() {
+  procd_add_reload_trigger "dhcp"
+  procd_add_reload_trigger "network"
+  procd_add_reload_trigger "unbound"
+}
+
+##############################################################################
+
index 245bd18b265862a247a3a0390075f59666c333d9..83121029808a82a34584ac4952b19011447ac1e8 100644 (file)
@@ -7,22 +7,41 @@
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
-# 
+#
 # Copyright (C) 2016 Eric Luehrsen
 #
 ##############################################################################
 #
-# TODO: This file will build the UCI for Unbound. This iteration only puts
-# our default unbound configuration and root.key into /var/lib/unbound.
+# 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.
 #
 ##############################################################################
 
-# TODO: Just default definitions versus real UCI coming soon.
-UNBOUND_B_MAN_CONF=1
-UNBOUND_B_DNSSEC=1
-UNBOUND_N_ROOT_AGE=7
+UNBOUND_B_CONTROL=0
+UNBOUND_B_DNSMASQ=0
+UNBOUND_B_DNSSEC=0
+UNBOUND_B_GATE_NAME=0
+UNBOUND_B_LOCL_BLCK=0
+UNBOUND_B_LOCL_NAME=0
+UNBOUND_B_LOCL_SERV=1
+UNBOUND_B_MAN_CONF=0
+UNBOUND_B_NTP_BOOT=1
+UNBOUND_B_PRIV_BLCK=1
+UNBOUND_B_QUERY_MIN=0
+
+UNBOUND_D_RESOURCE=small
+UNBOUND_D_RECURSION=passive
+
+UNBOUND_TXT_FWD_ZONE=""
+UNBOUND_TTL_MIN=120
+
+UNBOUND_N_EDNS_SIZE=1280
+UNBOUND_N_FWD_PORTS=""
+UNBOUND_N_RX_PORT=53
+UNBOUND_N_ROOT_AGE=28
 
 ##############################################################################
 
@@ -37,6 +56,7 @@ UNBOUND_VARDIR=/var/lib/unbound
 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_CHECKFILE=$UNBOUND_VARDIR/unbound.check
 
 ##############################################################################
@@ -44,38 +64,72 @@ UNBOUND_CHECKFILE=$UNBOUND_VARDIR/unbound.check
 . /lib/functions.sh
 . /lib/functions/network.sh
 
+. $UNBOUND_LIBDIR/dnsmasq.sh
+. $UNBOUND_LIBDIR/iptools.sh
 . $UNBOUND_LIBDIR/rootzone.sh
 
 ##############################################################################
 
+create_access_control() {
+  local cfg="$1"
+  local subnets subnets4 subnets6
+  local validip4 validip6
+
+  network_get_subnets  subnets4 "$cfg"
+  network_get_subnets6 subnets6 "$cfg"
+  subnets="$subnets4 $subnets6"
+
+
+  if [ -n "$subnets" ] ; then
+    for subnet in $subnets ; do
+      validip4=$( valid_subnet4 $subnet )
+      validip6=$( valid_subnet6 $subnet )
+
+
+      if [ "$validip4" = "ok" -o "$validip6" = "ok" ] ; then
+        # For each "network" UCI add "access-control:" white list for queries
+        echo "  access-control: $subnet allow" >> $UNBOUND_CONFFILE
+      fi
+    done
+  fi
+}
+
+##############################################################################
+
+create_domain_insecure() {
+  echo "  domain-insecure: \"$1\"" >> $UNBOUND_CONFFILE
+}
+
+##############################################################################
+
 unbound_mkdir() {
   mkdir -p $UNBOUND_VARDIR
-  
-  
+
+
   if [ -f /etc/unbound/root.hints ] ; then
     # Your own local copy of root.hints
     cp -p /etc/unbound/root.hints $UNBOUND_HINTFILE
-    
+
   elif [ -f /usr/share/dns/root.hints ] ; then
     # Debian-like package dns-root-data
     cp -p /usr/share/dns/root.hints $UNBOUND_HINTFILE
-    
+
   else
     logger -t unbound -s "iterator will use built-in root hints"
   fi
-  
-  
+
+
   if [ -f /etc/unbound/root.key ] ; then
     # Your own local copy of a root.key
     cp -p /etc/unbound/root.key $UNBOUND_KEYFILE
-      
+
   elif [ -f /usr/share/dns/root.key ] ; then
     # Debian-like package dns-root-data
     cp -p /usr/share/dns/root.key $UNBOUND_KEYFILE
-      
-  elif [ -x "$UNBOUND_ANCHOR" ] ; then 
+
+  elif [ -x "$UNBOUND_ANCHOR" ] ; then
     $UNBOUND_ANCHOR -a $UNBOUND_KEYFILE
-        
+
   else
     logger -t unbound -s "validator will use built-in trust anchor"
   fi
@@ -84,30 +138,379 @@ unbound_mkdir() {
 ##############################################################################
 
 unbound_conf() {
-  # TODO: Just structure to real UCI coming soon.
-  if [ "$UNBOUND_B_MAN_CONF" -gt 0 -a -f /etc/unbound/unbound.conf ] ; then
-    # You don't want UCI and use your own manual configuration
-    cp -p /etc/unbound/unbound.conf $UNBOUND_CONFFILE
+  local cfg=$1
+  local rt_mem rt_conn
+
+  {
+    # Make fresh conf file
+    echo "# $UNBOUND_CONFFILE generated by UCI $( date )"
+    echo
+  } > $UNBOUND_CONFFILE
+
+
+  if [ "$UNBOUND_B_CONTROL" -gt 0 ] ; then
+    {
+      # Enable remote control tool, but only at local host for security
+      echo "remote-control:"
+      echo "  control-enable: yes"
+      echo "  control-use-cert: no"
+      echo "  control-interface: 127.0.0.1"
+      echo "  control-interface: ::1"
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    {
+      # "control:" clause is seperate before "server:" so we can append
+      # dnsmasq "server:" parts and "forward:" cluases towards the end.
+      echo "remote-control:"
+      echo "  control-enable: no"
+      echo
+    } >> $UNBOUND_CONFFILE
+  fi
+
+
+  {
+    # No threading
+    echo "server:"
+    echo "  username: unbound"
+    echo "  num-threads: 1"
+    echo "  msg-cache-slabs: 1"
+    echo "  rrset-cache-slabs: 1"
+    echo "  infra-cache-slabs: 1"
+    echo "  key-cache-slabs: 1"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  {
+    # Logging
+    echo "  verbosity: 1"
+    echo "  statistics-interval: 0"
+    echo "  statistics-cumulative: no"
+    echo "  extended-statistics: no"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  {
+    # Interfaces (access contol "option local_service")
+    echo "  interface: 0.0.0.0"
+    echo "  interface: ::0"
+    echo "  outgoing-interface: 0.0.0.0"
+    echo "  outgoing-interface: ::0"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  {
+    # protocol level tuning
+    echo "  edns-buffer-size: $UNBOUND_N_EDNS_SIZE"
+    echo "  msg-buffer-size: 8192"
+    echo "  port: $UNBOUND_N_RX_PORT"
+    echo "  outgoing-port-permit: 10240-65535"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  {
+    # Other harding and options for an embedded router
+    echo "  harden-short-bufsize: yes"
+    echo "  harden-large-queries: yes"
+    echo "  harden-glue: yes"
+    echo "  harden-below-nxdomain: no"
+    echo "  harden-referral-path: no"
+    echo "  use-caps-for-id: no"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  {
+    # Default Files
+    echo "  use-syslog: yes"
+    echo "  chroot: \"$UNBOUND_VARDIR\""
+    echo "  directory: \"$UNBOUND_VARDIR\""
+    echo "  pidfile: \"$UNBOUND_PIDFILE\""
+  } >> $UNBOUND_CONFFILE
+
+
+  if [ -f "$UNBOUND_HINTFILE" ] ; then
+    # Optional hints if found
+    echo "  root-hints: \"$UNBOUND_HINTFILE\"" >> $UNBOUND_CONFFILE
+  fi
+
+
+  if [ "$UNBOUND_B_DNSSEC" -gt 0 -a -f "$UNBOUND_KEYFILE" ] ; then
+    {
+      echo "  auto-trust-anchor-file: \"$UNBOUND_KEYFILE\""
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    echo >> $UNBOUND_CONFFILE
+  fi
+
+
+  case "$UNBOUND_D_RESOURCE" in
+    # Tiny - Unbound's recommended cheap hardware config
+    tiny)   rt_mem=1  ; rt_conn=1 ;;
+    # Small - Half RRCACHE and open ports
+    small)  rt_mem=8  ; rt_conn=5 ;;
+    # Medium - Nearly default but with some added balancintg
+    medium) rt_mem=16 ; rt_conn=10 ;;
+    # Large - Double medium
+    large)  rt_mem=32 ; rt_conn=10 ;;
+    # Whatever unbound does
+    *) rt_mem=0 ; rt_conn=0 ;;
+  esac
+
+
+  if [ "$rt_mem" -gt 0 ] ; then
+    {
+      # Set memory sizing parameters
+      echo "  outgoing-range: $(($rt_conn*64))"
+      echo "  num-queries-per-thread: $(($rt_conn*32))"
+      echo "  outgoing-num-tcp: $(($rt_conn))"
+      echo "  incoming-num-tcp: $(($rt_conn))"
+      echo "  rrset-cache-size: $(($rt_mem*256))k"
+      echo "  msg-cache-size: $(($rt_mem*128))k"
+      echo "  key-cache-size: $(($rt_mem*128))k"
+      echo "  neg-cache-size: $(($rt_mem*64))k"
+      echo "  infra-cache-numhosts: $(($rt_mem*256))"
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    logger -t unbound -s "default memory resource consumption"
+  fi
+
+
+  if [ "$UNBOUND_B_DNSSEC" -gt 0 ] ; then
+    if [ ! -f "$UNBOUND_TIMEFILE" -a "$UNBOUND_B_NTP_BOOT" -gt 0 ] ; then
+      # DNSSEC chicken and egg with getting NTP time
+      echo "  val-override-date: -1" >> $UNBOUND_CONFFILE
+    fi
+
+
+    {
+      # Validation of DNSSEC
+      echo "  module-config: \"validator iterator\""
+      echo "  harden-dnssec-stripped: yes"
+      echo "  val-clean-additional: yes"
+      echo "  ignore-cd-flag: yes"
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    {
+      # Just iteration without DNSSEC
+      echo "  module-config: \"iterator\""
+      echo
+    } >> $UNBOUND_CONFFILE
+  fi
+
+
+  if [ "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then
+    # Minor improvement on query privacy
+    echo "  qname-minimisation: yes" >> $UNBOUND_CONFFILE
+
+  else
+    echo "  qname-minimisation: no" >> $UNBOUND_CONFFILE
+  fi
+
+
+  case "$UNBOUND_D_RECURSION" in
+    passive)
+      {
+        echo "  prefetch: no"
+        echo "  prefetch-key: no"
+        echo "  target-fetch-policy: \"0 0 0 0 0\""
+        echo
+      } >> $UNBOUND_CONFFILE
+      ;;
+
+    aggressive)
+      {
+        echo "  prefetch: yes"
+        echo "  prefetch-key: yes"
+        echo "  target-fetch-policy: \"3 2 1 0 0\""
+        echo
+      } >> $UNBOUND_CONFFILE
+      ;;
+
+    *)
+      logger -t unbound -s "default recursion configuration"
+      ;;
+  esac
+
+
+  {
+    # Reload records more than 10 hours old
+    # DNSSEC 5 minute bogus cool down before retry
+    # Adaptive infrastructure info kept for 15 minutes
+    echo "  cache-min-ttl: $UNBOUND_TTL_MIN"
+    echo "  cache-max-ttl: 36000"
+    echo "  val-bogus-ttl: 300"
+    echo "  infra-host-ttl: 900"
+    echo
+  } >> $UNBOUND_CONFFILE
+
+
+  if [ "$UNBOUND_B_PRIV_BLCK" -gt 0 ] ; then
+    {
+      # Remove DNS reponses from upstream with private IP
+      echo "  private-address: 10.0.0.0/8"
+      echo "  private-address: 169.254.0.0/16"
+      echo "  private-address: 172.16.0.0/12"
+      echo "  private-address: 192.168.0.0/16"
+      echo "  private-address: fc00::/8"
+      echo "  private-address: fd00::/8"
+      echo "  private-address: fe80::/10"
+    } >> $UNBOUND_CONFFILE
+  fi
+
+
+  if [ "$UNBOUND_B_LOCL_BLCK" -gt 0 ] ; then
+    {
+      # Remove DNS reponses from upstream with loopback IP
+      # Black hole DNS method for ad blocking, so consider...
+      echo "  private-address: 127.0.0.0/8"
+      echo "  private-address: ::1/128"
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    echo >> $UNBOUND_CONFFILE
+  fi
+
+
+  # Domain Exceptions
+  config_list_foreach "$cfg" "domain_insecure" create_domain_insecure
+  echo >> $UNBOUND_CONFFILE
+
+
+  ####################
+  # UCI @ network    #
+  ####################
+
+
+  if [ "$UNBOUND_B_LOCL_SERV" -gt 0 ] ; then
+    # Only respond to queries from which this device has an interface.
+    # Prevent DNS amplification attacks by not responding to the universe.
+    config_load network
+    config_foreach create_access_control interface
+
+    {
+      echo "  access-control: 127.0.0.0/8 allow"
+      echo "  access-control: ::1/128 allow"
+      echo "  access-control: fe80::/10 allow"
+      echo
+    } >> $UNBOUND_CONFFILE
+
+  else
+    {
+      echo "  access-control: 0.0.0.0/0 allow"
+      echo "  access-control: ::0/0 allow"
+      echo
+    } >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+unbound_uci() {
+  local cfg=$1
+  local dnsmasqpath
+
+  ####################
+  # UCI @ unbound    #
+  ####################
+
+  config_get_bool UNBOUND_B_GATE_NAME "$cfg" dnsmsaq_gate_name 0
+  config_get_bool UNBOUND_B_DNSMASQ   "$cfg" dnsmasq_link_dns 0
+  config_get_bool UNBOUND_B_LOCL_NAME "$cfg" dnsmasq_only_local 0
+  config_get_bool UNBOUND_B_LOCL_SERV "$cfg" localservice 1
+  config_get_bool UNBOUND_B_MAN_CONF  "$cfg" manual_conf 0
+  config_get_bool UNBOUND_B_QUERY_MIN "$cfg" query_minimize 0
+  config_get_bool UNBOUND_B_PRIV_BLCK "$cfg" rebind_protection 1
+  config_get_bool UNBOUND_B_LOCL_BLCK "$cfg" rebind_localhost 0
+  config_get_bool UNBOUND_B_CONTROL   "$cfg" unbound_control 0
+  config_get_bool UNBOUND_B_DNSSEC    "$cfg" validator  0
+  config_get_bool UNBOUND_B_NTP_BOOT  "$cfg" validator_ntp 1
+
+  config_get UNBOUND_N_EDNS_SIZE "$cfg" edns_size 1280
+  config_get UNBOUND_N_RX_PORT   "$cfg" listen_port 53
+  config_get UNBOUND_D_RECURSION "$cfg" recursion passive
+  config_get UNBOUND_D_RESOURCE  "$cfg" resource small
+  config_get UNBOUND_N_ROOT_AGE  "$cfg" root_age 7
+  config_get UNBOUND_TTL_MIN     "$cfg" ttl_min 120
+
+
+  if [ "$UNBOUND_B_DNSMASQ" -gt 0 ] ; then
+    dnsmasqpath=$( which dnsmasq )
+
+
+    if [ ! -x "$dnsmasqpath" ] ; then
+      logger -t unbound -s "cannot forward to dnsmasq"
+      UNBOUND_B_DNSMASQ=0
+    fi
+  fi
+
+
+  if [ "$UNBOUND_N_EDNS_SIZE" -lt 512 \
+    -o 4096 -lt "$UNBOUND_N_EDNS_SIZE" ] ; then
+    # exceeds range, back to default
+    UNBOUND_N_EDNS_SIZE=1280
+  fi
+
+
+  if [ "$UNBOUND_N_RX_PORT" -lt 1024 \
+    -o 10240 -lt "$UNBOUND_N_RX_PORT" ] ; then
+    # special port or in 5 digits, back to default
+    UNBOUND_N_RX_PORT=53
+  fi
+
+
+  if [ "$UNBOUND_TTL_MIN" -gt 1800 ] ; then
+    # that could have had awful side effects
+    UNBOUND_TTL_MIN=300
+  fi
+
+
+  if [ "$UNBOUND_B_MAN_CONF" -gt 0 ] ; then
+    if [ -f /etc/unbound/unbound.conf ] ; then
+      # You don't want UCI and use your own manual configuration
+      # or with no base file whatever Unbound defaults are.
+      cp -p /etc/unbound/unbound.conf $UNBOUND_CONFFILE
+    fi
+
+
+    # Don't want this being triggered. Maybe we could, but then the
+    # base conf you provide would need to be just right.
+    UNBOUND_B_DNSMASQ=0
+
+  else
+    unbound_conf $cfg
   fi
 }
 
 ##############################################################################
 
-unbound_own() {
+unbound_own () {
   # Debug UCI
   {
     echo "# $UNBOUND_CHECKFILE generated by UCI $( date )"
     echo
     set | grep ^UNBOUND_
   } > $UNBOUND_CHECKFILE
-    
-  
+
+
   if [ ! -f "$UNBOUND_CONFFILE" ] ; then
     # if somehow this happened
     touch $UNBOUND_CONFFILE
   fi
-  
-  
+
+
   # Ensure Access
   chown -R unbound:unbound $UNBOUND_VARDIR
   chmod 775 $UNBOUND_VARDIR
@@ -117,8 +520,17 @@ unbound_own() {
 ##############################################################################
 
 unbound_prepare() {
+  # Make a home for Unbound in /var/lib/unbound
   unbound_mkdir
-  unbound_conf
+
+  # Load up the chunks of UCI
+  config_load unbound
+  config_foreach unbound_uci unbound
+
+  # Unbound primary DNS, and dnsmasq side service DHCP-DNS (dnsmasq.sh)
+  dnsmasq_link
+
+  # Unbound needs chroot ownership
   unbound_own
 }