diff --git a/net/unbound/Makefile b/net/unbound/Makefile index 93856b2bd..c8c8c4ab5 100644 --- a/net/unbound/Makefile +++ b/net/unbound/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=unbound PKG_VERSION:=1.7.3 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_LICENSE:=BSD-3-Clause PKG_LICENSE_FILES:=LICENSE @@ -159,7 +159,7 @@ define Package/unbound/install $(INSTALL_DATA) ./files/iptools.sh $(1)/usr/lib/unbound/iptools.sh $(INSTALL_BIN) ./files/odhcpd.sh $(1)/usr/lib/unbound/odhcpd.sh $(INSTALL_DATA) ./files/odhcpd.awk $(1)/usr/lib/unbound/odhcpd.awk - $(INSTALL_DATA) ./files/rootzone.sh $(1)/usr/lib/unbound/rootzone.sh + $(INSTALL_DATA) ./files/stopping.sh $(1)/usr/lib/unbound/stopping.sh $(INSTALL_DATA) ./files/unbound.sh $(1)/usr/lib/unbound/unbound.sh endef diff --git a/net/unbound/files/README.md b/net/unbound/files/README.md index 0a8020be0..d22d56681 100644 --- a/net/unbound/files/README.md +++ b/net/unbound/files/README.md @@ -6,7 +6,7 @@ ## Package Overview OpenWrt default build uses [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html) for DNS forwarding and DHCP. With a forward only resolver, dependence on the upstream recursors may be cause for concern. They are often provided by the ISP, and some users have switched to public DNS providers. Either way may result in problems due to performance, "snoop-vertising", hijacking (MiM), and other causes. Running a recursive resolver or resolver capable of TLS may be a solution. -Unbound may be useful on consumer grade embedded hardware. It is fully DNSSEC and TLS capable. It is _intended_ to be a recursive resolver only. [NLnet Labs NSD](https://www.nlnetlabs.nl/projects/nsd/) is _intended_ for the authoritative task. This is different than [ISC Bind](https://www.isc.org/downloads/bind/) and its inclusive functions. Unbound configuration effort and memory consumption may be easier to control. A consumer could have their own recursive resolver with 8/64 MB router, and remove potential issues from forwarding resolvers outside of their control. +Unbound may be useful on consumer grade embedded hardware. It is fully DNSSEC and TLS capable. It is _intended_ to be a recursive resolver only. NLnet Labs [NSD](https://www.nlnetlabs.nl/projects/nsd/) is _intended_ for the authoritative task. This is different than [ISC Bind](https://www.isc.org/downloads/bind/) and its inclusive functions. Unbound configuration effort and memory consumption may be easier to control. A consumer could have their own recursive resolver with 8/64 MB router, and remove potential issues from forwarding resolvers outside of their control. This package builds on Unbounds capabilities with OpenWrt UCI. Not every Unbound option is in UCI, but rather, UCI simplifies the combination of related options. Unbounds native options are bundled and balanced within a smaller set of choices. Options include resources, DNSSEC, access control, and some TTL tweaking. The UCI also provides an escape option and works at the raw "unbound.conf" level. @@ -18,21 +18,21 @@ A few tweaks may be needed to enhance the realiability and effectiveness. Ad Blo **/etc/config/firewall**: ``` config rule - option name 'Block-Public-DNS' - option enabled '1' - option src 'lan' - option dest 'wan' - option dest_port '53 853 5353' - option proto 'tcpudp' - option family 'any' - option target 'REJECT' + option name 'Block-Public-DNS' + option enabled '1' + option src 'lan' + option dest 'wan' + option dest_port '53 853 5353' + option proto 'tcpudp' + option family 'any' + option target 'REJECT' ``` ## HOW TO: Integrate with DHCP Some UCI options and scripts help Unbound to work with DHCP servers to load the local DNS. The examples provided here are serial dnsmasq-unbound, parallel dnsmasq-unbound, and unbound scripted with odhcpd. ### Serial dnsmasq -In this case, dnsmasq is not changed *much* with respect to the default [OpenWrt configuration](https://openwrt.org/docs/guide-user/base-system/dns_configuration). Here dnsmasq is forced to use the local Unbound instance as the lone upstream DNS server, instead of your ISP. This may be the easiest implementation, but performance degradation can occur in high volume networks. dnsmasq and Unbound effectively have the same information in memory, and all transfers are double handled. +In this case, dnsmasq is not changed *much* with respect to the default [OpenWrt](https://openwrt.org/docs/guide-user/base-system/dns_configuration) configuration. Here dnsmasq is forced to use the local Unbound instance as the lone upstream DNS server, instead of your ISP. This may be the easiest implementation, but performance degradation can occur in high volume networks. Unbound and dnsmasq effectively have the same information in memory, and all transfers are double handled. **/etc/config/unbound**: ``` @@ -120,7 +120,6 @@ config dhcp 'lan' option leasetime '12h' option ra 'server' option ra_management '1' - # odhcpd should issue ULA [fd00::/8] by default ... config odhcpd 'odhcpd' @@ -151,23 +150,40 @@ You like the UCI. Yet, you need to add some difficult to standardize options, or The file `unbound_srv.conf` will be added into the `server:` clause. The file `unbound_ext.conf` will be added to the end of all configuration. It is for extended `forward-zone:`, `stub-zone:`, `auth-zone:`, and `view:` clauses. You can also disable unbound-control in the UCI which only allows "localhost" connections unencrypted, and then add an encrypted remote `control:` clause. -#### DNS over TLS -Some public servers are now offering DNS over TLS. Unbound supports acting as DNS over TLS forwarding client. You can use the override files to enable this funciton. Unbound will connect TLS without verifying keys unless you include the PEM path and install `ca-bundle` package. No connection or connection without verification will occur unless you use complete syntax with "@" and "#". See `forward-addr: 1.1.1.1@853#cloudflare-dns.com` for example. Unbound makes a new TLS connection for each query. You limit this effect using large resource and aggressive recursion setting (big cache and prefetching). You can also set memory and recursion to default and edit `unbound_srv.conf` to suit your needs. UCI improvements are in progress but not ready in OpenWrt 18.06. +## HOW TO: Cache Zone Files +Unbound has the ability to AXFR a whole zone from an authoritative server to prefetch the zone. This can speed up access to common zones. Some may have special bandwidth concerns for DNSSEC overhead. The following is a generic example. UCI defaults include the [root](https://www.internic.net/domain/) zone, but it is disabled as a ready to go example. -**/etc/unbound/unbound_srv.conf**: +**/etc/config/unbound**: ``` - tls-service-pem: /etc/ssl/certs/ca-certificates.crt +config zone + option enabled '1' + option fallback '1' + option url_dir 'https://asset-management.it.example.com/zones/' + option zone_type 'auth_zone' + list server 'ns1.it.example.com' + list server 'ns2.it.example.com' + list zone_name 'example.com' ``` -**/etc/unbound/unbound_ext.conf**: +## HOW TO: TLS Over DNS +Unbound has the ability to be client and server in TLS mode. UCI can configure Unbound to be a client forwarding queries in TLS mode for selected domains. (Server is more complex to setup and needs to be done manually). This may be desired for privacy against stealth market tracking in some cases. Some public DNS servers seem to advertise help in this quest. + +Unbound will make TLS connections without validation unless you install the 'ca-bundle' package. Do **not** however forget to maintain the certification bundle. The validation chain otherwise will expire and connections will go dead. Unbound makes and breaks TCP connections per connection. To reduce the lag from TLS handshaking it may help to use more cache memory `resource`, increase record exirations `ttl_min`, enable `aggressive` searching, or manually enable prefetch options. + +The following is a generic example. If your looking for a better understanding, then some information can be found at [Cloudflare](https://www.cloudflare.com/) DNS [1.1.1.1](https://1.1.1.1/) for one place. + +**/etc/config/unbound**: ``` -forward-zone: - name: . - forward-addr: 1.1.1.1@853#cloudflare-dns.com - forward-addr: 1.0.0.1@853#cloudflare-dns.com - forward-addr: 2606:4700:4700::1111@853#cloudflare-dns.com - forward-addr: 2606:4700:4700::1001@853#cloudflare-dns.com - forward-tls-upstream: yes +config zone + option enabled '1' + # question: do you want to recurse when TLS fails or not? + option fallback '0' + option tls_index 'dns.example.net' + option tls_upstream '1' + option zone_type 'forward_zone' + list server '192.0.2.53' + list server '2001:db8::53' + list zone_name '.' ``` ## Complete List of UCI Options @@ -234,9 +250,6 @@ config unbound Bytes. Extended DNS is necessary for DNSSEC. However, it can run into MTU issues. Use this size in bytes to manage drop outs. - option extended_luci '0' - Boolean. Extends a tab hierarchy in LuCI for advanced configuration. - option extended_stats '0' Boolean. extended statistics are printed from unbound-control. Keeping track of more statistics takes time. @@ -256,11 +269,6 @@ config unbound Boolean. Skip all this UCI nonsense. Manually edit the configuration. Make changes to /etc/unbound/unbound.conf. - option prefetch_root '0' - Boolean. Cache the entire root. Enable Unbound `auth-zone:` clauses for - "." (root), "arpa," "in-addr.arpa," and "ip6.arpa." Obtain complete zone - files from public servers using http or AXFR. (see RFC7706) - option protocol 'mixed' Unbound can limit its protocol used for recursive queries. ip4_only - limit issues if you do not have native IPv6 @@ -336,23 +344,83 @@ 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_forward 'mail.my-isp.com' - Domain. Do not recurse, but rather forward the domains to given DNS - servers found in resolve.conf.auto from WAN DHCP client. This may - provide better access to mirror servers in 'your neigborhood.' This - may be useful in keeping local organization lookups on local subnets. + option verbosity '1' + Level. Sets Unbounds logging intensity. list domain_insecure 'ntp.somewhere.org' Domain. Domains that you wish to skip DNSSEC. It is one way around NTP chicken and egg. Your DHCP servered domains are automatically included. - list rebind_interface 'lan' - Interface (logical). Works with 'rebind_protection' options 2 and 3. - list trigger_interface '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. + + +config zone + Create Unbounds forward-zone:, stub-zone:, or auth-zone: clauses + + option enabled 1 + Boolean. Enable the zone clause. + + option fallback 1 + Boolean. Permit normal recursion when the narrowly selected servers + in this zone are unresponsive or return empty responses. Disable, if + there are security concerns (forward only internal to organization). + + option port 53 + Port. Servers are contact on this port for plain DNS operations. + + option resolv_conf 0 + Boolean. Use "resolv.conf" as it was filled by the DHCP client. This + can be used to forward zones within your ISP (mail.example.net) or that + have co-located services (streamed-movies.example.com). Recursion may + not yield the most local result, but forwarding may instead. + + option tls_index (n/a) + Domain. Name TLS certificates are signed for (dns.example.net). If this + option is ommitted, then Unbound will make the connection but not + validate it. + + option tls_port 853 + Port. Servers are contact on this port for DNS over TLS operations. + + option tls_upstream 0 + Boolean. Use TLS to contact the zone server. + + option url_dir + String. http or https path, directory part only, to the zone file for + auth_zone type only. Files "${zone_name}.zone" are expect in this path. + + option zone_type (n/a) + State. Required field or the clause is effectively disabled. Check + Unbound documentation for clarity (unbound-conf). + auth_zone - prefetch whole zones from authoritative server (ICANN) + forward_zone - forward queries in these domains to the listed servers + stub_zone - force recursion of these domains to the listed servers + + list server (n/a) + IP. Every zone must have one server. Stub and forward require IP to + prevent chicken and egg (due to UCI simplicity). Authoritative prefetch + may use a server name. + + list zone_name + Domain. Every zone must represent some part of the DNS tree. It can be + all of it "." or you internal organization domain "example.com." Within + each zone clause all zone names will be matched to all servers. ``` +## Replaced Options + config unbound / option prefetch_root + List the domains in a zone with type auth_zone and fill in the server + or url fields. Root zones are ready but disabled in default install UCI. + + config unbound / list domain_forward + List the domains in a zone with type forward_zone and enable the + resolv_conf option. + + config unbound / list rebind_interface + Enable rebind_protection at 2 and all DHCP interfaces are also + protected for IPV6 GLA (parallel to subnets in add_local_fqdn). + diff --git a/net/unbound/files/defaults.sh b/net/unbound/files/defaults.sh index e362b9598..61c88d219 100644 --- a/net/unbound/files/defaults.sh +++ b/net/unbound/files/defaults.sh @@ -14,30 +14,52 @@ # ############################################################################## -UNBOUND_LIBDIR=/usr/lib/unbound -UNBOUND_VARDIR=/var/lib/unbound +# where are we? +UB_LIBDIR=/usr/lib/unbound +UB_VARDIR=/var/lib/unbound +UB_PIDFILE=/var/run/unbound.pid -UNBOUND_PIDFILE=/var/run/unbound.pid +# conf deconstructed +UB_TOTAL_CONF=$UB_VARDIR/unbound.conf +UB_CORE_CONF=$UB_VARDIR/server.conf.tmp +UB_HOST_CONF=$UB_VARDIR/host.conf.tmp +UB_DHCP_CONF=$UB_VARDIR/dhcp.conf +UB_ZONE_CONF=$UB_VARDIR/zone.conf.tmp +UB_CTRL_CONF=$UB_VARDIR/ctrl.conf.tmp +UB_SRVMASQ_CONF=$UB_VARDIR/dnsmasq_srv.conf.tmp +UB_EXTMASQ_CONF=$UB_VARDIR/dnsmasq_ext.conf.tmp +UB_SRV_CONF=$UB_VARDIR/unbound_srv.conf +UB_EXT_CONF=$UB_VARDIR/unbound_ext.conf -UNBOUND_SRV_CONF=$UNBOUND_VARDIR/unbound_srv.conf -UNBOUND_EXT_CONF=$UNBOUND_VARDIR/unbound_ext.conf -UNBOUND_DHCP_CONF=$UNBOUND_VARDIR/unbound_dhcp.conf -UNBOUND_CONFFILE=$UNBOUND_VARDIR/unbound.conf +# TLS keys +UB_TLS_KEY_FILE="TLS server UCI not implemented" +UB_TLS_PEM_FILE="TLS server UCI not implemented" +UB_TLS_FWD_FILE=$UB_VARDIR/ca-certificates.crt +UB_TLS_ETC_FILE=/etc/ssl/certs/ca-certificates.crt -UNBOUND_KEYFILE=$UNBOUND_VARDIR/root.key -UNBOUND_HINTFILE=$UNBOUND_VARDIR/root.hints -UNBOUND_TIMEFILE=$UNBOUND_VARDIR/hotplug.time +# start files +UB_RKEY_FILE=$UB_VARDIR/root.key +UB_RHINT_FILE=$UB_VARDIR/root.hints +UB_TIME_FILE=$UB_VARDIR/hotplug.time -UNBOUND_CTLKEY_FILE=$UNBOUND_VARDIR/unbound_control.key -UNBOUND_CTLPEM_FILE=$UNBOUND_VARDIR/unbound_control.pem -UNBOUND_SRVKEY_FILE=$UNBOUND_VARDIR/unbound_server.key -UNBOUND_SRVPEM_FILE=$UNBOUND_VARDIR/unbound_server.pem +# control app keys +UB_CTLKEY_FILE=$UB_VARDIR/unbound_control.key +UB_CTLPEM_FILE=$UB_VARDIR/unbound_control.pem +UB_SRVKEY_FILE=$UB_VARDIR/unbound_server.key +UB_SRVPEM_FILE=$UB_VARDIR/unbound_server.pem -############################################################################## +# similar default SOA / NS RR as Unbound uses for private ARPA zones +UB_XSER=$(( $( date +%s ) / 60 )) +UB_XSOA="7200 IN SOA localhost. nobody.invalid. $UB_XSER 3600 1200 9600 600" +UB_XNS="7200 IN NS localhost." +UB_XTXT="7200 IN TXT \"comment=local intranet dns zone\"" +UB_MTXT="7200 IN TXT \"comment=masked internet dns zone\"" +UB_LTXT="7200 IN TXT \"comment=rfc6762 multicast dns zone\"" -UNBOUND_ANCHOR=/usr/sbin/unbound-anchor -UNBOUND_CONTROL=/usr/sbin/unbound-control -UNBOUND_CONTROL_CFG="$UNBOUND_CONTROL -c $UNBOUND_CONFFILE" +# helper apps +UB_ANCHOR=/usr/sbin/unbound-anchor +UB_CONTROL=/usr/sbin/unbound-control +UB_CONTROL_CFG="$UB_CONTROL -c $UB_TOTAL_CONF" ############################################################################## diff --git a/net/unbound/files/dnsmasq.sh b/net/unbound/files/dnsmasq.sh index 32e5f2355..eac2261d8 100644 --- a/net/unbound/files/dnsmasq.sh +++ b/net/unbound/files/dnsmasq.sh @@ -23,6 +23,140 @@ # ############################################################################## +DM_D_WAN_FQDN=0 + +DM_LIST_KNOWN_ZONES="invalid" +DM_LIST_TRN_ZONES="" +DM_LIST_LOCAL_DATA="" +DM_LIST_LOCAL_PTR="" +DM_LIST_FWD_PORTS="" +DM_LIST_FWD_ZONES="" + +############################################################################## + +create_local_zone() { + local target="$1" + local partial domain found + + case $DM_LIST_TRN_ZONES in + *"${target}"*) + found=1 + ;; + + *) + case $target in + [A-Za-z0-9]*.[A-Za-z0-9]*) + found=0 + ;; + + *) # no dots + found=1 + ;; + esac + esac + + + 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 }' ) + DM_LIST_TRN_ZONES="$DM_LIST_TRN_ZONES $partial" + DM_LIST_KNOWN_ZONES="$DM_LIST_KNOWN_ZONES $partial" + fi +} + +############################################################################## + +create_host_record() { + local cfg="$1" + local ip name debug_ip + + # 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.*) + debug_ip="$ip@$host" + ;; + + [1-9a-f]*:*[0-9a-f]) + DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $name.@@300@@IN@@AAAA@@$ip" + DM_LIST_LOCAL_PTR="$DM_LIST_LOCAL_PTR $ip@@300@@$name" + ;; + + [1-9]*.*[0-9]) + DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $name.@@300@@IN@@A@@$ip" + DM_LIST_LOCAL_PTR="$DM_LIST_LOCAL_PTR $ip@@300@@$name" + ;; + esac + fi +} + +############################################################################## + +create_mx_record() { + local cfg="$1" + local domain relay pref record + + # 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" + record="$domain.@@300@@IN@@MX@@$pref@@$relay." + DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record" + fi +} + +############################################################################## + +create_srv_record() { + local cfg="$1" + local srv target port class weight record + + # 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" + record="$srv.@@300@@IN@@SRV@@$class@@$weight@@$port@@$target." + DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record" + fi +} + +############################################################################## + +create_cname_record() { + local cfg="$1" + local cname target record + + # 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" + record="$cname.@@300@@IN@@CNAME@@$target." + DM_LIST_LOCAL_DATA="$DM_LIST_LOCAL_DATA $record" + fi +} + +############################################################################## + dnsmasq_local_zone() { local cfg="$1" local fwd_port fwd_domain wan_fqdn @@ -34,130 +168,127 @@ dnsmasq_local_zone() { if [ -n "$wan_fqdn" ] ; then - UNBOUND_D_WAN_FQDN=$wan_fqdn + DM_D_WAN_FQDN=$wan_fqdn fi + if [ -n "$fwd_domain" -a -n "$fwd_port" -a ! "${fwd_port:-53}" -eq 53 ] ; then # dnsmasq localhost listening ports (possible multiple instances) - UNBOUND_N_FWD_PORTS="$UNBOUND_N_FWD_PORTS $fwd_port" - UNBOUND_TXT_FWD_ZONE="$UNBOUND_TXT_FWD_ZONE $fwd_domain" - - { - # This creates DOMAIN local privledges - echo " private-domain: \"$fwd_domain\"" - echo " local-zone: \"$fwd_domain.\" transparent" - echo " domain-insecure: \"$fwd_domain\"" - echo - } >> $UNBOUND_CONFFILE + DM_LIST_FWD_PORTS="$DM_LIST_FWD_PORTS $fwd_port" + DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $fwd_domain" fi } ############################################################################## dnsmasq_local_arpa() { - local cfg="$1" - local logint dhcpv4 dhcpv6 ignore - local subnets subnets4 subnets6 - local forward arpa - local validip4 validip6 privateip + local ifarpa ifsubnet - config_get logint "$cfg" interface - config_get dhcpv4 "$cfg" dhcpv4 - config_get dhcpv6 "$cfg" dhcpv6 - config_get_bool ignore "$cfg" ignore 0 - # Find the list of addresses assigned to a logical interface - # Its typical to have a logical gateway split NAME and NAME6 - network_get_subnets subnets4 "$logint" - network_get_subnets6 subnets6 "$logint" - subnets="$subnets4 $subnets6" + if [ -n "$UB_LIST_NETW_LAN" ] ; then + for ifsubnet in $UB_LIST_NETW_LAN ; do + ifarpa=$( domain_ptr_any "${ifsubnet#*@}" ) + DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $ifarpa" + done + fi - network_get_subnets subnets4 "${logint}6" - network_get_subnets6 subnets6 "${logint}6" - subnets="$subnets $subnets4 $subnets6" + if [ -n "$UB_LIST_NETW_WAN" -a "$DM_D_WAN_FQDN" -gt 0 ] ; then + for ifsubnet in $UB_LIST_NETW_WAN ; do + ifarpa=$( domain_ptr_any "${ifsubnet#*@}" ) + DM_LIST_FWD_ZONES="$DM_LIST_FWD_ZONES $ifarpa" + done + fi +} - if [ -z "$subnets" ] ; then - forward="" +############################################################################## - elif [ -z "$UNBOUND_N_FWD_PORTS" ] ; then - forward="" +dnsmasq_inactive() { + local record - elif [ "$ignore" -gt 0 ] ; then - if [ "$UNBOUND_D_WAN_FQDN" -gt 0 ] ; then - # Only forward the one gateway host. - forward="host" + if [ "$UB_D_EXTRA_DNS" -gt 0 ] ; then + # Parasite from the uci.dhcp.domain clauses + DM_LIST_KNOWN_ZONES="$DM_LIST_KNOWN_ZONES $UB_TXT_DOMAIN" + config_load dhcp + config_foreach create_host_record domain - else - forward="" - fi - else - # Forward the entire private subnet. - forward="domain" - fi + if [ "$UB_D_EXTRA_DNS" -gt 1 ] ; then + config_foreach create_srv_record srvhost + config_foreach create_mx_record mxhost + fi - if [ -n "$forward" ] ; then - for subnet in $subnets ; do - validip4=$( valid_subnet4 $subnet ) - validip6=$( valid_subnet6 $subnet ) - privateip=$( private_subnet $subnet ) + if [ "$UB_D_EXTRA_DNS" -gt 2 ] ; then + config_foreach create_cname_record cname + fi - if [ "$validip4" = "ok" -a "$dhcpv4" != "disable" ] ; then - if [ "$forward" = "domain" ] ; then - arpa=$( domain_ptr_ip4 "$subnet" ) - else - arpa=$( host_ptr_ip4 "$subnet" ) - fi + { + echo "# $UB_SRVMASQ_CONF generated by UCI $( date -Is )" + if [ -n "$DM_LIST_TRN_ZONES" ] ; then + for record in $DM_LIST_TRN_ZONES ; do + echo " local-zone: $record transparent" + done + echo + fi + if [ -n "$DM_LIST_LOCAL_DATA" ] ; then + for record in $DM_LIST_LOCAL_DATA ; do + echo " local-data: \"${record//@@/ }\"" + done + echo + fi + if [ -n "$DM_LIST_LOCAL_PTR" ] ; then + for record in $DM_LIST_LOCAL_PTR ; do + echo " local-data-ptr: \"${record//@@/ }\"" + done + echo + fi + } > $UB_SRVMASQ_CONF + fi +} - elif [ "$validip6" = "ok" -a "$dhcpv6" != "disable" ] ; then - if [ "$forward" = "domain" ] ; then - arpa=$( domain_ptr_ip6 "$subnet" ) - else - arpa=$( host_ptr_ip6 "$subnet" ) - fi +############################################################################## - else - arpa="" - fi +dnsmasq_active() { + # Look at dnsmasq settings + config_load dhcp + # Zone for DHCP / SLAAC-PING DOMAIN + config_foreach dnsmasq_local_zone dnsmasq + # Zone for DHCP / SLAAC-PING ARPA + dnsmasq_local_arpa - if [ -n "$arpa" ] ; then - if [ "$privateip" = "ok" ] ; then - { - # This creates ARPA local zone privledges - echo " local-zone: \"$arpa.\" transparent" - echo " domain-insecure: \"$arpa\"" - echo - } >> $UNBOUND_CONFFILE - fi + if [ -n "$DM_LIST_FWD_PORTS" -a -n "$DM_LIST_FWD_ZONES" ] ; then + { + # Forward to dnsmasq on same host for DHCP lease hosts + echo "# $UB_SRVMASQ_CONF generated by UCI $( date -Is )" + echo " do-not-query-localhost: no" + echo + } > $UB_SRVMASQ_CONF + echo "# $UB_EXTMASQ_CONF generated by UCI $( date -Is )" > $UB_EXTMASQ_CONF - UNBOUND_TXT_FWD_ZONE="$UNBOUND_TXT_FWD_ZONE $arpa" - fi - done - fi -} -############################################################################## + for fwd_domain in $DM_LIST_FWD_ZONES ; do + { + # This creates a domain with local privledges + echo " domain-insecure: $fwd_domain" + echo " private-domain: $fwd_domain" + echo " local-zone: $fwd_domain transparent" + echo + } >> $UB_SRVMASQ_CONF -dnsmasq_forward_zone() { - if [ -n "$UNBOUND_N_FWD_PORTS" -a -n "$UNBOUND_TXT_FWD_ZONE" ] ; then - for fwd_domain in $UNBOUND_TXT_FWD_ZONE ; do { - # This is derived of dnsmasq_local_zone/arpa - # but forward: clauses need to be seperate + # This is derived from dnsmasq local domain and dhcp service subnets echo "forward-zone:" - echo " name: \"$fwd_domain.\"" - - for port in $UNBOUND_N_FWD_PORTS ; do + echo " name: $fwd_domain" + echo " forward-first: no" + for port in $DM_LIST_FWD_PORTS ; do echo " forward-addr: 127.0.0.1@$port" done - echo - } >> $UNBOUND_CONFFILE + } >> $UB_EXTMASQ_CONF done fi } @@ -165,16 +296,12 @@ dnsmasq_forward_zone() { ############################################################################## dnsmasq_link() { - # Forward to dnsmasq on same host for DHCP lease hosts - echo " do-not-query-localhost: no" >> $UNBOUND_CONFFILE - # Look at dnsmasq settings - config_load dhcp - # Zone for DHCP / SLAAC-PING DOMAIN - config_foreach dnsmasq_local_zone dnsmasq - # Zone for DHCP / SLAAC-PING ARPA - config_foreach dnsmasq_local_arpa dhcp - # Now create ALL seperate forward: clauses - dnsmasq_forward_zone + if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then + dnsmasq_active + + else + dnsmasq_inactive + fi } ############################################################################## diff --git a/net/unbound/files/iptools.sh b/net/unbound/files/iptools.sh index 9985f76d0..c2ec7a06b 100644 --- a/net/unbound/files/iptools.sh +++ b/net/unbound/files/iptools.sh @@ -160,3 +160,25 @@ domain_ptr_any() { ############################################################################## +host_ptr_any() { + local subnet=$1 + local arpa validip4 validip6 + + validip4=$( valid_subnet4 $subnet ) + validip6=$( valid_subnet6 $subnet ) + + + if [ "$validip4" = "ok" ] ; then + arpa=$( host_ptr_ip4 "$subnet" ) + elif [ "$validip6" = "ok" ] ; then + arpa=$( host_ptr_ip6 "$subnet" ) + fi + + + if [ -n "$arpa" ] ; then + echo $arpa + fi +} + +############################################################################## + diff --git a/net/unbound/files/odhcpd.awk b/net/unbound/files/odhcpd.awk index 363f413de..ca0595773 100644 --- a/net/unbound/files/odhcpd.awk +++ b/net/unbound/files/odhcpd.awk @@ -66,15 +66,15 @@ if ( bconf == 1 ) { - x = ( "local-data: \"" fqdn ". 120 IN A " adr "\"" ) ; - y = ( "local-data-ptr: \"" adr " 120 " fqdn "\"" ) ; + x = ( "local-data: \"" fqdn ". 300 IN A " adr "\"" ) ; + y = ( "local-data-ptr: \"" adr " 300 " fqdn "\"" ) ; print ( x "\n" y "\n" ) > hostfile ; } else { for( i=1; i<=4; i++ ) { qpr = ( ptr[i] "." qpr) ; } - x = ( fqdn ". 120 IN A " adr ) ; - y = ( qpr "in-addr.arpa. 120 IN PTR " fqdn ) ; + x = ( fqdn ". 300 IN A " adr ) ; + y = ( qpr "in-addr.arpa. 300 IN PTR " fqdn ) ; print ( x "\n" y ) > hostfile ; } @@ -100,15 +100,15 @@ if ( bconf == 1 ) { - x = ( "local-data: \"" fqdn ". 120 IN AAAA " adr "\"" ) ; - y = ( "local-data-ptr: \"" adr " 120 " fqdn "\"" ) ; + x = ( "local-data: \"" fqdn ". 300 IN AAAA " adr "\"" ) ; + y = ( "local-data-ptr: \"" adr " 300 " fqdn "\"" ) ; print ( x "\n" y "\n" ) > hostfile ; } else { qpr = ipv6_ptr( adr ) ; - x = ( fqdn ". 120 IN AAAA " adr ) ; - y = ( qpr ". 120 IN PTR " fqdn ) ; + x = ( fqdn ". 300 IN AAAA " adr ) ; + y = ( qpr ". 300 IN PTR " fqdn ) ; print ( x "\n" y ) > hostfile ; } } @@ -123,32 +123,32 @@ else { if (( cdr == 128 ) && ( hst != "-" )) { if ( bconf == 1 ) { - x = ( "local-data: \"" fqdn ". 120 IN AAAA " adr "\"" ) ; - y = ( "local-data-ptr: \"" adr " 120 " fqdn "\"" ) ; + x = ( "local-data: \"" fqdn ". 300 IN AAAA " adr "\"" ) ; + y = ( "local-data-ptr: \"" adr " 300 " fqdn "\"" ) ; print ( x "\n" y "\n" ) > hostfile ; } else { # only for provided hostnames and full /128 assignments qpr = ipv6_ptr( adr ) ; - x = ( fqdn ". 120 IN AAAA " adr ) ; - y = ( qpr ". 120 IN PTR " fqdn ) ; + x = ( fqdn ". 300 IN AAAA " adr ) ; + y = ( qpr ". 300 IN PTR " fqdn ) ; print ( x "\n" y ) > hostfile ; } } if (( cdr2 == 128 ) && ( hst != "-" )) { if ( bconf == 1 ) { - x = ( "local-data: \"" fqdn ". 120 IN AAAA " adr2 "\"" ) ; - y = ( "local-data-ptr: \"" adr2 " 120 " fqdn "\"" ) ; + x = ( "local-data: \"" fqdn ". 300 IN AAAA " adr2 "\"" ) ; + y = ( "local-data-ptr: \"" adr2 " 300 " fqdn "\"" ) ; print ( x "\n" y "\n" ) > hostfile ; } else { # odhcp puts GA and ULA on the same line (position 9 and 10) qpr2 = ipv6_ptr( adr2 ) ; - x = ( fqdn ". 120 IN AAAA " adr2 ) ; - y = ( qpr2 ". 120 IN PTR " fqdn ) ; + x = ( fqdn ". 300 IN AAAA " adr2 ) ; + y = ( qpr2 ". 300 IN PTR " fqdn ) ; print ( x "\n" y ) > hostfile ; } } diff --git a/net/unbound/files/odhcpd.sh b/net/unbound/files/odhcpd.sh index 93efa73ad..60c2aabea 100644 --- a/net/unbound/files/odhcpd.sh +++ b/net/unbound/files/odhcpd.sh @@ -30,12 +30,12 @@ odhcpd_zonedata() { local longconf dateconf - local dns_ls_add=$UNBOUND_VARDIR/dhcp_dns.add - local dns_ls_del=$UNBOUND_VARDIR/dhcp_dns.del - local dhcp_ls_new=$UNBOUND_VARDIR/dhcp_lease.new - 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 dns_ls_add=$UB_VARDIR/dhcp_dns.add + local dns_ls_del=$UB_VARDIR/dhcp_dns.del + local dhcp_ls_new=$UB_VARDIR/dhcp_lease.new + local dhcp_ls_old=$UB_VARDIR/dhcp_lease.old + local dhcp_ls_add=$UB_VARDIR/dhcp_lease.add + local dhcp_ls_del=$UB_VARDIR/dhcp_lease.del local dhcp_link=$( uci_get unbound.@unbound[0].dhcp_link ) local dhcp4_slaac6=$( uci_get unbound.@unbound[0].dhcp4_slaac6 ) @@ -43,18 +43,17 @@ odhcpd_zonedata() { local dhcp_origin=$( uci_get dhcp.@odhcpd[0].leasefile ) - if [ "$dhcp_link" = "odhcpd" \ - -a -f "$dhcp_origin" \ - -a -n "$dhcp_domain" ] ; then + if [ -f "$UB_TIME_FILE" -a "$dhcp_link" = "odhcpd" \ + -a -f "$dhcp_origin" -a -n "$dhcp_domain" ] ; then # Capture the lease file which could be changing often sort $dhcp_origin > $dhcp_ls_new - if [ ! -f $UNBOUND_DHCP_CONF -o ! -f $dhcp_ls_old ] ; then + if [ ! -f $UB_DHCP_CONF -o ! -f $dhcp_ls_old ] ; then longconf=2 else - dateconf=$(( $( date +%s ) - $( date -r $UNBOUND_DHCP_CONF +%s ) )) + dateconf=$(( $( date +%s ) - $( date -r $UB_DHCP_CONF +%s ) )) if [ $dateconf > 150 ] ; then @@ -68,7 +67,7 @@ odhcpd_zonedata() { if [ $longconf -gt 0 ] ; then # Go through the messy business of coding up A, AAAA, and PTR records # This static conf will be available if Unbound restarts asynchronously - awk -v hostfile=$UNBOUND_DHCP_CONF -v domain=$dhcp_domain \ + awk -v hostfile=$UB_DHCP_CONF -v domain=$dhcp_domain \ -v bslaac=$dhcp4_slaac6 -v bisolt=0 -v bconf=1 \ -f /usr/lib/unbound/odhcpd.awk $dhcp_ls_new fi @@ -95,12 +94,12 @@ odhcpd_zonedata() { if [ -f "$dns_ls_del" ] ; then - cat $dns_ls_del | $UNBOUND_CONTROL_CFG local_datas_remove + cat $dns_ls_del | $UB_CONTROL_CFG local_datas_remove fi if [ -f "$dns_ls_add" ] ; then - cat $dns_ls_add | $UNBOUND_CONTROL_CFG local_datas + cat $dns_ls_add | $UB_CONTROL_CFG local_datas fi diff --git a/net/unbound/files/rootzone.sh b/net/unbound/files/stopping.sh similarity index 73% rename from net/unbound/files/rootzone.sh rename to net/unbound/files/stopping.sh index cc2edf695..5bec1b979 100644 --- a/net/unbound/files/rootzone.sh +++ b/net/unbound/files/stopping.sh @@ -19,6 +19,10 @@ # ############################################################################## +. /usr/lib/unbound/defaults.sh + +############################################################################## + roothints_update() { # TODO: Might not be implemented. Unbound doesn't natively update hints. # Unbound philosophy is built in root hints are good for machine life. @@ -29,17 +33,21 @@ roothints_update() { rootkey_update() { local basekey_date rootkey_date rootkey_age filestuff - local dnssec=$( uci_get unbound.@unbound[0].validator ) local dnssec_ntp=$( uci_get unbound.@unbound[0].validator_ntp ) local dnssec_age=$( uci_get unbound.@unbound[0].root_age ) + # fix empty + [ -z "$dnssec" ] && dnssec=0 + [ -z "$dnssec_ntp" ] && dnssec_ntp=1 + [ -z "$dnssec_age" ] && dnssec_age=9 + if [ "$dnssec_age" -gt 90 -o "$dnssec" -lt 1 ] ; then # Feature disabled return 0 - elif [ "$dnssec_ntp" -gt 0 -a ! -f "$UNBOUND_TIMEFILE" ] ; then + elif [ "$dnssec_ntp" -gt 0 -a ! -f "$UB_TIME_FILE" ] ; then # We don't have time yet return 0 fi @@ -54,16 +62,16 @@ rootkey_update() { fi - if [ -f "$UNBOUND_KEYFILE" ] ; then + if [ -f "$UB_RKEY_FILE" ] ; then # Unbound maintains it itself - rootkey_date=$( date -r $UNBOUND_KEYFILE +%s ) + rootkey_date=$( date -r $UB_RKEY_FILE +%s ) rootkey_age=$(( (rootkey_date - basekey_date) / 86440 )) - elif [ -x "$UNBOUND_ANCHOR" ] ; then + elif [ -x "$UB_ANCHOR" ] ; then # No tmpfs key - use unbound-anchor rootkey_date=$( date -I +%s ) rootkey_age=$(( (rootkey_date - basekey_date) / 86440 )) - $UNBOUND_ANCHOR -a $UNBOUND_KEYFILE + $UB_ANCHOR -a $UB_RKEY_FILE else # give up @@ -72,20 +80,20 @@ rootkey_update() { if [ "$rootkey_age" -gt "$dnssec_age" ] ; then - filestuff=$( cat $UNBOUND_KEYFILE ) + filestuff=$( cat $UB_RKEY_FILE ) 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 + cp -p $UB_RKEY_FILE /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 + cp -p $UB_RKEY_FILE /etc/unbound/root.key ;; *) @@ -97,7 +105,20 @@ rootkey_update() { ############################################################################## -rootzone_update() { +resolv_teardown() { + case $( cat /tmp/resolv.conf ) in + *"generated by Unbound UCI"*) + # our resolver file, reset to auto resolver file. + rm -f /tmp/resolv.conf + ln -s /tmp/resolv.conf.auto /tmp/resolv.conf + ;; + esac +} + +############################################################################## + +unbound_stop() { + resolv_teardown roothints_update rootkey_update } diff --git a/net/unbound/files/unbound.init b/net/unbound/files/unbound.init index 2f93b4d65..f12e6831c 100755 --- a/net/unbound/files/unbound.init +++ b/net/unbound/files/unbound.init @@ -17,14 +17,14 @@ PROG=/usr/sbin/unbound ############################################################################## boot() { - UNBOUND_BOOT=1 + UB_BOOT=1 start "$@" } ############################################################################## start_service() { - if [ -n "$UNBOUND_BOOT" ] ; then + if [ -n "$UB_BOOT" ] ; then # Load procd triggers (rc) and use event IFUP to really start return 0 fi @@ -35,7 +35,7 @@ start_service() { # standard procd clause procd_open_instance "unbound" - procd_set_param command $PROG -d -c $UNBOUND_CONFFILE + procd_set_param command $PROG -d -c $UB_TOTAL_CONF procd_set_param respawn procd_close_instance } @@ -44,7 +44,7 @@ start_service() { stop_service() { # clean up - . /usr/lib/unbound/unbound.sh + . /usr/lib/unbound/stopping.sh unbound_stop # Wait! on restart Unbound may take time writing closure stats to syslog diff --git a/net/unbound/files/unbound.ntpd b/net/unbound/files/unbound.ntpd index d744cb067..d9d0deefa 100755 --- a/net/unbound/files/unbound.ntpd +++ b/net/unbound/files/unbound.ntpd @@ -13,12 +13,12 @@ ############################################################################## # Common file location definitions -. /usr/lib/unbound/unbound.sh +. /usr/lib/unbound/defaults.sh ############################################################################## -if [ "$ACTION" = stratum -a ! -f "$UNBOUND_TIMEFILE" ] ; then - echo "ntpd: $( date )" > $UNBOUND_TIMEFILE +if [ ! -f "$UB_TIME_FILE" -a "$ACTION" = stratum ] ; then + date -Is > $UB_TIME_FILE /etc/init.d/unbound enabled && /etc/init.d/unbound restart # Yes, hard RESTART. We need to be absolutely sure to enable DNSSEC. fi diff --git a/net/unbound/files/unbound.sh b/net/unbound/files/unbound.sh index a1f328e57..798b4e353 100644 --- a/net/unbound/files/unbound.sh +++ b/net/unbound/files/unbound.sh @@ -23,58 +23,51 @@ # ############################################################################## -UNBOUND_B_SLAAC6_MAC=0 -UNBOUND_B_DNSSEC=0 -UNBOUND_B_DNS64=0 -UNBOUND_B_EXT_STATS=0 -UNBOUND_B_GATE_NAME=0 -UNBOUND_B_HIDE_BIND=1 -UNBOUND_B_LOCL_BLCK=0 -UNBOUND_B_LOCL_SERV=1 -UNBOUND_B_MAN_CONF=0 -UNBOUND_B_NTP_BOOT=1 -UNBOUND_B_QUERY_MIN=0 -UNBOUND_B_QRY_MINST=0 -UNBOUND_B_AUTH_ROOT=0 - -UNBOUND_D_CONTROL=0 -UNBOUND_D_DOMAIN_TYPE=static -UNBOUND_D_DHCP_LINK=none -UNBOUND_D_EXTRA_DNS=0 -UNBOUND_D_LAN_FQDN=0 -UNBOUND_D_PRIV_BLCK=1 -UNBOUND_D_PROTOCOL=mixed -UNBOUND_D_RESOURCE=small -UNBOUND_D_RECURSION=passive -UNBOUND_D_WAN_FQDN=0 - -UNBOUND_IP_DNS64="64:ff9b::/96" - -UNBOUND_N_EDNS_SIZE=1280 -UNBOUND_N_FWD_PORTS="" -UNBOUND_N_RX_PORT=53 -UNBOUND_N_ROOT_AGE=9 - -UNBOUND_TTL_MIN=120 - -UNBOUND_TXT_DOMAIN=lan -UNBOUND_TXT_FWD_ZONE="" -UNBOUND_TXT_HOSTNAME=thisrouter - -UNBOUND_LIST_FORWARD="" -UNBOUND_LIST_INSECURE="" +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_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_TTL_MIN=120 +UB_TXT_DOMAIN=lan +UB_TXT_HOSTNAME=thisrouter ############################################################################## # keep track of assignments during inserted resource records -UNBOUND_LIST_DOMAINS="" -UNBOUND_LIST_IFACE="" -UNBOUND_LIST_PRV_IP6GLA="" -UNBOUND_LIST_LAN_NET="" - -# Similar default SOA / NS RR as Unbound uses for private ARPA zones -UNBOUND_XSOA="3600 IN SOA localhost. nobody.invalid. 1 3600 1200 7200 600" -UNBOUND_XNS="3600 IN NS localhost." +UB_LIST_NETW_ALL="" +UB_LIST_NETW_LAN="" +UB_LIST_NETW_WAN="" +UB_LIST_INSECURE="" +UB_LIST_ZONE_SERVERS="" +UB_LIST_ZONE_NAMES="" ############################################################################## @@ -84,342 +77,103 @@ UNBOUND_XNS="3600 IN NS localhost." . /usr/lib/unbound/defaults.sh . /usr/lib/unbound/dnsmasq.sh . /usr/lib/unbound/iptools.sh -. /usr/lib/unbound/rootzone.sh ############################################################################## -create_interface_dns() { +bundle_all_networks() { local cfg="$1" - local ipcommand logint ignore ifname ifdashname - local name names address addresses - local ulaprefix if_fqdn host_fqdn - local mode_ptr="$UNBOUND_TXT_HOSTNAME" - local names="$UNBOUND_TXT_HOSTNAME" - - # Create local-data: references for this hosts interfaces (router). - config_get logint "$cfg" interface - config_get_bool ignore "$cfg" ignore 0 - network_get_device ifname "$cfg" - - ifdashname="${ifname//./-}" - ipcommand="ip -o address show $ifname" - 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" - - - if [ -z "$ifdashname" ] ; then - # race conditions at init can rarely cause a blank device return - # the record format is invalid and Unbound won't load the conf file - mode=0 - - elif [ -n "$UNBOUND_LIST_IFACE" ] ; then - case "$UNBOUND_LIST_IFACE" in - *$ifdashname*) - # repeat such as dual WAN (eth0-1) and WAN6 (eth0-1) - mode=0 - ;; - - *) - mode=1 - ;; - esac - - else - mode=1 - fi - - - if [ $mode -gt 0 ] ; then - UNBOUND_LIST_IFACE="$UNBOUND_LIST_IFACE $ifdashname" - - - if [ -z "${ulaprefix%%:/*}" ] ; then - # Nonsense so this option isn't globbed below - ulaprefix="fdno:such:addr::/48" - fi - - - if [ "$ignore" -gt 0 ] ; then - mode="$UNBOUND_D_WAN_FQDN" - else - mode="$UNBOUND_D_LAN_FQDN" - fi - fi - - - if [ "$mode" -gt 1 ] ; then - case "$mode" in - 3) - mode_ptr="$host_fqdn" - names="$host_fqdn $UNBOUND_TXT_HOSTNAME" - ;; - - 4) - mode_ptr="$if_fqdn" - names="$if_fqdn $host_fqdn $UNBOUND_TXT_HOSTNAME" - ;; - esac - - - { - for address in $addresses ; do - case $address in - fe80:*|169.254.*) - echo " # note link address $address" - ;; - - [1-9a-f]*:*[0-9a-f]) - # GA and ULA IP6 for HOST IN AAA records (ip command is robust) - for name in $names ; do - echo " local-data: \"$name. 120 IN AAAA $address\"" - done - echo " local-data-ptr: \"$address 120 $mode_ptr\"" - ;; - - [1-9]*.*[0-9]) - # Old fashioned HOST IN A records - for name in $names ; do - echo " local-data: \"$name. 120 IN A $address\"" - done - echo " local-data-ptr: \"$address 120 $mode_ptr\"" - ;; - esac - done - echo - } >> $UNBOUND_CONFFILE - - elif [ "$mode" -gt 0 ] ; then - { - for address in $addresses ; do - case $address in - fe80:*|169.254.*) - echo " # note link address $address" - ;; - - "${ulaprefix%%:/*}"*) - # Only this networks ULA and only hostname - echo " local-data: \"$UNBOUND_TXT_HOSTNAME. 120 IN AAAA $address\"" - echo " local-data-ptr: \"$address 120 $UNBOUND_TXT_HOSTNAME\"" - ;; - - [1-9]*.*[0-9]) - echo " local-data: \"$UNBOUND_TXT_HOSTNAME. 120 IN A $address\"" - echo " local-data-ptr: \"$address 120 $UNBOUND_TXT_HOSTNAME\"" - ;; - esac - done - echo - } >> $UNBOUND_CONFFILE - fi -} + local ifname ifdashname + local subnet subnets subnets4 subnets6 + local validip4 validip6 -############################################################################## + network_get_subnets subnets4 "$cfg" + network_get_subnets6 subnets6 "$cfg" + network_get_device ifname "$cfg" -create_local_zone() { - local target="$1" - local partial domain found + ifdashname="${ifname//./-}" + subnets="$subnets4 $subnets6" - if [ -n "$UNBOUND_LIST_DOMAINS" ] ; then - for domain in $UNBOUND_LIST_DOMAINS ; do - case $target in - *"${domain}") - found=1 - break - ;; + if [ -n "$subnets" ] ; then + for subnet in $subnets ; do + validip4=$( valid_subnet4 $subnet ) + validip6=$( valid_subnet6 $subnet ) - [A-Za-z0-9]*.[A-Za-z0-9]*) - found=0 - ;; - *) # no dots - found=1 - break - ;; - esac + if [ "$validip4" = "ok" -o "$validip6" = "ok" ] ; then + UB_LIST_NETW_ALL="$UB_LIST_NETW_ALL $ifdashname@$subnet" + fi 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() { +bundle_lan_networks() { 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 - + local ifsubnet ifname ifdashname ignore - 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" - ;; + config_get_bool ignore "$cfg" ignore 0 + network_get_device ifname "$cfg" + ifdashname="${ifname//./-}" - [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\"" - ;; + if [ "$ignore" -eq 0 -a -n "$ifdashname" -a -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 as a catagory + UB_LIST_NETW_LAN="$UB_LIST_NETW_LAN $ifsubnet" + ;; 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 + done fi } ############################################################################## -create_srv_record() { - local cfg="$1" - local srv target port class weight +bundle_wan_networks() { + local ifsubnet - # 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 "$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 ... + ;; - 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 + *) + UB_LIST_NETW_WAN="$UB_LIST_NETW_WAN $ifsubnet" + ;; + esac + done 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 +bundle_resolv_conf_servers() { + local resolvers=$( awk '/nameserver/ { print $2 }' /tmp/resolv.conf.auto ) + UB_LIST_ZONE_SERVERS="$UB_LIST_ZONE_SERVERS $resolvers" } ############################################################################## -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 +bundle_zone_names() { + UB_LIST_ZONE_NAMES="$UB_LIST_ZONE_NAMES $1" } ############################################################################## -bundle_domain_forward() { - UNBOUND_LIST_FORWARD="$UNBOUND_LIST_FORWARD $1" +bundle_zone_servers() { + UB_LIST_ZONE_SERVERS="$UB_LIST_ZONE_SERVERS $1" } ############################################################################## bundle_domain_insecure() { - UNBOUND_LIST_INSECURE="$UNBOUND_LIST_INSECURE $1" -} - -############################################################################## - -bundle_private_interface() { - local ipcommand ifsubnet ifsubnets ifname validip4 - - network_get_device ifname $1 - - - if [ -n "$ifname" ] ; then - ipcommand="ip -o address show $ifname" - ifsubnets=$( $ipcommand | awk '/inet/{ print $4 }' ) - - - if [ -n "$ifsubnets" ] ; then - for ifsubnet in $ifsubnets ; do - case $ifsubnet in - [1-9][0-9a-f][0-9a-f][0-9a-f]:*[0-9a-f]) - # Special GLA protection for local block; ULA protected as a catagory - UNBOUND_LIST_PRV_IP6GLA="$UNBOUND_LIST_PRV_IP6GLA $ifsubnet" - ;; - - f[dc][0-9a-f][0-9a-f]:*[0-9a-f]) - # Used to configure specific local-zone: data - UNBOUND_LIST_LAN_NET="$UNBOUND_LIST_LAN_NET $ifsubnet" - ;; - - *) - validip4=$( valid_subnet4 $ifsubnet ) - - - if [ "$validip4" = "ok" ] ; then - UNBOUND_LIST_LAN_NET="$UNBOUND_LIST_LAN_NET $ifsubnet" - fi - ;; - esac - done - fi - fi + UB_LIST_INSECURE="$UB_LIST_INSECURE $1" } ############################################################################## @@ -428,7 +182,7 @@ unbound_mkdir() { local filestuff - if [ "$UNBOUND_D_DHCP_LINK" = "odhcpd" ] ; then + if [ "$UB_D_DHCP_LINK" = "odhcpd" ] ; then local dhcp_origin=$( uci_get dhcp.@odhcpd[0].leasefile ) local dhcp_dir=$( dirname $dhcp_origin ) @@ -440,250 +194,341 @@ unbound_mkdir() { fi - if [ -f $UNBOUND_KEYFILE ] ; then - filestuff=$( cat $UNBOUND_KEYFILE ) + 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 $UNBOUND_KEYFILE $UNBOUND_KEYFILE.keep + cp -p $UB_RKEY_FILE $UB_RKEY_FILE.keep ;; esac fi - # Blind copy /etc/ to /var/lib/ - mkdir -p $UNBOUND_VARDIR - rm -f $UNBOUND_VARDIR/dhcp_* - touch $UNBOUND_CONFFILE - touch $UNBOUND_SRV_CONF - touch $UNBOUND_EXT_CONF - cp -p /etc/unbound/* $UNBOUND_VARDIR/ + # 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 $UNBOUND_HINTFILE ] ; then + 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 $UNBOUND_HINTFILE + cp -p /usr/share/dns/root.hints $UB_RHINT_FILE - elif [ ! -f "$UNBOUND_TIMEFILE" ] ; then - logger -t unbound -s "default root hints (built in rootservers.net)" + elif [ ! -f "$UB_TIME_FILE" ] ; then + logger -t unbound -s "default root hints (built in root-servers.net)" fi fi - if [ ! -f $UNBOUND_KEYFILE ] ; then + 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 $UNBOUND_KEYFILE + cp -p /usr/share/dns/root.key $UB_RKEY_FILE - elif [ -x $UNBOUND_ANCHOR ] ; then - $UNBOUND_ANCHOR -a $UNBOUND_KEYFILE + elif [ -x $UB_ANCHOR ] ; then + $UB_ANCHOR -a $UB_RKEY_FILE - elif [ ! -f "$UNBOUND_TIMEFILE" ] ; then + elif [ ! -f "$UB_TIME_FILE" ] ; then logger -t unbound -s "default trust anchor (built in root DS record)" fi fi - if [ -f $UNBOUND_KEYFILE.keep ] ; then + if [ -f $UB_RKEY_FILE.keep ] ; then # root.key.keep is reused if newest - cp -u $UNBOUND_KEYFILE.keep $UNBOUND_KEYFILE - rm -f $UNBOUND_KEYFILE.keep + 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 $UNBOUND_VARDIR - chmod 755 $UNBOUND_VARDIR - chmod 644 $UNBOUND_VARDIR/* + chown -R unbound:unbound $UB_VARDIR + chmod 755 $UB_VARDIR + chmod 644 $UB_VARDIR/* - if [ -f $UNBOUND_CTLKEY_FILE -o -f $UNBOUND_CTLPEM_FILE \ - -o -f $UNBOUND_SRVKEY_FILE -o -f $UNBOUND_SRVPEM_FILE ] ; then + if [ -f $UB_CTLKEY_FILE -o -f $UB_CTLPEM_FILE \ + -o -f $UB_SRVKEY_FILE -o -f $UB_SRVPEM_FILE ] ; then # Keys (some) exist already; do not create new ones - chmod 640 $UNBOUND_CTLKEY_FILE $UNBOUND_CTLPEM_FILE \ - $UNBOUND_SRVKEY_FILE $UNBOUND_SRVPEM_FILE + chmod 640 $UB_CTLKEY_FILE $UB_CTLPEM_FILE \ + $UB_SRVKEY_FILE $UB_SRVPEM_FILE elif [ -x /usr/sbin/unbound-control-setup ] ; then - case "$UNBOUND_D_CONTROL" in - [2-3]) - # unbound-control-setup for encrypt opt. 2 and 3, but not 4 "static" - /usr/sbin/unbound-control-setup -d $UNBOUND_VARDIR + 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 $UNBOUND_CTLKEY_FILE $UNBOUND_CTLPEM_FILE \ - $UNBOUND_SRVKEY_FILE $UNBOUND_SRVPEM_FILE + chown -R unbound:unbound $UB_CTLKEY_FILE $UB_CTLPEM_FILE \ + $UB_SRVKEY_FILE $UB_SRVPEM_FILE - chmod 640 $UNBOUND_CTLKEY_FILE $UNBOUND_CTLPEM_FILE \ - $UNBOUND_SRVKEY_FILE $UNBOUND_SRVPEM_FILE + chmod 640 $UB_CTLKEY_FILE $UB_CTLPEM_FILE \ + $UB_SRVKEY_FILE $UB_SRVPEM_FILE - cp -p $UNBOUND_CTLKEY_FILE /etc/unbound/unbound_control.key - cp -p $UNBOUND_CTLPEM_FILE /etc/unbound/unbound_control.pem - cp -p $UNBOUND_SRVKEY_FILE /etc/unbound/unbound_server.key - cp -p $UNBOUND_SRVPEM_FILE /etc/unbound/unbound_server.pem - ;; + 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 [ "$UB_B_NTP_BOOT" -eq 0 ] ; then + # time is considered okay on this device (skip /etc/hotplug/ntpd/unbound) + date -Is > $UB_TIME_FILE + fi } ############################################################################## unbound_control() { - if [ "$UNBOUND_D_CONTROL" -gt 1 ] ; then - if [ ! -f $UNBOUND_CTLKEY_FILE -o ! -f $UNBOUND_CTLPEM_FILE \ - -o ! -f $UNBOUND_SRVKEY_FILE -o ! -f $UNBOUND_SRVPEM_FILE ] ; then + echo "# $UB_CTRL_CONF generated by UCI $( date -Is )" > $UB_CTRL_CONF + + + if [ "$UB_D_CONTROL" -gt 1 ] ; then + if [ ! -f $UB_CTLKEY_FILE -o ! -f $UB_CTLPEM_FILE \ + -o ! -f $UB_SRVKEY_FILE -o ! -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. - UNBOUND_D_CONTROL=0 + UB_D_CONTROL=0 fi fi - case "$UNBOUND_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 - } >> $UNBOUND_CONFFILE - ;; + 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: $UNBOUND_SRVKEY_FILE" - echo " server-cert-file: $UNBOUND_SRVPEM_FILE" - echo " control-key-file: $UNBOUND_CTLKEY_FILE" - echo " control-cert-file: $UNBOUND_CTLPEM_FILE" - echo - } >> $UNBOUND_CONFFILE - ;; + 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: $UNBOUND_SRVKEY_FILE" - echo " server-cert-file: $UNBOUND_SRVPEM_FILE" - echo " control-key-file: $UNBOUND_CTLKEY_FILE" - echo " control-cert-file: $UNBOUND_CTLPEM_FILE" - echo - } >> $UNBOUND_CONFFILE - ;; + [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 - - - { - # Amend your own extended clauses here like forward zones or disable - # above (local, no encryption) and amend your own remote encrypted control - echo - echo "include: $UNBOUND_EXT_CONF" >> $UNBOUND_CONFFILE - echo - } >> $UNBOUND_CONFFILE } ############################################################################## -unbound_forward() { - local fdomain fresolver resolvers - # Forward selected domains to the upstream (WAN) stub resolver. This may be - # faster or local pool addresses to ISP service login page. This may keep - # internal organization lookups, well, internal to the organization. +unbound_zone() { + local cfg=$1 + local zone_sym zone_name zone_type zone_enabled zone_file + local tls_upstream fallback proivder + 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 - if [ -n "$UNBOUND_LIST_FORWARD" ] ; then - resolvers=$( grep nameserver /tmp/resolv.conf.auto | sed "s/nameserver//g" ) + config_get_bool zone_enabled "$cfg" enabled 0 - if [ -n "$resolvers" ] ; then - for fdomain in $UNBOUND_LIST_FORWARD ; do - { - echo "forward-zone:" - echo " name: $fdomain" - for fresolver in $resolvers ; do - echo " forward-addr: $fresolver" - done - echo - } >> $UNBOUND_CONFFILE - done + + 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 -} -############################################################################## -unbound_auth_root() { - local axfrservers="lax.xfr.dns.icann.org iad.xfr.dns.icann.org" - local httpserver="http://www.internic.net/domain/" - local authzones="root arpa in-addr.arpa ip6.arpa" - local server zone realzone - # Download or AXFR the root and arpa zones to reduce the work needed at - # top level of recursion. If your users will hit many ccTLD or you have - # tracking logs resolving many PTR, then this can speed things up. - # Total size of text in TMPFS could be about 5MB. - - - if [ "$UNBOUND_B_AUTH_ROOT" -gt 0 ] ; then - for zone in $authzones ; do - if [ "$zone" = "root" ] ; then - realzone="." - else - realzone=$zone + case $zone_type in + auth_zone) + if [ -n "$UB_LIST_ZONE_NAMES" ] \ + && [ -n "$url_dir" -o -n "$UB_LIST_ZONE_SERVERS" ] ; then + 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 -a "$tls_upstream" = "yes" ] ; then + logger -p 4 -t unbound -s \ + "Forward-zone TLS benefits from authentication in package 'ca-bundle'" fi - { - echo "auth-zone:" - echo " name: $realzone" - for server in $axfrservers ; do - echo " master: $server" + if [ -n "$UB_LIST_ZONE_NAMES" -a -n "$UB_LIST_ZONE_SERVERS" ] ; then + 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 $UB_LIST_ZONE_SERVERS ; do + if [ "$tls_upstream" = "yes" ] ; then + echo " forward-addr: $server${tls_suffix}" + else + echo " forward-addr: $server${port:+@${port}}" + fi + done + echo " forward-first: $fallback" + echo " forward-tls-upstream: $tls_upstream" + echo + } >> $UB_ZONE_CONF done - echo " url: $httpserver$zone.zone" - echo " fallback-enabled: yes" - echo " for-downstream: no" - echo " for-upstream: yes" - echo " zonefile: $zone.zone" - echo - } >> $UNBOUND_CONFFILE - done - fi + fi + ;; + + stub_zone) + if [ -n "$UB_LIST_ZONE_NAMES" -a -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 modulestring domain ifsubnet - - # Make fresh conf file - echo > $UNBOUND_CONFFILE - + local rt_mem rt_conn rt_buff modulestring domain ifsubnet nsubnet { - # Make fresh conf file - echo "# $UNBOUND_CONFFILE generated by UCI $( date )" - echo + # server: for this whole function + echo "# $UB_CORE_CONF generated by UCI $( date -Is )" echo "server:" echo " username: unbound" - echo " chroot: $UNBOUND_VARDIR" - echo " directory: $UNBOUND_VARDIR" - echo " pidfile: $UNBOUND_PIDFILE" - echo + 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 -a -f "$UB_RKEY_FILE" ] ; then + { + echo " auto-trust-anchor-file: $UB_RKEY_FILE" + echo + } >> $UB_CORE_CONF + + else + echo >> $UB_CORE_CONF + fi + + + { # No threading echo " num-threads: 1" echo " msg-cache-slabs: 1" @@ -691,82 +536,112 @@ unbound_conf() { echo " infra-cache-slabs: 1" echo " key-cache-slabs: 1" echo - # Interface Wildcard (access contol handled by "option local_service") - echo " interface: 0.0.0.0" - echo " interface: ::0" - echo " outgoing-interface: 0.0.0.0" - echo " outgoing-interface: ::0" - echo # Logging echo " use-syslog: yes" - echo " verbosity: 1" echo " statistics-interval: 0" echo " statistics-cumulative: no" - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF + + if [ "$UB_D_VERBOSE" -ge 0 -a "$UB_D_VERBOSE" -le 5 ] ; then + echo " verbosity: $UB_D_VERBOSE" >> $UB_CORE_CONF + fi - if [ "$UNBOUND_B_EXT_STATS" -gt 0 ] ; then + + if [ "$UB_B_EXT_STATS" -gt 0 ] ; then { # Log More echo " extended-statistics: yes" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF else { # Log Less echo " extended-statistics: no" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF fi - case "$UNBOUND_D_PROTOCOL" in + 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 " interface: ::0" + echo " outgoing-interface: 0.0.0.0" echo " do-ip4: yes" echo " do-ip6: no" - } >> $UNBOUND_CONFFILE + 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.0.0.0" + echo " interface: ::0" + echo " outgoing-interface: ::0" echo " do-ip4: no" echo " do-ip6: yes" - } >> $UNBOUND_CONFFILE + 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" - } >> $UNBOUND_CONFFILE + 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" - } >> $UNBOUND_CONFFILE + echo + } >> $UB_CORE_CONF ;; *) - if [ ! -f "$UNBOUND_TIMEFILE" ] ; then + if [ ! -f "$UB_TIME_FILE" ] ; then logger -t unbound -s "default protocol configuration" fi - ;; - esac - { - # 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 + { + # 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 { @@ -778,35 +653,18 @@ unbound_conf() { echo " harden-referral-path: no" echo " use-caps-for-id: no" echo - } >> $UNBOUND_CONFFILE - - - if [ -f "$UNBOUND_HINTFILE" ] ; then - # Optional hints if found - echo " root-hints: $UNBOUND_HINTFILE" >> $UNBOUND_CONFFILE - fi - + } >> $UB_CORE_CONF - 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 + case "$UB_D_RESOURCE" in # Tiny - Unbound's recommended cheap hardware config - tiny) rt_mem=1 ; rt_conn=1 ;; + tiny) rt_mem=1 ; rt_conn=2 ; rt_buff=1 ;; # Small - Half RRCACHE and open ports - small) rt_mem=8 ; rt_conn=5 ;; + small) rt_mem=8 ; rt_conn=10 ; rt_buff=2 ;; # Medium - Nearly default but with some added balancintg - medium) rt_mem=16 ; rt_conn=10 ;; + medium) rt_mem=16 ; rt_conn=20 ; rt_buff=4 ;; # Large - Double medium - large) rt_mem=32 ; rt_conn=10 ;; + large) rt_mem=32 ; rt_conn=40 ; rt_buff=4 ;; # Whatever unbound does *) rt_mem=0 ; rt_conn=0 ;; esac @@ -815,6 +673,7 @@ unbound_conf() { if [ "$rt_mem" -gt 0 ] ; then { # Set memory sizing parameters + echo " msg-buffer-size: $(($rt_buff*8192))" echo " outgoing-range: $(($rt_conn*64))" echo " num-queries-per-thread: $(($rt_conn*32))" echo " outgoing-num-tcp: $(($rt_conn))" @@ -825,9 +684,9 @@ unbound_conf() { echo " neg-cache-size: $(($rt_mem*64))k" echo " infra-cache-numhosts: $(($rt_mem*256))" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF - elif [ ! -f "$UNBOUND_TIMEFILE" ] ; then + elif [ ! -f "$UB_TIME_FILE" ] ; then logger -t unbound -s "default memory configuration" fi @@ -836,10 +695,10 @@ unbound_conf() { modulestring="iterator" - if [ "$UNBOUND_B_DNSSEC" -gt 0 ] ; then - if [ ! -f "$UNBOUND_TIMEFILE" -a "$UNBOUND_B_NTP_BOOT" -gt 0 ] ; then + if [ "$UB_B_DNSSEC" -gt 0 ] ; then + if [ ! -f "$UB_TIME_FILE" -a "$UB_B_NTP_BOOT" -gt 0 ] ; then # DNSSEC chicken and egg with getting NTP time - echo " val-override-date: -1" >> $UNBOUND_CONFFILE + echo " val-override-date: -1" >> $UB_CORE_CONF fi @@ -847,15 +706,15 @@ unbound_conf() { echo " harden-dnssec-stripped: yes" echo " val-clean-additional: yes" echo " ignore-cd-flag: yes" - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF modulestring="validator $modulestring" fi - if [ "$UNBOUND_B_DNS64" -gt 0 ] ; then - echo " dns64-prefix: $UNBOUND_IP_DNS64" >> $UNBOUND_CONFFILE + if [ "$UB_B_DNS64" -gt 0 ] ; then + echo " dns64-prefix: $UB_IP_DNS64" >> $UB_CORE_CONF modulestring="dns64 $modulestring" fi @@ -865,24 +724,24 @@ unbound_conf() { # Print final module string echo " module-config: \"$modulestring\"" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF - case "$UNBOUND_D_RECURSION" in + case "$UB_D_RECURSION" in passive) { # Some query privacy but "strict" will break some servers - if [ "$UNBOUND_B_QRY_MINST" -gt 0 \ - -a "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then + if [ "$UB_B_QRY_MINST" -gt 0 \ + -a "$UB_B_QUERY_MIN" -gt 0 ] ; then echo " qname-minimisation: yes" echo " qname-minimisation-strict: yes" - elif [ "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then + 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 [ "$UNBOUND_B_DNSSEC" -gt 0 ] ; then + if [ "$UB_B_DNSSEC" -gt 0 ] ; then echo " aggressive-nsec: yes" echo " prefetch-key: no" fi @@ -890,23 +749,23 @@ unbound_conf() { echo " prefetch: no" echo " target-fetch-policy: \"0 0 0 0 0\"" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF ;; aggressive) { # Some query privacy but "strict" will break some servers - if [ "$UNBOUND_B_QRY_MINST" -gt 0 \ - -a "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then + if [ "$UB_B_QRY_MINST" -gt 0 \ + -a "$UB_B_QUERY_MIN" -gt 0 ] ; then echo " qname-minimisation: yes" echo " qname-minimisation-strict: yes" - elif [ "$UNBOUND_B_QUERY_MIN" -gt 0 ] ; then + 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 [ "$UNBOUND_B_DNSSEC" -gt 0 ] ; then + if [ "$UB_B_DNSSEC" -gt 0 ] ; then echo " aggressive-nsec: yes" echo " prefetch-key: yes" fi @@ -914,11 +773,11 @@ unbound_conf() { echo " prefetch: yes" echo " target-fetch-policy: \"3 2 1 0 0\"" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF ;; *) - if [ ! -f "$UNBOUND_TIMEFILE" ] ; then + if [ ! -f "$UB_TIME_FILE" ] ; then logger -t unbound -s "default recursion configuration" fi ;; @@ -926,28 +785,28 @@ unbound_conf() { { - # Reload records more than 10 hours old + # 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: $UNBOUND_TTL_MIN" - echo " cache-max-ttl: 36000" + echo " cache-min-ttl: $UB_TTL_MIN" + echo " cache-max-ttl: 72000" echo " val-bogus-ttl: 300" echo " infra-host-ttl: 900" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF - if [ "$UNBOUND_B_HIDE_BIND" -gt 0 ] ; then + 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 - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF fi - if [ "$UNBOUND_D_PRIV_BLCK" -gt 0 ] ; then + 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. @@ -960,236 +819,309 @@ unbound_conf() { echo " private-address: fc00::/7" echo " private-address: fe80::/10" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF fi - if [ -n "$UNBOUND_LIST_PRV_IP6GLA" -a "$UNBOUND_D_PRIV_BLCK" -gt 1 ] ; then - for ifsubnet in $UNBOUND_LIST_PRV_IP6GLA ; do - # Remove global DNS responses with your local network IP6 GLA - echo " private-address: $ifsubnet" >> $UNBOUND_CONFFILE - done - - - echo >> $UNBOUND_CONFFILE + if [ -n "$UB_LIST_NETW_LAN" -a "$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 [ "$UNBOUND_B_LOCL_BLCK" -gt 0 ] ; then + 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 - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF fi - if [ -n "$UNBOUND_LIST_INSECURE" ] ; then - for domain in $UNBOUND_LIST_INSECURE ; do - # Except and accept domains without (DNSSEC); work around broken domains - echo " domain-insecure: $domain" >> $UNBOUND_CONFFILE - done - - - echo >> $UNBOUND_CONFFILE + 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 -} - -############################################################################## - -unbound_access() { - # TODO: Unbound 1.6.0 added "tags" and "views", so we can add tags to - # each access-control IP block, and then divert access. - # -- "guest" WIFI will not be allowed to see local zone data - # -- "child" LAN can black whole a list of domains to http~deadpixel - - - 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 + if [ "$UB_B_LOCL_SERV" -gt 0 -a -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 - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF else { echo " access-control: 0.0.0.0/0 allow" echo " access-control: ::0/0 allow" echo - } >> $UNBOUND_CONFFILE + } >> $UB_CORE_CONF fi - - - { - # Amend your own "server:" stuff here - echo " include: $UNBOUND_SRV_CONF" - echo - } >> $UNBOUND_CONFFILE } ############################################################################## -unbound_adblock() { - # TODO: Unbound 1.6.0 added "tags" and "views"; lets work with adblock team - local adb_enabled adb_file - +unbound_hostname() { + local ifsubnet ifarpa ifaddr ifname iffqdn + local ulaprefix hostfqdn name names namerec ptrrec + local zonetype=0 - if [ ! -x /usr/bin/adblock.sh -o ! -x /etc/init.d/adblock ] ; then - adb_enabled=0 - else - /etc/init.d/adblock enabled && adb_enabled=1 || adb_enabled=0 - fi + echo "# $UB_HOST_CONF generated by UCI $( date -Is )" > $UB_HOST_CONF - if [ "$adb_enabled" -gt 0 ] ; then + if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then { - # Pull in your selected openwrt/pacakges/net/adblock generated lists - for adb_file in $UNBOUND_VARDIR/adb_list.* ; do - echo " include: $adb_file" - done + echo "# Local zone is handled by dnsmasq" echo - } >> $UNBOUND_CONFFILE - fi -} + } >> $UB_HOST_CONF -############################################################################## + elif [ -n "$UB_TXT_DOMAIN" ] \ + && [ "$UB_D_WAN_FQDN" -gt 0 -o "$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 + # avoid upstream involvement in RFC6762 + echo " domain-insecure: local" + echo " private-domain: local" + echo " local-zone: local $UB_D_DOMAIN_TYPE" + echo " local-data: \"local. $UB_XSOA\"" + echo " local-data: \"local. $UB_XNS\"" + echo " local-data: 'local. $UB_LTXT'" + echo + } >> $UB_HOST_CONF + zonetype=2 + ;; -unbound_hostname() { - local ifsubnet ifarpa + 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 - if [ -n "$UNBOUND_TXT_DOMAIN" ] ; then { - # Hostname as TLD works, but not transparent through recursion - echo " domain-insecure: $UNBOUND_TXT_HOSTNAME" - echo " private-domain: $UNBOUND_TXT_HOSTNAME" - echo " local-zone: $UNBOUND_TXT_HOSTNAME static" - echo " local-data: \"$UNBOUND_TXT_HOSTNAME. $UNBOUND_XSOA\"" - echo " local-data: \"$UNBOUND_TXT_HOSTNAME. $UNBOUND_XNS\"" + # 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 - } >> $UNBOUND_CONFFILE + } >> $UB_HOST_CONF - case "$UNBOUND_D_DOMAIN_TYPE" in - deny|inform_deny|refuse|static) - if [ -n "$UNBOUND_LIST_PRV_IP6GLA" \ - -a "$UNBOUND_D_PRIV_BLCK" -gt 1 ] ; then - for ifsubnet in $UNBOUND_LIST_PRV_IP6GLA ; do - ifarpa=$( domain_ptr_any "$ifsubnet" ) + if [ -f "$UB_TIME_FILE" ] ; then + 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 - { - # Do NOT forward queries with your GLA ip6.arpa - echo " domain-insecure: $ifarpa" - echo " local-zone: $ifarpa $UNBOUND_D_DOMAIN_TYPE" - echo " local-data: \"$ifarpa. $UNBOUND_XSOA\"" - echo " local-data: \"$ifarpa. $UNBOUND_XNS\"" - echo - } >> $UNBOUND_CONFFILE + 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 "$UNBOUND_LIST_LAN_NET" \ - -a "$UNBOUND_D_PRIV_BLCK" -gt 0 ] ; then - for ifsubnet in $UNBOUND_LIST_LAN_NET ; do - ifarpa=$( domain_ptr_any "$ifsubnet" ) + if [ -n "$UB_LIST_NETW_LAN" ] ; then + for ifsubnet in $UB_LIST_NETW_LAN ; do + ifarpa=$( domain_ptr_any "${ifsubnet#*@}" ) if [ -n "$ifarpa" ] ; then - { - # Do NOT forward queries with your ULA ip6.arpa or in-addr.arpa - echo " domain-insecure: $ifarpa" - echo " local-zone: $ifarpa $UNBOUND_D_DOMAIN_TYPE" - echo " local-data: \"$ifarpa. $UNBOUND_XSOA\"" - echo " local-data: \"$ifarpa. $UNBOUND_XNS\"" - echo - } >> $UNBOUND_CONFFILE + 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 -a "$UB_D_PRIV_BLCK" -eq 0 ] ; then + { + echo " local-zone: $ifarpa transparent" + echo + } >> $UB_HOST_CONF + fi fi done fi - { - # avoid upstream involvement in RFC6762 - echo " domain-insecure: local" - echo " private-domain: local" - echo " local-zone: local $UNBOUND_D_DOMAIN_TYPE" - echo " local-data: \"local. $UNBOUND_XSOA\"" - echo " local-data: \"local. $UNBOUND_XNS\"" - echo " local-data: \"local. 3600 IN TXT RFC6762\"" - echo - # type static means only this router has your domain - # type transparent will permit forward-zone: or stub-zone: clauses - echo " domain-insecure: $UNBOUND_TXT_DOMAIN" - echo " private-domain: $UNBOUND_TXT_DOMAIN" - echo " local-zone: $UNBOUND_TXT_DOMAIN $UNBOUND_D_DOMAIN_TYPE" - echo " local-data: \"$UNBOUND_TXT_DOMAIN. $UNBOUND_XSOA\"" - echo " local-data: \"$UNBOUND_TXT_DOMAIN. $UNBOUND_XNS\"" - echo - } >> $UNBOUND_CONFFILE - ;; + ulaprefix=$( uci_get network.@globals[0].ula_prefix ) + ulaprefix=${ulaprefix%%:/*} + hostfqdn="$UB_TXT_HOSTNAME.$UB_TXT_DOMAIN" - *) - # likely transparent domain with fordward-zone: clause to next router - echo " domain-insecure: $UNBOUND_TXT_DOMAIN" - echo " private-domain: $UNBOUND_TXT_DOMAIN" - echo " local-zone: $UNBOUND_TXT_DOMAIN $UNBOUND_D_DOMAIN_TYPE" - echo - ;; - esac + if [ -z "$ulaprefix" ] ; then + # Nonsense so this option isn't globbed below + ulaprefix="fdno:such:addr::" + fi - if [ "$UNBOUND_D_LAN_FQDN" -gt 0 -o "$UNBOUND_D_WAN_FQDN" -gt 0 ] ; then - config_load dhcp - config_foreach create_interface_dns dhcp - fi + if [ "$UB_LIST_NETW_LAN" -a "$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 [ -f "$UNBOUND_DHCP_CONF" ] ; then - { - # Seed DHCP records because dhcp scripts trigger externally - # Incremental Unbound restarts may drop unbound-control add records - echo " include: $UNBOUND_DHCP_CONF" - echo - } >> $UNBOUND_CONFFILE - fi - fi -} -############################################################################## + 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 -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 + 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 - if [ "$UNBOUND_D_EXTRA_DNS" -gt 1 ] ; then - config_foreach create_srv_record srvhost - config_foreach create_mx_record mxhost - 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 [ "$UNBOUND_D_EXTRA_DNS" -gt 2 ] ; then - config_foreach create_cname_record cname - fi + + if [ -n "$UB_LIST_NETW_WAN" -a "$UB_D_WAN_FQDN" -gt 0 ] ; then + for ifsubnet in $UB_LIST_NETW_WAN ; do + ifaddr=${ifsubnet#*@} + ifaddr=${ifaddr%/*} + ifname=${ifsubnet%@*} + iffqdn="$ifname.$hostfqdn" - echo >> $UNBOUND_CONFFILE + 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 time file + fi # end if uci valid } ############################################################################## @@ -1199,120 +1131,214 @@ unbound_uci() { local dnsmasqpath hostnm hostnm=$( uci_get system.@system[0].hostname | awk '{print tolower($0)}' ) - UNBOUND_TXT_HOSTNAME=${hostnm:-thisrouter} + UB_TXT_HOSTNAME=${hostnm:-thisrouter} - config_get_bool UNBOUND_B_SLAAC6_MAC "$cfg" dhcp4_slaac6 0 - config_get_bool UNBOUND_B_DNS64 "$cfg" dns64 0 - config_get_bool UNBOUND_B_EXT_STATS "$cfg" extended_stats 0 - config_get_bool UNBOUND_B_HIDE_BIND "$cfg" hide_binddata 1 - 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_QRY_MINST "$cfg" query_min_strict 0 - config_get_bool UNBOUND_B_AUTH_ROOT "$cfg" prefetch_root 0 - config_get_bool UNBOUND_B_LOCL_BLCK "$cfg" rebind_localhost 0 - config_get_bool UNBOUND_B_DNSSEC "$cfg" validator 0 - config_get_bool UNBOUND_B_NTP_BOOT "$cfg" validator_ntp 1 + 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 UNBOUND_IP_DNS64 "$cfg" dns64_prefix "64:ff9b::/96" + config_get UB_IP_DNS64 "$cfg" dns64_prefix "64:ff9b::/96" - config_get UNBOUND_N_EDNS_SIZE "$cfg" edns_size 1280 - config_get UNBOUND_N_RX_PORT "$cfg" listen_port 53 - config_get UNBOUND_N_ROOT_AGE "$cfg" root_age 9 + 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 UNBOUND_D_CONTROL "$cfg" unbound_control 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_PRIV_BLCK "$cfg" rebind_protection 1 - config_get UNBOUND_D_PROTOCOL "$cfg" protocol mixed - config_get UNBOUND_D_RECURSION "$cfg" recursion passive - config_get UNBOUND_D_RESOURCE "$cfg" resource small - config_get UNBOUND_D_WAN_FQDN "$cfg" add_wan_fqdn 0 + 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 UNBOUND_TTL_MIN "$cfg" ttl_min 120 - config_get UNBOUND_TXT_DOMAIN "$cfg" domain lan + config_get UB_TTL_MIN "$cfg" ttl_min 120 + config_get UB_TXT_DOMAIN "$cfg" domain lan - config_list_foreach "$cfg" "domain_forward" bundle_domain_forward - config_list_foreach "$cfg" "domain_insecure" bundle_domain_insecure - config_list_foreach "$cfg" "rebind_interface" bundle_private_interface + config_list_foreach "$cfg" domain_insecure bundle_domain_insecure - 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 [ "$UB_D_DHCP_LINK" = "none" ] ; then + config_get_bool UB_B_DNSMASQ "$cfg" dnsmasq_link_dns 0 - if [ "$UNBOUND_B_DNSMASQ" -gt 0 ] ; then - UNBOUND_D_DHCP_LINK=dnsmasq + if [ "$UB_B_DNSMASQ" -gt 0 ] ; then + UB_D_DHCP_LINK=dnsmasq - if [ ! -f "$UNBOUND_TIMEFILE" ] ; then + if [ ! -f "$UB_TIME_FILE" ] ; then logger -t unbound -s "Please use 'dhcp_link' selector instead" fi fi fi - if [ "$UNBOUND_D_DHCP_LINK" = "dnsmasq" ] ; then + if [ "$UB_D_DHCP_LINK" = "dnsmasq" ] ; then if [ ! -x /usr/sbin/dnsmasq -o ! -x /etc/init.d/dnsmasq ] ; then - UNBOUND_D_DHCP_LINK=none + UB_D_DHCP_LINK=none else - /etc/init.d/dnsmasq enabled || UNBOUND_D_DHCP_LINK=none + /etc/init.d/dnsmasq enabled || UB_D_DHCP_LINK=none fi - if [ "$UNBOUND_D_DHCP_LINK" = "none" -a ! -f "$UNBOUND_TIMEFILE" ] ; then + if [ ! -f "$UB_TIME_FILE" -a "$UB_D_DHCP_LINK" = "none" ] ; then logger -t unbound -s "cannot forward to dnsmasq" fi fi - if [ "$UNBOUND_D_DHCP_LINK" = "odhcpd" ] ; then + if [ "$UB_D_DHCP_LINK" = "odhcpd" ] ; then if [ ! -x /usr/sbin/odhcpd -o ! -x /etc/init.d/odhcpd ] ; then - UNBOUND_D_DHCP_LINK=none + UB_D_DHCP_LINK=none else - /etc/init.d/odhcpd enabled || UNBOUND_D_DHCP_LINK=none + /etc/init.d/odhcpd enabled || UB_D_DHCP_LINK=none fi - if [ "$UNBOUND_D_DHCP_LINK" = "none" -a ! -f "$UNBOUND_TIMEFILE" ] ; then + if [ ! -f "$UB_TIME_FILE" -a "$UB_D_DHCP_LINK" = "none" ] ; then logger -t unbound -s "cannot receive records from odhcpd" fi fi - if [ "$UNBOUND_N_EDNS_SIZE" -lt 512 \ - -o 4096 -lt "$UNBOUND_N_EDNS_SIZE" ] ; then + if [ "$UB_N_EDNS_SIZE" -lt 512 \ + -o 4096 -lt "$UB_N_EDNS_SIZE" ] ; then logger -t unbound -s "edns_size exceeds range, using default" - UNBOUND_N_EDNS_SIZE=1280 + UB_N_EDNS_SIZE=1280 fi - if [ "$UNBOUND_N_RX_PORT" -ne 53 ] \ - && [ "$UNBOUND_N_RX_PORT" -lt 1024 -o 10240 -lt "$UNBOUND_N_RX_PORT" ] ; then + if [ "$UB_N_RX_PORT" -ne 53 ] \ + && [ "$UB_N_RX_PORT" -lt 1024 -o 10240 -lt "$UB_N_RX_PORT" ] ; then logger -t unbound -s "privileged port or in 5 digits, using default" - UNBOUND_N_RX_PORT=53 + UB_N_RX_PORT=53 fi - if [ "$UNBOUND_TTL_MIN" -gt 1800 ] ; then + if [ "$UB_TTL_MIN" -gt 1800 ] ; then logger -t unbound -s "ttl_min could have had awful side effects, using 300" - UNBOUND_TTL_MIN=300 + UB_TTL_MIN=300 fi } ############################################################################## -unbound_resolv_setup() { - if [ "$UNBOUND_N_RX_PORT" != "53" ] ; then - return +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 [ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq enabled \ - && nslookup localhost 127.0.0.1#53 >/dev/null 2>&1 ; then + 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_TIME_FILE" -a -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 [ ! -f "$UB_TIME_FILE" -o -z "$adb_files" \ + -o ! -x /usr/bin/adblock.sh -o ! -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: @@ -1327,61 +1353,44 @@ unbound_resolv_setup() { rm -f /tmp/resolv.conf { - echo "# /tmp/resolv.conf generated by Unbound UCI $( date )" + echo "# /tmp/resolv.conf generated by Unbound UCI $( date -Is )" echo "nameserver 127.0.0.1" echo "nameserver ::1" - echo "search $UNBOUND_TXT_DOMAIN." + echo "search $UB_TXT_DOMAIN." } > /tmp/resolv.conf } ############################################################################## -unbound_resolv_teardown() { - case $( cat /tmp/resolv.conf ) in - *"generated by Unbound UCI"*) - # our resolver file, reset to auto resolver file. - rm -f /tmp/resolv.conf - ln -s /tmp/resolv.conf.auto /tmp/resolv.conf - ;; - esac -} - -############################################################################## - unbound_start() { config_load unbound config_foreach unbound_uci unbound unbound_mkdir - if [ "$UNBOUND_B_MAN_CONF" -eq 0 ] ; then + 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_access - unbound_adblock - - - if [ "$UNBOUND_D_DHCP_LINK" = "dnsmasq" ] ; then - dnsmasq_link - else - unbound_hostname - unbound_records - fi - - - unbound_forward - unbound_auth_root + unbound_hostname + # control: unbound_control + # dnsmasq + dnsmasq_link + # merge + unbound_include fi - unbound_resolv_setup -} - -############################################################################## - -unbound_stop() { - unbound_resolv_teardown - rootzone_update + resolv_setup } ############################################################################## diff --git a/net/unbound/files/unbound.uci b/net/unbound/files/unbound.uci index fb0f6c887..9614357eb 100644 --- a/net/unbound/files/unbound.uci +++ b/net/unbound/files/unbound.uci @@ -9,13 +9,11 @@ config unbound option domain 'lan' option domain_type 'static' option edns_size '1280' - option extended_luci '0' option extended_stats '0' option hide_binddata '1' option listen_port '53' option localservice '1' option manual_conf '0' - option prefetch_root '0' option protocol 'default' option query_minimize '0' option query_min_strict '0' @@ -28,9 +26,28 @@ config unbound option unbound_control '0' option validator '0' option validator_ntp '1' + option verbosity '1' list trigger_interface 'lan' list trigger_interface 'wan' - #list rebind_interface 'lan' #list domain_insecure 'ntp.example.com' - #list domain_forward 'mail.example.com' + +config zone + option enabled '0' + option fallback '1' + option url_dir 'https://www.internic.net/domain/' + option zone_type 'auth_zone' + list server 'lax.xfr.dns.icann.org' + list server 'iad.xfr.dns.icann.org' + list zone_name '.' + list zone_name 'arpa.' + list zone_name 'in-addr.arpa.' + list zone_name 'ip6.arpa.' + +config zone + option enabled '0' + option fallback '1' + option resolv_conf '1' + option zone_type 'forward_zone' + list zone_name 'isp-bill.example.com.' + list zone_name 'isp-mail.example.net.'