```
### 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.
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'
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.
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.
```
#
##############################################################################
#
-# 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.
#
##############################################################################
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
##############################################################################
+# keep track of local-domain: assignments during inserted resource records
+UNBOUND_LIST_DOMAINS=""
+
+##############################################################################
+
UNBOUND_LIBDIR=/usr/lib/unbound
UNBOUND_VARDIR=/var/lib/unbound
UNBOUND_KEYFILE=$UNBOUND_VARDIR/root.key
UNBOUND_HINTFILE=$UNBOUND_VARDIR/root.hints
-UNBOUND_TIMEFILE=$UNBOUND_VARDIR/unbound.time
+UNBOUND_TIMEFILE=$UNBOUND_VARDIR/hotplug.time
##############################################################################
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"
##############################################################################
+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
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
##############################################################################
+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
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
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
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
dnsmasq_link
else
unbound_hostname
+ unbound_records
fi
unbound_control