Skip to content

Instantly share code, notes, and snippets.

@kevinoid
Last active July 29, 2024 17:00
Show Gist options
  • Save kevinoid/00656e6e4815e3ffe25dabe252e0f1e3 to your computer and use it in GitHub Desktop.
Save kevinoid/00656e6e4815e3ffe25dabe252e0f1e3 to your computer and use it in GitHub Desktop.
Setup Unbound with Dnsmasq on OpenWrt
server:
do-not-query-localhost: no
domain-insecure: "0.168.192.in-addr.arpa"
domain-insecure: "example.local"
local-zone: "168.192.in-addr.arpa." nodefault
private-address: 10.0.0.0/8
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: fd00::/8
private-address: fe80::/10
private-domain: "example.local"
forward-zone:
name: "example.local"
forward-addr: 127.0.0.1@53535
forward-zone:
name: "0.168.192.in-addr.arpa"
forward-addr: 127.0.0.1@53535
#!/bin/sh
# Steps to configure unbound on OpenWRT with dnsmasq for dynamic DNS
# Note: Clarity of instruction is favored over script speed or robustness.
# It is not idempotent.
# Show commands as executed, error out on failure or undefined variables
set -eux
# Note the local domain (Network -> DHCP & DNS -> General Settings)
lan_domain=$(uci get 'dhcp.@dnsmasq[0].domain')
# Note the LAN network address (Network -> Interfaces -> LAN -> IPv4 address)
lan_address=$(uci get network.lan.ipaddr)
# Update the package list (System -> Software -> Update lists)
opkg update
# Install unbound (System -> Software -> Find package: unbound -> Install)
opkg install unbound # Ignore error that it can't listen on port 53
# Move dnsmasq to port 53535 where it will still serve dynamic DNS from DHCP
# Network -> DHCP & DNS -> Advanced Settings -> DNS server port to 53535
uci set 'dhcp.@dnsmasq[0].port=53535'
# Configure dnsmasq to send a DNS Server DHCP option with its LAN IP
# since it does not do this by default when port is configured.
uci add_list "dhcp.lan.dhcp_option=option:dns-server,$lan_address"
# Configure Unbound from unbound.conf, instead of generating it from UCI
# Services -> Recursive DNS -> Manual Conf
uci set 'unbound.@unbound[0].manual_conf=1'
# Save & Apply (will restart dnsmasq, DNS unreachable until unbound is up)
uci commit
# Allow unbound to query dnsmasq on the loopback address
# by adding 'do-not-query-localhost: no' to server section
sed -i '/^server:/a\ do-not-query-localhost: no' /etc/unbound/unbound.conf
# Convert the network address to a Reverse DNS domain
# https://en.wikipedia.org/wiki/Reverse_DNS_lookup
case $(uci get network.lan.netmask) in
255.255.255.0) ip_to_rdns='\3.\2.\1.in-addr.arpa' ;;
255.255.0.0) ip_to_rdns='\2.\1.in-addr.arpa' ;;
255.0.0.0) ip_to_rdns='\1.in-addr.arpa' ;;
*) echo 'More complex rDNS configuration required.' >&2 ; exit 1 ;;
esac
lan_rdns_domain=$(echo "$lan_address" | \
sed -E "s/^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/$ip_to_rdns/")
# Check if the local addresses are in a private address range (very common)
case "$lan_address" in
0.*) ip_to_priv_rdns='0.in-addr.arpa.' ;;
10.*) ip_to_priv_rdns='10.in-addr.arpa.' ;;
169.254.*) ip_to_priv_rdns='254.169.in-addr.arpa.' ;;
172.1[6-9].*|172.2[0-9].*|172.3[0-1].*) ip_to_priv_rdns='\2.172.in-addr.arpa.' ;;
192.0.2.*) ip_to_priv_rdns='2.0.192.in-addr.arpa.' ;;
192.168.*) ip_to_priv_rdns='168.192.in-addr.arpa.' ;;
198.51.100.*) ip_to_priv_rdns='100.51.198.in-addr.arpa.' ;;
203.0.113.*) ip_to_priv_rdns='113.0.203.in-addr.arpa.' ;;
esac
if [ -n "${ip_to_priv_rdns-}" ] ; then
# Disable default "does not exist" reply for private address ranges
# by adding 'local-zone "$lan_domain" nodefault' to server section
# Note that this must be on RFC 1918/5735/5737 boundary,
# this is only equal to $lan_rdns_domain when netmask covers whole range.
lan_priv_rdns_domain=$(echo "$lan_address" | \
sed -E "s/^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/$ip_to_priv_rdns/")
sed -i "/^server:/a\ local-zone: \"$lan_priv_rdns_domain\" nodefault" \
/etc/unbound/unbound.conf
fi
# Ignore DNSSEC chain of trust for the local domain
# by adding 'domain-insecure: "$lan_domain"' to server section
sed -i "/^server:/a\ domain-insecure: \"$lan_domain\"" /etc/unbound/unbound.conf
# Ignore DNSSEC chain of trust for the local reverse domain
# by adding 'domain-insecure: "$lan_rdns_domain"' to server section
sed -i "/^server:/a\ domain-insecure: \"$lan_rdns_domain\"" /etc/unbound/unbound.conf
# Add a forward zone for the local domain to forward requests to dnsmasq
cat >> /etc/unbound/unbound.conf <<DNS_FORWARD_ZONE
forward-zone:
name: "$lan_domain"
forward-addr: 127.0.0.1@53535
DNS_FORWARD_ZONE
# Add a forward zone for the local reverse domain to forward requests to dnsmasq
cat >> /etc/unbound/unbound.conf <<RDNS_FORWARD_ZONE
forward-zone:
name: "$lan_rdns_domain"
forward-addr: 127.0.0.1@53535
RDNS_FORWARD_ZONE
# Optionally enable DNS Rebinding protection by uncommenting private-address
# configuration and adding 'private-domain: "$lan_domain"' to server section
sed -E -i \
-e 's/(# )?private-address:/private-address:/' \
-e "/^server:/a\ private-domain: \"$lan_domain\"" \
/etc/unbound/unbound.conf
# Restart (or start) unbound (System -> Startup -> unbound -> Restart)
/etc/init.d/unbound restart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment