Graham Eddy

dnsmasq server

Small DNS/DHCP server for home/office network.

2022-09-12 Ubuntu 22.04


Assumes network as follows:

Network
192.168.99.0/24
Gateway/WAN router
192.168.99.1
dnsmasq server
192.168.99.20
Domain name
home.arpa (per RFC 8375)
DHCP server upstream DNS servers
1.1.1.1, 1.0.0.1 (cloudflare) in /etc/resolv.dnsmasq
DHCP client DNS servers
192.168.99.20, 1.1.1.1
Permanent IP addresses
192.168.99.1 to 192.168.99.99
Dynamic IP addresses
192.168.99.100 to 192.168.99.199 (1d lease)
Map MAC address↔hostname
/etc/ethers
Map hostname↔IP address
/etc/hosts.dnsmasq

Firstly dispense with systemd-resolved as dnsmasq replaces it and they collide on use of port 53.

graham:~ sudo systemctl stop systemd-resolved graham:~ sudo systemctl disable systemd-resolved graham:~ sudo unlink /etc/resolv.conf # use temporary name server graham:~ echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

Installation

graham:~ sudo apt update graham:~ sudo apt install dnsmasq

We effectively split up the provided /etc/dnsmasq.conf into subsystems and configure them separately. It contains no settings, only comments and defaults, so there is no harm in leaving it in situ. The comments however are very useful and it is recommended to use the full files referenced below rather than just the settings as shown.

DNS server

graham:~ sudo vi /etc/dnsmasq.d/dns.conf
/etc/dnsmasq/dns.conf new file

Note that the following only shows the settings changed from default – see dns.conf in full

#port 53
domain-needed
bogus-priv
resolv-file=/etc/resolv.dnsmasq
local=/home.arpa/
no-hosts
addn-hosts=/etc/hosts.dnsmasq
log-queries
graham:~ sudo vi /etc/dnsmasq.d/blacklist.conf # domains to filter out of queries
/etc/dnsmasq.d/blacklist.conf new file
# blacklist.conf - block domains from DNS queries
#
# redirect them into blackhole
address=/double-click.net/0.0.0.0
address=/facebook.com/0.0.0.0
address=/facebook.net/0.0.0.0
address=/imrworldwide.com/0.0.0.0
graham:~ sudo vi /etc/resolv.dnsmasq # upstream name servers
/etc/resolv.dnsmasq new file
# resolv.dnsmasq - upstream name servers
# cloudflare
nameserver 1.1.1.1
nameserver 1.0.0.1
graham:~ sudo vi /etc/resolv.conf # local name server
/etc/resolv.conf replace contents
# resolv.conf - loopback to local dnsmasq
nameserver 127.0.0.1
graham:~ sudo vi /etc/hosts.dnsmasq # local domain addresses being managed
/etc/hosts new file

Obviously, populate with your own IP addresses and hostnames.

# hosts.dnsmasq - map IP address to hostname

192.168.99.1    gateway         # WAN router/gateway
192.168.99.20   messmate        # Mac Mini
192.168.99.23   paperbark       # RPi 4
192.168.99.25   ironbark        # RPi 4
192.168.99.27   stringybark     # RPi 4 + RAK2245
192.168.99.39   huonpine        # MacBook Pro
graham:~ sudo vi /etc/hosts
/etc/hosts IP addresses not offered by dnsmasq
127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             ip6-localhost
fe00::0         ip6-localnet
ff00::0         ip6-mcastprefix
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

# not assigned by dnsmasq
127.0.1.1       messmate.home.arpa

DHCP server

graham:~ sudo vi /etc/dnsmasq.d/dhcp.conf
/etc/dnsmasq/dhcp.conf new file

Note that the following only shows the settings changed from default – see dhcp.conf in full

expand-hosts
domain=home.arpa
dhcp-range=set:POOL,192.168.99.100,192.168.99.199,1d
read-ethers
dhcp-option=option:router,192.168.99.1
dhcp-option=option:dns-server,192.168.99.20,1.1.1.1
dhcp-option=option:domain-name,home.arpa
dhcp-option=option:domain-search,home.arpa
dhcp-authoritative
dhcp-rapid-commit
log-dhcp
synth-domain=home.arpa,192.168.99.100,192.168.99.199,pool-*
graham:~ sudo vi /etc/ethers # MAC address db
/etc/ethers new file

Obviously, populate with your own MAC addresses and hostnames.

# ethers - map MAC address to hostname
#
# hostname must be DNS-resolvable

ac:87:a3:25:7b:00 messmate
d8:47:32:d6:97:d0 gateway
dc:a6:32:b0:b5:a4 paperbark
dc:a6:32:e0:aa:12 ironbark
dc:a6:32:ea:65:c8 stringybark
f4:d4:88:88:cb:d6 huonpine

TFTP server

graham:~ sudo vi /etc/dnsmasq.d/tftp.conf-OFF
/etc/dnsmasq/tftp.conf-OFF new file (empty)

Note that this file has no settings changed from the default – see tftp.conf in full to capture the useful comments.


Common to all subsystems

graham:~ sudo vi /etc/dnsmasq.d/common.conf-OFF
/etc/dnsmasq/common.conf-OFF new file (empty)

Note that this file has no settings changed from the default – see common.conf in full to capture the useful comments.


graham:~ dnsmasq --test # simple syntax check graham:~ sudo vi /etc/netplan/00-installer-config.yaml # server requires static IP
/etc/netplan/00-installer-config.yaml update interface definition
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0f0:
      dhcp4: false
      addresses: [ 192.168.99.20/24 ]
      routes:
        - to:      default
          via:     192.168.99.1
          on-link: true
      nameservers:
        addresses: [ 127.0.0.1 ]
graham:~ sudo netplan apply graham:~ sudo vi /etc/rsyslog.d/dnsmasq.conf # split out dnsmasq logging
/etc/rsyslog.d/dnsmasq.conf new file
# dnsmasq.conf - syslog config
:programname,startswith,"dnsmasq" /var/log/dnsmasq.log
:programname,startswith,"dnsmasq" stop
graham:~ sudo vi /etc/logrotate.d/dnsmasq
/etc/logrotate.d/dnsmasq new file
# dnsmasq - logrotate config
/var/log/dnsmasq.log
{
  daily
  missingok
  rotate 7
  compress
  delaycompress
  notifempty
  sharedscripts
  postrotate
    pkill -USR2 dnsmasq
    /usr/lib/rsyslog/rsyslog-rotate
  endscript
}
graham:~ sudo systemctl restart rsyslog graham:~ sudo systemctl restart dnsmasq # start dnsmasq graham:~ systemctl status dnsmasq ● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor prese> Active: active (running) since Tue 2022-09-20 23:10:53 AEST; 4min 11s ago … … graham:~ sudo tail -f /var/log/dnsmasq.log graham:~ dig stringybark @localhost ; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> stringybark @localhost ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54662 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;stringybark. IN A ;; ANSWER SECTION: stringybark. 0 IN A 192.168.99.27 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(localhost) (UDP) ;; WHEN: Tue Sep 20 02:32:02 AEST 2022 ;; MSG SIZE rcvd: 56

Appendix: NoTracking – domain blacklist

NoTracking is a publicly maintained blacklist of advertising and malware domains. With the perfomance penalty of checking more than ¼million entries on each uncached domain lookup, these domains can be blocked at the DNS level.

graham:~ sudo vi /usr/local/sbin/update-notracking
/usr/local/sbin/update-tracking new file
#!/bin/sh
# install NoTracking blocklist in dnsmasq.
# dnsmasq must be restarted (HUP insufficient) to utilise - not done here.
#
# see https://github.com/notracking/hosts-blocklists

# config
bl_url="https://raw.githubusercontent.com/notracking/hosts-blocklists/master"
bl_url="${bl_url}/dnsmasq/dnsmasq.blacklist.txt"
bl_line='^address=\/[-._a-zA-Z0-9]*\/\#$'
target="/etc/dnsmasq.d/notracking.conf"

abort () {
    [ $# -gt 0 ] && echo "$@" 1>&2
    exit 1
}

# parse command line
[ $# -gt 0 ] && abort "usage: $0"

# fetch & check blacklist file
umask 022
bl_file=$(mktemp)
trap 'rm -f "$bl_file"' 0
curl --silent --show-error --fail "$bl_url" --output "$bl_file" || abort
grep -v -e '^#' -e "$bl_line" "$bl_file" &&
    abort "rejected: some malformed entries"

# install blacklist file
chmod 644 "$bl_file"
mv "$bl_file" "$target"
graham:~ sudo chmod 554 /usr/local/sbin/update-notracking graham:~ sudo crontab -e # schedule weekly
…temp file… append to end
# dnsmasq maintenance
#
# update blocklists
11 1 * * 6 /usr/local/sbin/update-notracking && systemctl restart dnsmasq