packages/net/unbound/files/unbound.sh
Eric Luehrsen 8e0b2d344e unbound: refactor build options to select switches
The two unique packages "Unbound light" and "Unbound heavy"
were not working well due to the fact that Unbound is mostly
its library. Tools and helpers would crash. Instead a reasonable
default Unbound is built. Also up select options like python
are added. libevent and libpthreads are options to down select.

Signed-off-by: Eric Luehrsen <ericluehrsen@gmail.com>
2020-06-27 17:17:41 -04:00

1482 lines
41 KiB
Bash

#!/bin/sh
##############################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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
# GNU General Public License for more details.
#
# Copyright (C) 2016 Eric Luehrsen
#
##############################################################################
#
# 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.
#
##############################################################################
UB_B_SLAAC6_MAC=0
UB_B_DNSSEC=0
UB_B_DNS64=0
UB_B_EXT_STATS=0
UB_B_GATE_NAME=0
UB_B_HIDE_BIND=1
UB_B_LOCL_BLCK=0
UB_B_LOCL_SERV=1
UB_B_MAN_CONF=0
UB_B_NTP_BOOT=1
UB_B_QUERY_MIN=0
UB_B_QRY_MINST=0
UB_B_AUTH_ROOT=0
UB_B_IF_AUTO=1
UB_D_CONTROL=0
UB_D_DOMAIN_TYPE=static
UB_D_DHCP_LINK=none
UB_D_EXTRA_DNS=0
UB_D_LAN_FQDN=0
UB_D_PRIV_BLCK=1
UB_D_PROTOCOL=mixed
UB_D_RESOURCE=small
UB_D_RECURSION=passive
UB_D_VERBOSE=1
UB_D_WAN_FQDN=0
UB_IP_DNS64="64:ff9b::/96"
UB_N_EDNS_SIZE=1280
UB_N_RX_PORT=53
UB_N_ROOT_AGE=9
UB_N_THREADS=1
UB_TTL_MIN=120
UB_TXT_DOMAIN=lan
UB_TXT_HOSTNAME=thisrouter
##############################################################################
# reset as a combo with UB_B_NTP_BOOT and some time stamp files
UB_B_READY=1
# keep track of assignments during inserted resource records
UB_LIST_NETW_ALL=""
UB_LIST_NETW_LAN=""
UB_LIST_NETW_WAN=""
UB_LIST_INSECURE=""
UB_LIST_ZONE_SERVERS=""
UB_LIST_ZONE_NAMES=""
##############################################################################
. /lib/functions.sh
. /lib/functions/network.sh
. /usr/lib/unbound/defaults.sh
. /usr/lib/unbound/dnsmasq.sh
. /usr/lib/unbound/iptools.sh
##############################################################################
bundle_all_networks() {
local cfg="$1"
local ifname ifdashname validip
local subnet subnets subnets4 subnets6
network_get_subnets subnets4 "$cfg"
network_get_subnets6 subnets6 "$cfg"
network_get_device ifname "$cfg"
ifdashname="${ifname//./-}"
subnets="$subnets4 $subnets6"
if [ -n "$subnets" ] ; then
for subnet in $subnets ; do
validip=$( valid_subnet_any $subnet )
if [ "$validip" = "ok" ] ; then
UB_LIST_NETW_ALL="$UB_LIST_NETW_ALL $ifdashname@$subnet"
fi
done
fi
}
##############################################################################
bundle_lan_networks() {
local cfg="$1"
local interface ifsubnet ifname ifdashname ignore
config_get_bool ignore "$cfg" ignore 0
config_get interface "$cfg" interface ""
network_get_device ifname "$interface"
ifdashname="${ifname//./-}"
if [ "$ignore" -eq 0 ] && [ -n "$ifdashname" ] \
&& [ -n "$UB_LIST_NETW_ALL" ] ; then
for ifsubnet in $UB_LIST_NETW_ALL ; do
case $ifsubnet in
"${ifdashname}"@*)
# Special GLA protection for local block; ULA protected default
UB_LIST_NETW_LAN="$UB_LIST_NETW_LAN $ifsubnet"
;;
esac
done
fi
}
##############################################################################
bundle_wan_networks() {
local ifsubnet
if [ -n "$UB_LIST_NETW_ALL" ] ; then
for ifsubnet in $UB_LIST_NETW_ALL ; do
case $UB_LIST_NETW_LAN in
*"${ifsubnet}"*)
# If LAN, then not WAN ...
;;
*)
UB_LIST_NETW_WAN="$UB_LIST_NETW_WAN $ifsubnet"
;;
esac
done
fi
}
##############################################################################
bundle_resolv_conf_servers() {
local resolvers=$( awk '/nameserver/ { print $2 }' /tmp/resolv.conf.auto )
UB_LIST_ZONE_SERVERS="$UB_LIST_ZONE_SERVERS $resolvers"
}
##############################################################################
bundle_zone_names() {
UB_LIST_ZONE_NAMES="$UB_LIST_ZONE_NAMES $1"
}
##############################################################################
bundle_zone_servers() {
UB_LIST_ZONE_SERVERS="$UB_LIST_ZONE_SERVERS $1"
}
##############################################################################
bundle_domain_insecure() {
UB_LIST_INSECURE="$UB_LIST_INSECURE $1"
}
##############################################################################
unbound_mkdir() {
local filestuff
if [ "$UB_D_DHCP_LINK" = "odhcpd" ] ; then
local dhcp_origin=$( uci_get dhcp.@odhcpd[0].leasefile )
local dhcp_dir=$( dirname $dhcp_origin )
if [ ! -d "$dhcp_dir" ] ; then
# make sure odhcpd has a directory to write (not done itself, yet)
mkdir -p "$dhcp_dir"
fi
fi
if [ -f $UB_RKEY_FILE ] ; then
filestuff=$( cat $UB_RKEY_FILE )
case "$filestuff" in
*"state=2 [ VALID ]"*)
# Lets not lose RFC 5011 tracking if we don't have to
cp -p $UB_RKEY_FILE $UB_RKEY_FILE.keep
;;
esac
fi
# Blind copy /etc/unbound to /var/lib/unbound
mkdir -p $UB_VARDIR
rm -f $UB_VARDIR/dhcp_*
touch $UB_TOTAL_CONF
cp -p /etc/unbound/* $UB_VARDIR/
if [ ! -f $UB_RHINT_FILE ] ; then
if [ -f /usr/share/dns/root.hints ] ; then
# Debian-like package dns-root-data
cp -p /usr/share/dns/root.hints $UB_RHINT_FILE
elif [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "default root hints (built in root-servers.net)"
fi
fi
if [ ! -f $UB_RKEY_FILE ] ; then
if [ -f /usr/share/dns/root.key ] ; then
# Debian-like package dns-root-data
cp -p /usr/share/dns/root.key $UB_RKEY_FILE
elif [ -x $UB_ANCHOR ] ; then
$UB_ANCHOR -a $UB_RKEY_FILE
elif [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "default trust anchor (built in root DS record)"
fi
fi
if [ -f $UB_RKEY_FILE.keep ] ; then
# root.key.keep is reused if newest
cp -u $UB_RKEY_FILE.keep $UB_RKEY_FILE
rm -f $UB_RKEY_FILE.keep
fi
if [ -f $UB_TLS_ETC_FILE ] ; then
# copy the cert bundle into jail
cp -p $UB_TLS_ETC_FILE $UB_TLS_FWD_FILE
fi
# Ensure access and prepare to jail
chown -R unbound:unbound $UB_VARDIR
chmod 755 $UB_VARDIR
chmod 644 $UB_VARDIR/*
if [ -f $UB_CTLKEY_FILE ] || [ -f $UB_CTLPEM_FILE ] \
|| [ -f $UB_SRVKEY_FILE ] || [ -f $UB_SRVPEM_FILE ] ; then
# Keys (some) exist already; do not create new ones
chmod 640 $UB_CTLKEY_FILE $UB_CTLPEM_FILE \
$UB_SRVKEY_FILE $UB_SRVPEM_FILE
elif [ -x /usr/sbin/unbound-control-setup ] ; then
case "$UB_D_CONTROL" in
[2-3])
# unbound-control-setup for encrypt opt. 2 and 3, but not 4 "static"
/usr/sbin/unbound-control-setup -d $UB_VARDIR
chown -R unbound:unbound $UB_CTLKEY_FILE $UB_CTLPEM_FILE \
$UB_SRVKEY_FILE $UB_SRVPEM_FILE
chmod 640 $UB_CTLKEY_FILE $UB_CTLPEM_FILE \
$UB_SRVKEY_FILE $UB_SRVPEM_FILE
cp -p $UB_CTLKEY_FILE /etc/unbound/unbound_control.key
cp -p $UB_CTLPEM_FILE /etc/unbound/unbound_control.pem
cp -p $UB_SRVKEY_FILE /etc/unbound/unbound_server.key
cp -p $UB_SRVPEM_FILE /etc/unbound/unbound_server.pem
;;
esac
fi
if [ -f "$UB_TIME_FILE" ] ; then
# NTP is done so its like you actually had an RTC
UB_B_READY=1
UB_B_NTP_BOOT=0
elif [ "$UB_B_NTP_BOOT" -eq 0 ] ; then
# time is considered okay on this device (ignore /etc/hotplug/ntpd/unbound)
date -Is > $UB_TIME_FILE
UB_B_READY=0
UB_B_NTP_BOOT=0
else
# DNSSEC-TIME will not reconcile
UB_B_READY=0
UB_B_NTP_BOOT=1
fi
}
##############################################################################
unbound_control() {
echo "# $UB_CTRL_CONF generated by UCI $( date -Is )" > $UB_CTRL_CONF
if [ "$UB_D_CONTROL" -gt 1 ] ; then
if [ ! -f $UB_CTLKEY_FILE ] || [ ! -f $UB_CTLPEM_FILE ] \
|| [ ! -f $UB_SRVKEY_FILE ] || [ ! -f $UB_SRVPEM_FILE ] ; then
# Key files need to be present; if unbound-control-setup was found, then
# they might have been made during unbound_makedir() above.
UB_D_CONTROL=0
fi
fi
case "$UB_D_CONTROL" in
1)
{
# Local Host Only Unencrypted Remote Control
echo "remote-control:"
echo " control-enable: yes"
echo " control-use-cert: no"
echo " control-interface: 127.0.0.1"
echo " control-interface: ::1"
echo
} >> $UB_CTRL_CONF
;;
2)
{
# Local Host Only Encrypted Remote Control
echo "remote-control:"
echo " control-enable: yes"
echo " control-use-cert: yes"
echo " control-interface: 127.0.0.1"
echo " control-interface: ::1"
echo " server-key-file: $UB_SRVKEY_FILE"
echo " server-cert-file: $UB_SRVPEM_FILE"
echo " control-key-file: $UB_CTLKEY_FILE"
echo " control-cert-file: $UB_CTLPEM_FILE"
echo
} >> $UB_CTRL_CONF
;;
[3-4])
{
# Network Encrypted Remote Control
# (3) may auto setup and (4) must have static key/pem files
# TODO: add UCI list for interfaces to bind
echo "remote-control:"
echo " control-enable: yes"
echo " control-use-cert: yes"
echo " control-interface: 0.0.0.0"
echo " control-interface: ::0"
echo " server-key-file: $UB_SRVKEY_FILE"
echo " server-cert-file: $UB_SRVPEM_FILE"
echo " control-key-file: $UB_CTLKEY_FILE"
echo " control-cert-file: $UB_CTLPEM_FILE"
echo
} >> $UB_CTRL_CONF
;;
esac
}
##############################################################################
unbound_zone() {
local cfg=$1
local servers_ip=""
local servers_host=""
local zone_sym zone_name zone_type zone_enabled zone_file
local tls_upstream fallback
local server port tls_port tls_index tls_suffix url_dir
if [ ! -f "$UB_ZONE_CONF" ] ; then
echo "# $UB_ZONE_CONF generated by UCI $( date -Is )" > $UB_ZONE_CONF
fi
config_get_bool zone_enabled "$cfg" enabled 0
if [ "$zone_enabled" -eq 1 ] ; then
# these lists are built for each zone; empty to start
UB_LIST_ZONE_NAMES=""
UB_LIST_ZONE_SERVERS=""
config_get zone_type "$cfg" zone_type ""
config_get port "$cfg" port ""
config_get tls_index "$cfg" tls_index ""
config_get tls_port "$cfg" tls_port 853
config_get url_dir "$cfg" url_dir ""
config_get_bool resolv_conf "$cfg" resolv_conf 0
config_get_bool fallback "$cfg" fallback 1
config_get_bool tls_upstream "$cfg" tls_upstream 0
config_list_foreach "$cfg" zone_name bundle_zone_names
config_list_foreach "$cfg" server bundle_zone_servers
# string formating for Unbound syntax
tls_suffix="${tls_port:+@${tls_port}${tls_index:+#${tls_index}}}"
[ "$fallback" -eq 0 ] && fallback=no || fallback=yes
[ "$tls_upstream" -eq 0 ] && tls_upstream=no || tls_upstream=yes
if [ $resolv_conf -eq 1 ] ; then
bundle_resolv_conf_servers
fi
else
zone_type=skip
fi
case $zone_type in
auth_zone)
if [ "$UB_B_NTP_BOOT" -eq 0 ] && [ -n "$UB_LIST_ZONE_NAMES" ] \
&& { [ -n "$url_dir" ] || [ -n "$UB_LIST_ZONE_SERVERS" ] ; } ; then
# Note AXFR may have large downloads. If NTP restart is configured,
# then this can cause procd to force a process kill.
for zone_name in $UB_LIST_ZONE_NAMES ; do
if [ "$zone_name" = "." ] ; then
zone_sym=.
zone_name=root
zone_file=root.zone
else
zone_sym=$zone_name
zone_file=$zone_name.zone
zone_file=${zone_file//../.}
fi
{
# generate an auth-zone: with switches for prefetch cache
echo "auth-zone:"
echo " name: $zone_sym"
for server in $UB_LIST_ZONE_SERVERS ; do
echo " master: $server${port:+@${port}}"
done
if [ -n "$url_dir" ] ; then
echo " url: $url_dir$zone_file"
fi
echo " fallback-enabled: $fallback"
echo " for-downstream: no"
echo " for-upstream: yes"
echo " zonefile: $zone_file"
echo
} >> $UB_ZONE_CONF
done
fi
;;
forward_zone)
if [ ! -f $UB_TLS_FWD_FILE ] && [ "$tls_upstream" = "yes" ] ; then
logger -p 4 -t unbound -s \
"Forward-zone TLS benefits from authentication in package 'ca-bundle'"
fi
if [ -n "$UB_LIST_ZONE_NAMES" ] && [ -n "$UB_LIST_ZONE_SERVERS" ] ; then
for server in $UB_LIST_ZONE_SERVERS ; do
if [ "$( valid_subnet_any $server )" = "not" ] ; then
case $server in
*@[0-9]*|*#[A-Za-z0-9]*)
# unique Unbound option for server host name
servers_host="$servers_host $server"
;;
*)
if [ "$tls_upstream" = "yes" ] ; then
servers_host="$servers_host $server${tls_port:+@${tls_port}}"
else
servers_host="$servers_host $server${port:+@${port}}"
fi
;;
esac
else
case $server in
*@[0-9]*|*#[A-Za-z0-9]*)
# unique Unbound option for server address
servers_ip="$servers_ip $server"
;;
*)
if [ "$tls_upstream" = "yes" ] ; then
servers_ip="$servers_ip $server$tls_suffix"
else
servers_ip="$servers_ip $server${port:+@${port}}"
fi
;;
esac
fi
done
for zonename in $UB_LIST_ZONE_NAMES ; do
{
# generate a forward-zone with or without tls
echo "forward-zone:"
echo " name: $zonename"
for server in $servers_host ; do
echo " forward-host: $server"
done
for server in $servers_ip ; do
echo " forward-addr: $server"
done
echo " forward-first: $fallback"
echo " forward-tls-upstream: $tls_upstream"
echo
} >> $UB_ZONE_CONF
done
fi
;;
stub_zone)
if [ -n "$UB_LIST_ZONE_NAMES" ] && [ -n "$UB_LIST_ZONE_SERVERS" ] ; then
for zonename in $UB_LIST_ZONE_NAMES ; do
{
# generate a stub-zone: or ensure short cut to authority NS
echo "stub-zone:"
echo " name: $zonename"
for server in $UB_LIST_ZONE_SERVERS ; do
echo " stub-addr: $server${port:+@${port}}"
done
echo " stub-first: $fallback"
echo
} >> $UB_ZONE_CONF
done
fi
;;
esac
}
##############################################################################
unbound_conf() {
local rt_mem rt_conn rt_buff modulestring domain ifsubnet moduleopts
{
# server: for this whole function
echo "# $UB_CORE_CONF generated by UCI $( date -Is )"
echo "server:"
echo " username: unbound"
echo " chroot: $UB_VARDIR"
echo " directory: $UB_VARDIR"
echo " pidfile: $UB_PIDFILE"
} > $UB_CORE_CONF
if [ -f "$UB_TLS_FWD_FILE" ] ; then
# TLS cert bundle for upstream forwarder and https zone files
# This is loaded before drop to root, so pull from /etc/ssl
echo " tls-cert-bundle: $UB_TLS_FWD_FILE" >> $UB_CORE_CONF
fi
if [ -f "$UB_RHINT_FILE" ] ; then
# Optional hints if found
echo " root-hints: $UB_RHINT_FILE" >> $UB_CORE_CONF
fi
if [ "$UB_B_DNSSEC" -gt 0 ] && [ -f "$UB_RKEY_FILE" ] ; then
{
echo " auto-trust-anchor-file: $UB_RKEY_FILE"
echo
} >> $UB_CORE_CONF
else
echo >> $UB_CORE_CONF
fi
if [ "$UB_N_THREADS" -gt 1 ] \
&& $PROG -V | grep -q "Linked libs:.*libevent" ; then
# heavy variant using "threads" may need substantial resources
echo " num-threads: 2" >> $UB_CORE_CONF
else
# light variant with one "process" is much more efficient with light traffic
echo " num-threads: 1" >> $UB_CORE_CONF
fi
{
# Limited threading (2) with one shared slab
echo " msg-cache-slabs: 1"
echo " rrset-cache-slabs: 1"
echo " infra-cache-slabs: 1"
echo " key-cache-slabs: 1"
echo
# Logging
echo " use-syslog: yes"
echo " statistics-interval: 0"
echo " statistics-cumulative: no"
} >> $UB_CORE_CONF
if [ "$UB_D_VERBOSE" -ge 0 ] && [ "$UB_D_VERBOSE" -le 5 ] ; then
echo " verbosity: $UB_D_VERBOSE" >> $UB_CORE_CONF
fi
if [ "$UB_B_EXT_STATS" -gt 0 ] ; then
{
# Log More
echo " extended-statistics: yes"
echo
} >> $UB_CORE_CONF
else
{
# Log Less
echo " extended-statistics: no"
echo
} >> $UB_CORE_CONF
fi
case "$UB_D_PROTOCOL" in
ip4_only)
{
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: 0.0.0.0"
echo " outgoing-interface: 0.0.0.0"
echo " do-ip4: yes"
echo " do-ip6: no"
echo
} >> $UB_CORE_CONF
;;
ip6_only)
{
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: ::0"
echo " outgoing-interface: ::0"
echo " do-ip4: no"
echo " do-ip6: yes"
echo
} >> $UB_CORE_CONF
;;
ip6_local)
{
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: 0.0.0.0"
echo " interface: ::0"
echo " outgoing-interface: 0.0.0.0"
echo " do-ip4: yes"
echo " do-ip6: yes"
echo
} >> $UB_CORE_CONF
;;
ip6_prefer)
{
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: 0.0.0.0"
echo " interface: ::0"
echo " outgoing-interface: 0.0.0.0"
echo " outgoing-interface: ::0"
echo " do-ip4: yes"
echo " do-ip6: yes"
echo " prefer-ip6: yes"
echo
} >> $UB_CORE_CONF
;;
mixed)
{
# Interface Wildcard (access contol handled by "option local_service")
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: 0.0.0.0"
echo " interface: ::0"
echo " outgoing-interface: 0.0.0.0"
echo " outgoing-interface: ::0"
echo " do-ip4: yes"
echo " do-ip6: yes"
echo
} >> $UB_CORE_CONF
;;
*)
if [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "default protocol configuration"
fi
{
# outgoing-interface has useful defaults; incoming is localhost though
echo " edns-buffer-size: $UB_N_EDNS_SIZE"
echo " port: $UB_N_RX_PORT"
echo " outgoing-port-permit: 10240-65535"
echo " interface: 0.0.0.0"
echo " interface: ::0"
echo
} >> $UB_CORE_CONF
;;
esac
if [ "$UB_B_IF_AUTO" -gt 0 ] ; then
echo " interface-automatic: yes" >> $UB_CORE_CONF
fi
case "$UB_D_RESOURCE" in
# Tiny - Unbound's recommended cheap hardware config
tiny) rt_mem=1 ; rt_conn=2 ; rt_buff=1 ;;
# Small - Half RRCACHE and open ports
small) rt_mem=8 ; rt_conn=10 ; rt_buff=2 ;;
# Medium - Nearly default but with some added balancintg
medium) rt_mem=16 ; rt_conn=15 ; rt_buff=4 ;;
# Large - Double medium
large) rt_mem=32 ; rt_conn=20 ; rt_buff=4 ;;
# Whatever unbound does
*) rt_mem=0 ; rt_conn=0 ;;
esac
if [ "$rt_mem" -gt 0 ] ; then
{
# Other harding and options for an embedded router
echo " harden-short-bufsize: yes"
echo " harden-large-queries: yes"
echo " harden-glue: yes"
echo " use-caps-for-id: no"
echo
# Set memory sizing parameters
echo " msg-buffer-size: $(($rt_buff*8192))"
echo " outgoing-range: $(($rt_conn*32))"
echo " num-queries-per-thread: $(($rt_conn*16))"
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
} >> $UB_CORE_CONF
elif [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "default memory configuration"
fi
# Assembly of module-config: options is tricky; order matters
moduleopts="$( /usr/sbin/unbound -V )"
modulestring="iterator"
case $moduleopts in
*with-python*)
modulestring="python $modulestring"
;;
esac
if [ "$UB_B_DNSSEC" -gt 0 ] ; then
if [ "$UB_B_NTP_BOOT" -gt 0 ] ; then
# DNSSEC chicken and egg with getting NTP time
echo " val-override-date: -1" >> $UB_CORE_CONF
fi
{
echo " harden-dnssec-stripped: yes"
echo " val-clean-additional: yes"
echo " ignore-cd-flag: yes"
} >> $UB_CORE_CONF
modulestring="validator $modulestring"
fi
case $moduleopts in
*enable-subnet*)
modulestring="subnetcache $modulestring"
;;
esac
if [ "$UB_B_DNS64" -gt 0 ] ; then
echo " dns64-prefix: $UB_IP_DNS64" >> $UB_CORE_CONF
modulestring="dns64 $modulestring"
fi
{
# Print final module string
echo " module-config: \"$modulestring\""
echo
} >> $UB_CORE_CONF
case "$UB_D_RECURSION" in
passive)
{
# Some query privacy but "strict" will break some servers
if [ "$UB_B_QRY_MINST" -gt 0 ] && [ "$UB_B_QUERY_MIN" -gt 0 ] ; then
echo " qname-minimisation: yes"
echo " qname-minimisation-strict: yes"
elif [ "$UB_B_QUERY_MIN" -gt 0 ] ; then
echo " qname-minimisation: yes"
else
echo " qname-minimisation: no"
fi
# Use DNSSEC to quickly understand NXDOMAIN ranges
if [ "$UB_B_DNSSEC" -gt 0 ] ; then
echo " aggressive-nsec: yes"
echo " prefetch-key: no"
fi
# On demand fetching
echo " prefetch: no"
echo " target-fetch-policy: \"0 0 0 0 0\""
echo
} >> $UB_CORE_CONF
;;
aggressive)
{
# Some query privacy but "strict" will break some servers
if [ "$UB_B_QRY_MINST" -gt 0 ] && [ "$UB_B_QUERY_MIN" -gt 0 ] ; then
echo " qname-minimisation: yes"
echo " qname-minimisation-strict: yes"
elif [ "$UB_B_QUERY_MIN" -gt 0 ] ; then
echo " qname-minimisation: yes"
else
echo " qname-minimisation: no"
fi
# Use DNSSEC to quickly understand NXDOMAIN ranges
if [ "$UB_B_DNSSEC" -gt 0 ] ; then
echo " aggressive-nsec: yes"
echo " prefetch-key: yes"
fi
# Prefetch what can be
echo " prefetch: yes"
echo " target-fetch-policy: \"3 2 1 0 0\""
echo
} >> $UB_CORE_CONF
;;
*)
if [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "default recursion configuration"
fi
;;
esac
{
# Reload records more than 20 hours old
# DNSSEC 5 minute bogus cool down before retry
# Adaptive infrastructure info kept for 15 minutes
echo " cache-min-ttl: $UB_TTL_MIN"
echo " cache-max-ttl: 72000"
echo " val-bogus-ttl: 300"
echo " infra-host-ttl: 900"
echo
} >> $UB_CORE_CONF
if [ "$UB_B_HIDE_BIND" -gt 0 ] ; then
{
# Block server id and version DNS TXT records
echo " hide-identity: yes"
echo " hide-version: yes"
echo
} >> $UB_CORE_CONF
fi
if [ "$UB_D_PRIV_BLCK" -gt 0 ] ; then
{
# Remove _upstream_ or global reponses with private addresses.
# Unbounds own "local zone" and "forward zone" may still use these.
# RFC1918, RFC3927, RFC4291, RFC6598, RFC6890
echo " private-address: 10.0.0.0/8"
echo " private-address: 100.64.0.0/10"
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::/7"
echo " private-address: fe80::/10"
echo
} >> $UB_CORE_CONF
fi
if [ -n "$UB_LIST_NETW_LAN" ] && [ "$UB_D_PRIV_BLCK" -gt 1 ] ; then
{
for ifsubnet in $UB_LIST_NETW_LAN ; do
case $ifsubnet in
*@[1-9][0-9a-f][0-9a-f][0-9a-f]:*:[0-9a-f]*)
# Remove global DNS responses with your local network IP6 GLA
echo " private-address: ${ifsubnet#*@}"
;;
esac
done
echo
} >> $UB_CORE_CONF
fi
if [ "$UB_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
} >> $UB_CORE_CONF
fi
if [ -n "$UB_LIST_INSECURE" ] ; then
{
for domain in $UB_LIST_INSECURE ; do
# Except and accept domains without (DNSSEC); work around broken domains
echo " domain-insecure: $domain"
done
echo
} >> $UB_CORE_CONF
fi
if [ "$UB_B_LOCL_SERV" -gt 0 ] && [ -n "$UB_LIST_NETW_ALL" ] ; then
{
for ifsubnet in $UB_LIST_NETW_ALL ; do
# Only respond to queries from subnets which have an interface.
# Prevent DNS amplification attacks by not responding to the universe.
echo " access-control: ${ifsubnet#*@} allow"
done
echo " access-control: 127.0.0.0/8 allow"
echo " access-control: ::1/128 allow"
echo " access-control: fe80::/10 allow"
echo
} >> $UB_CORE_CONF
else
{
echo " access-control: 0.0.0.0/0 allow"
echo " access-control: ::0/0 allow"
echo
} >> $UB_CORE_CONF
fi
}
##############################################################################
unbound_hostname() {
local ifsubnet ifarpa ifaddr ifname iffqdn
local ulaprefix hostfqdn name names namerec ptrrec
local zonetype=0
echo "# $UB_HOST_CONF generated by UCI $( date -Is )" > $UB_HOST_CONF
if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then
{
echo "# Local zone is handled by dnsmasq"
echo
} >> $UB_HOST_CONF
elif [ -n "$UB_TXT_DOMAIN" ] \
&& { [ "$UB_D_WAN_FQDN" -gt 0 ] || [ "$UB_D_LAN_FQDN" -gt 0 ] ; } ; then
case "$UB_D_DOMAIN_TYPE" in
deny|inform_deny|refuse|static)
{
# type static means only this router has your domain
echo " domain-insecure: $UB_TXT_DOMAIN"
echo " private-domain: $UB_TXT_DOMAIN"
echo " local-zone: $UB_TXT_DOMAIN $UB_D_DOMAIN_TYPE"
echo " local-data: \"$UB_TXT_DOMAIN. $UB_XSOA\""
echo " local-data: \"$UB_TXT_DOMAIN. $UB_XNS\""
echo " local-data: '$UB_TXT_DOMAIN. $UB_XTXT'"
echo
if [ "$UB_TXT_DOMAIN" != "local" ] ; then
# avoid involvement in RFC6762, unless it is the local zone name
echo " local-zone: local always_nxdomain"
echo
fi
} >> $UB_HOST_CONF
zonetype=2
;;
inform|transparent|typetransparent)
{
# transparent will permit forward-zone: or stub-zone: clauses
echo " private-domain: $UB_TXT_DOMAIN"
echo " local-zone: $UB_TXT_DOMAIN $UB_D_DOMAIN_TYPE"
echo
} >> $UB_HOST_CONF
zonetype=1
;;
esac
{
# Hostname as TLD works, but not transparent through recursion (singular)
echo " domain-insecure: $UB_TXT_HOSTNAME"
echo " private-domain: $UB_TXT_HOSTNAME"
echo " local-zone: $UB_TXT_HOSTNAME static"
echo " local-data: \"$UB_TXT_HOSTNAME. $UB_XSOA\""
echo " local-data: \"$UB_TXT_HOSTNAME. $UB_XNS\""
echo " local-data: '$UB_TXT_HOSTNAME. $UB_XTXT'"
echo
} >> $UB_HOST_CONF
if [ -n "$UB_LIST_NETW_WAN" ] ; then
for ifsubnet in $UB_LIST_NETW_WAN ; do
ifaddr=${ifsubnet#*@}
ifaddr=${ifaddr%/*}
ifarpa=$( host_ptr_any "$ifaddr" )
if [ -n "$ifarpa" ] ; then
if [ "$UB_D_WAN_FQDN" -gt 0 ] ; then
{
# Create a static zone for WAN host record only (singular)
echo " domain-insecure: $ifarpa"
echo " private-address: $ifaddr"
echo " local-zone: $ifarpa static"
echo " local-data: \"$ifarpa. $UB_XSOA\""
echo " local-data: \"$ifarpa. $UB_XNS\""
echo " local-data: '$ifarpa. $UB_MTXT'"
echo
} >> $UB_HOST_CONF
elif [ "$zonetype" -gt 0 ] ; then
{
echo " local-zone: $ifarpa transparent"
echo
} >> $UB_HOST_CONF
fi
fi
done
fi
if [ -n "$UB_LIST_NETW_LAN" ] ; then
for ifsubnet in $UB_LIST_NETW_LAN ; do
ifarpa=$( domain_ptr_any "${ifsubnet#*@}" )
if [ -n "$ifarpa" ] ; then
if [ "$zonetype" -eq 2 ] ; then
{
# Do NOT forward queries with your ip6.arpa or in-addr.arpa
echo " domain-insecure: $ifarpa"
echo " local-zone: $ifarpa static"
echo " local-data: \"$ifarpa. $UB_XSOA\""
echo " local-data: \"$ifarpa. $UB_XNS\""
echo " local-data: '$ifarpa. $UB_XTXT'"
echo
} >> $UB_HOST_CONF
elif [ "$zonetype" -eq 1 ] && [ "$UB_D_PRIV_BLCK" -eq 0 ] ; then
{
echo " local-zone: $ifarpa transparent"
echo
} >> $UB_HOST_CONF
fi
fi
done
fi
ulaprefix=$( uci_get network.@globals[0].ula_prefix )
ulaprefix=${ulaprefix%%:/*}
hostfqdn="$UB_TXT_HOSTNAME.$UB_TXT_DOMAIN"
if [ -z "$ulaprefix" ] ; then
# Nonsense so this option isn't globbed below
ulaprefix="fdno:such:addr::"
fi
if [ "$UB_LIST_NETW_LAN" ] && [ "$UB_D_LAN_FQDN" -gt 0 ] ; then
for ifsubnet in $UB_LIST_NETW_LAN ; do
ifaddr=${ifsubnet#*@}
ifaddr=${ifaddr%/*}
ifname=${ifsubnet%@*}
iffqdn="$ifname.$hostfqdn"
if [ "$UB_D_LAN_FQDN" -eq 4 ] ; then
names="$iffqdn $hostfqdn $UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $iffqdn\""
echo "$ptrrec" >> $UB_HOST_CONF
elif [ "$UB_D_LAN_FQDN" -eq 3 ] ; then
names="$hostfqdn $UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $hostfqdn\""
echo "$ptrrec" >> $UB_HOST_CONF
else
names="$UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $UB_TXT_HOSTNAME\""
echo "$ptrrec" >> $UB_HOST_CONF
fi
for name in $names ; do
case $ifaddr in
"${ulaprefix}"*)
# IP6 ULA only is assigned for OPTION 1
namerec=" local-data: \"$name. 300 IN AAAA $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
;;
[1-9]*.*[0-9])
namerec=" local-data: \"$name. 300 IN A $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
;;
*)
if [ "$UB_D_LAN_FQDN" -gt 1 ] ; then
# IP6 GLA is assigned for higher options
namerec=" local-data: \"$name. 300 IN AAAA $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
fi
;;
esac
done
echo >> $UB_HOST_CONF
done
fi
if [ -n "$UB_LIST_NETW_WAN" ] && [ "$UB_D_WAN_FQDN" -gt 0 ] ; then
for ifsubnet in $UB_LIST_NETW_WAN ; do
ifaddr=${ifsubnet#*@}
ifaddr=${ifaddr%/*}
ifname=${ifsubnet%@*}
iffqdn="$ifname.$hostfqdn"
if [ "$UB_D_WAN_FQDN" -eq 4 ] ; then
names="$iffqdn $hostfqdn $UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $iffqdn\""
echo "$ptrrec" >> $UB_HOST_CONF
elif [ "$UB_D_WAN_FQDN" -eq 3 ] ; then
names="$hostfqdn $UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $hostfqdn\""
echo "$ptrrec" >> $UB_HOST_CONF
else
names="$UB_TXT_HOSTNAME"
ptrrec=" local-data-ptr: \"$ifaddr 300 $UB_TXT_HOSTNAME\""
echo "$ptrrec" >> $UB_HOST_CONF
fi
for name in $names ; do
case $ifaddr in
"${ulaprefix}"*)
# IP6 ULA only is assigned for OPTION 1
namerec=" local-data: \"$name. 300 IN AAAA $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
;;
[1-9]*.*[0-9])
namerec=" local-data: \"$name. 300 IN A $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
;;
*)
if [ "$UB_D_WAN_FQDN" -gt 1 ] ; then
# IP6 GLA is assigned for higher options
namerec=" local-data: \"$name. 300 IN AAAA $ifaddr\""
echo "$namerec" >> $UB_HOST_CONF
fi
;;
esac
done
echo >> $UB_HOST_CONF
done
fi
fi # end if uci valid
}
##############################################################################
unbound_uci() {
local cfg="$1"
local hostnm
hostnm=$( uci_get system.@system[0].hostname | awk '{print tolower($0)}' )
UB_TXT_HOSTNAME=${hostnm:-thisrouter}
config_get_bool UB_B_SLAAC6_MAC "$cfg" dhcp4_slaac6 0
config_get_bool UB_B_DNS64 "$cfg" dns64 0
config_get_bool UB_B_EXT_STATS "$cfg" extended_stats 0
config_get_bool UB_B_HIDE_BIND "$cfg" hide_binddata 1
config_get_bool UB_B_LOCL_SERV "$cfg" localservice 1
config_get_bool UB_B_MAN_CONF "$cfg" manual_conf 0
config_get_bool UB_B_QUERY_MIN "$cfg" query_minimize 0
config_get_bool UB_B_QRY_MINST "$cfg" query_min_strict 0
config_get_bool UB_B_AUTH_ROOT "$cfg" prefetch_root 0
config_get_bool UB_B_LOCL_BLCK "$cfg" rebind_localhost 0
config_get_bool UB_B_DNSSEC "$cfg" validator 0
config_get_bool UB_B_NTP_BOOT "$cfg" validator_ntp 1
config_get_bool UB_B_IF_AUTO "$cfg" interface_auto 1
config_get UB_IP_DNS64 "$cfg" dns64_prefix "64:ff9b::/96"
config_get UB_N_EDNS_SIZE "$cfg" edns_size 1280
config_get UB_N_RX_PORT "$cfg" listen_port 53
config_get UB_N_ROOT_AGE "$cfg" root_age 9
config_get UB_N_THREADS "$cfg" num_threads 1
config_get UB_D_CONTROL "$cfg" unbound_control 0
config_get UB_D_DOMAIN_TYPE "$cfg" domain_type static
config_get UB_D_DHCP_LINK "$cfg" dhcp_link none
config_get UB_D_EXTRA_DNS "$cfg" add_extra_dns 0
config_get UB_D_LAN_FQDN "$cfg" add_local_fqdn 0
config_get UB_D_PRIV_BLCK "$cfg" rebind_protection 1
config_get UB_D_PROTOCOL "$cfg" protocol mixed
config_get UB_D_RECURSION "$cfg" recursion passive
config_get UB_D_RESOURCE "$cfg" resource small
config_get UB_D_VERBOSE "$cfg" verbosity 1
config_get UB_D_WAN_FQDN "$cfg" add_wan_fqdn 0
config_get UB_TTL_MIN "$cfg" ttl_min 120
config_get UB_TXT_DOMAIN "$cfg" domain lan
config_list_foreach "$cfg" domain_insecure bundle_domain_insecure
if [ "$UB_D_DHCP_LINK" = "none" ] ; then
config_get_bool UB_B_DNSMASQ "$cfg" dnsmasq_link_dns 0
if [ "$UB_B_DNSMASQ" -gt 0 ] ; then
UB_D_DHCP_LINK=dnsmasq
if [ "$UB_B_READY" -eq 0 ] ; then
logger -t unbound -s "Please use 'dhcp_link' selector instead"
fi
fi
fi
if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then
if [ ! -x /usr/sbin/dnsmasq ] || [ ! -x /etc/init.d/dnsmasq ] ; then
UB_D_DHCP_LINK=none
else
/etc/init.d/dnsmasq enabled || UB_D_DHCP_LINK=none
fi
if [ "$UB_B_READY" -eq 0 ] && [ "$UB_D_DHCP_LINK" = "none" ] ; then
logger -t unbound -s "cannot forward to dnsmasq"
fi
fi
if [ "$UB_D_DHCP_LINK" = "odhcpd" ] ; then
if [ ! -x /usr/sbin/odhcpd ] || [ ! -x /etc/init.d/odhcpd ] ; then
UB_D_DHCP_LINK=none
else
/etc/init.d/odhcpd enabled || UB_D_DHCP_LINK=none
fi
if [ "$UB_B_READY" -eq 0 ] && [ "$UB_D_DHCP_LINK" = "none" ] ; then
logger -t unbound -s "cannot receive records from odhcpd"
fi
fi
if [ "$UB_N_EDNS_SIZE" -lt 512 ] || [ 4096 -lt "$UB_N_EDNS_SIZE" ] ; then
logger -t unbound -s "edns_size exceeds range, using default"
UB_N_EDNS_SIZE=1280
fi
if [ "$UB_N_RX_PORT" -ne 53 ] \
&& { [ "$UB_N_RX_PORT" -lt 1024 ] || [ 10240 -lt "$UB_N_RX_PORT" ] ; } ; then
logger -t unbound -s "privileged port or in 5 digits, using default"
UB_N_RX_PORT=53
fi
if [ "$UB_TTL_MIN" -gt 1800 ] ; then
logger -t unbound -s "ttl_min could have had awful side effects, using 300"
UB_TTL_MIN=300
fi
}
##############################################################################
unbound_include() {
local adb_enabled
local adb_files=$( ls $UB_VARDIR/adb_list.* 2>/dev/null )
echo "# $UB_TOTAL_CONF generated by UCI $( date -Is )" > $UB_TOTAL_CONF
if [ -f "$UB_CORE_CONF" ] ; then
# Yes this all looks busy, but it is in TMPFS. Working on separate files
# and piecing together is easier. UCI order is less constrained.
cat $UB_CORE_CONF >> $UB_TOTAL_CONF
rm $UB_CORE_CONF
fi
if [ -f "$UB_HOST_CONF" ] ; then
# UCI definitions of local host or local subnet
cat $UB_HOST_CONF >> $UB_TOTAL_CONF
rm $UB_HOST_CONF
fi
if [ -f $UB_SRVMASQ_CONF ] ; then
# UCI found link to dnsmasq
cat $UB_SRVMASQ_CONF >> $UB_TOTAL_CONF
rm $UB_SRVMASQ_CONF
fi
if [ -f "$UB_DHCP_CONF" ] ; then
{
# Seed DHCP records because dhcp scripts trigger externally
# Incremental Unbound restarts may drop unbound-control records
echo "include: $UB_DHCP_CONF"
echo
}>> $UB_TOTAL_CONF
fi
if [ -z "$adb_files" ] || [ ! -x /usr/bin/adblock.sh ] \
|| [ ! -x /etc/init.d/adblock ] ; then
adb_enabled=0
elif /etc/init.d/adblock enabled ; then
adb_enabled=1
{
# Pull in your selected openwrt/pacakges/net/adblock generated lists
echo "include: $UB_VARDIR/adb_list.*"
echo
} >> $UB_TOTAL_CONF
else
adb_enabled=0
fi
if [ -f $UB_SRV_CONF ] ; then
{
# Pull your own "server:" options here
echo "include: $UB_SRV_CONF"
echo
}>> $UB_TOTAL_CONF
fi
if [ -f "$UB_ZONE_CONF" ] ; then
# UCI defined forward, stub, and auth zones
cat $UB_ZONE_CONF >> $UB_TOTAL_CONF
rm $UB_ZONE_CONF
fi
if [ -f "$UB_CTRL_CONF" ] ; then
# UCI defined control application connection
cat $UB_CTRL_CONF >> $UB_TOTAL_CONF
rm $UB_CTRL_CONF
fi
if [ -f "$UB_EXTMASQ_CONF" ] ; then
# UCI found link to dnsmasq
cat $UB_EXTMASQ_CONF >> $UB_TOTAL_CONF
rm $UB_EXTMASQ_CONF
fi
if [ -f "$UB_EXT_CONF" ] ; then
{
# Pull your own extend feature clauses here
echo "include: $UB_EXT_CONF"
echo
} >> $UB_TOTAL_CONF
fi
}
##############################################################################
resolv_setup() {
if [ "$UB_N_RX_PORT" != "53" ] ; then
return
elif [ -x /etc/init.d/dnsmasq ] \
&& /etc/init.d/dnsmasq enabled \
&& nslookup localhost 127.0.0.1#53 >/dev/null 2>&1 ; then
# unbound is configured for port 53, but dnsmasq is enabled and a resolver
# listens on localhost:53, lets assume dnsmasq manages the resolver file.
# TODO:
# really check if dnsmasq runs a local (main) resolver in stead of using
# nslookup that times out when no resolver listens on localhost:53.
return
fi
# unbound is designated to listen on 127.0.0.1#53,
# set resolver file to local.
rm -f /tmp/resolv.conf
{
echo "# /tmp/resolv.conf generated by Unbound UCI $( date -Is )"
echo "nameserver 127.0.0.1"
echo "nameserver ::1"
echo "search $UB_TXT_DOMAIN."
} > /tmp/resolv.conf
}
##############################################################################
unbound_start() {
config_load unbound
config_foreach unbound_uci unbound
unbound_mkdir
if [ "$UB_B_MAN_CONF" -eq 0 ] ; then
# iterate zones before we load other UCI
# forward-zone: auth-zone: and stub-zone:
config_foreach unbound_zone zone
# associate potential DNS RR with interfaces
config_load network
config_foreach bundle_all_networks interface
config_load dhcp
config_foreach bundle_lan_networks dhcp
bundle_wan_networks
# server:
unbound_conf
unbound_hostname
# control:
unbound_control
# dnsmasq
dnsmasq_link
# merge
unbound_include
fi
resolv_setup
}
##############################################################################