unbound basics
stub-zones
I use stub-zones a few places in my own unbound. Mostly for internal-only zones which provide information about some internal/network hosts.
stub-zone: name: "spear.home.dayid.org." stub-addr: 192.168.0.18 # bind.home.dayid.org // maleah alias for isc_named/bindThis is used as all requests for "spear.home.dayid.org" are to be answered by 192.168.0.18 which is an ip alias running on "maleah" (where my unbound and nsd run) for an instance of isc_named/bind that runs there just to interact with dynamic & catalog zones. This is kept at the very bottom of my unbound.conf.
Yes, similar end-results can be accomplished by using a forward-zone, but a forward zone just forwards the request to another server (recursive or otherwise) whereas a stub-zone is pre-loading the cache with static entries for the nameservers of that particular zone.
You can confirm these by using `unbound-control list_stubs`.
$ doas unbound-control list_stubs | grep spear spear.home.dayid.org. IN stub noprime 192.168.0.18I serve 168.192.in-addr.arpa and 10.in-addr.arpa authoritively from my NSD instance. Then I also allow my domain (and its subdomains) to contain private addresses:
local-zone: "168.192.in-addr.arpa." nodefault local-zone: "10.in-addr.arpa." nodefault private-domain: "home.dayid.org" domain-insecure: "home.dayid.org" stub-zone: name: "10.in-addr.arpa." stub-addr: 127.0.0.1@5353 # NSD stub-zone: name: "168.192.in-addr.arpa." stub-addr: 127.0.0.1@5353 # NSD stub-zone: name: "home.dayid.org." stub-addr: 127.0.0.1@5353 # NSD
local-zone/local-data for blocking
As part of my adblock.conf (which is included in my unbound.conf as follows):
include: /var/unbound/etc/adblock.conf...I use local-zone/local-data to block problematic/hazardous stuff in the following pattern (generated by a script using cron)
local-zone: "analytic.shareaholic.com" always_nxdomain local-data: "analytic.shareaholic.com" 604800 IN SOA adblock adblock ( 0 604800 604800 604800 604800 )"If one of my clients tries to query for this, the dig output shows the SOA above, but also gives the client an NXDOMAIN:
$ dig @192.168.0.17 analytic.shareaholic.com ; <<>> dig 9.10.8-P1 <<>> @192.168.0.17 analytic.shareaholic.com ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 24652 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;analytic.shareaholic.com. IN A ;; AUTHORITY SECTION: shareaholic.com. 604800 IN SOA adblock. adblock. 0 604800 604800 604800 604800 ;; Query time: 0 msec ;; SERVER: 192.168.0.17#53(192.168.0.17) ;; WHEN: Mon Apr 10 21:21:01 EDT 2023 ;; MSG SIZE rcvd: 96I like having all of this instead of a just-nxdomain as I like forcing the negative cache as well as overriding the SOA to make it clear I'm blocking the domain (vs it just being a regular NXDOMAIN). Specifically these appear helpful in making some IoT devices not retrying quite as often.
You can confirm these with unbound-control also:
$ doas unbound-control list_local_data | grep analytic.shareaholic.com analytic.shareaholic.com. 604800 IN SOA adblock. adblock. 0 604800 604800 604800 604800 $ doas unbound-control list_local_zones | grep analytic.shareaholic.com analytic.shareaholic.com. always_nxdomain
local-zone for oddball situations
At one point my workstation was using my local DNS, but I needed to forward just a specific zone to my employer's DNS (through VPN). Thus, I overwrote just the NS for the zone so I could retrieve the company-internal-view of it:
local-zone: "example.com." static local-zone: "example.com. IN NS 10.1.240.1"
The cron script
#!/bin/sh mkdir -p /tmp/unbound-adblock cd /tmp/unbound-adblock # get the popular StevenBlack block list, strip it to just hostnames ftp -o - https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts | awk /^0.0.0.0/'{ print $2 }' > /tmp/unbound-adblock/stevenblack.ftp # Treat my own blacklist the same as any other cp /etc/unbound/blacklist.txt /tmp/unbound-adblock/dayid-blacklist.ftp # Concatenate the lists together to sort/uniq to avoid duplicates as this will cause unbound to fail upon reload cat /tmp/unbound-adblock/*.ftp | sort | uniq > /tmp/unbound-adblock/rawmasterlist awk '{ print "local-zone: \""$1"\" always_nxdomain"; print "local-data: \""$1" 604800 IN SOA adblock adblock ( 0 604800 604800 604800 604800 )\"" }' /tmp/unbound-adblock/rawmasterlist > /tmp/unbound-adblock/adblock.conf doas /bin/cp /tmp/unbound-adblcok/adblock.conf /var/unbound/etc/ doas /usr/sbin/rcctl reload unbound
$ doas grep adblock /etc/doas.conf # For /usr/local/bin/adblock.sh permit nopass _adblock cmd /usr/sbin/rcctl args reload unbound permit nopass _adblock cmd /bin/cp args /tmp/unbound-adblock/adblock.conf /var/unbound/etc/