DNSMasq with a Raspberry Pi DNS, DHCP, and Static Leases

Assumptions

  • You’re running Raspbian or a Debian-based distro on your Pi. Although there should be little difference, if any, in most areas between instances on other Operating Systems.
  • You know how to navigate the Linux – editing files, cron…

DNSMasq Configuration File

The below DNSMasq configuration was mostly copied, with some changes, from here.
Extra verbose comments are either my comments, or ones taken from what I found pertinent on this man page.

########################################
# DHCP
########################################

## man page for this config file: http://oss.segetech.com/intra/srv/dnsmasq.conf
## See current leases given here: /var/lib/misc/dnsmasq.leases

# Add domains which you want to force to an IP address here. The example below send any host in doubleclick.net to a local webserver.
address=/doubleclick.net/127.0.0.1

# Add the domain to simple names (without a period) in /etc/hosts in the same way as for DHCP-derived names. Note that this does not apply to domain names in cnames, PTR records, TXT records etc.
expand-hosts

# Range of IPs to use for DHCP Pool. Can have multiple ranges. Last part is lease time.
# Enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to
# repeat this for each network on which you want to supply DHCP
# service.
dhcp-range=10.0.0.100,10.0.0.200,48h
dhcp-option=6,10.0.0.33,10.0.0.1
# Override the default route supplied by dnsmasq, which assumes the router is the same machine as the one running dnsmasq.
dhcp-option=option:router,10.0.0.1
# Set the NTP time server addresses
dhcp-option=option:ntp-server,10.0.0.33

# Send microsoft-specific option to tell windows to release the DHCP lease when it shuts down. Note the "i" flag, to tell dnsmasq to send the value as a four-byte integer - that's what microsoft wants. See http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
dhcp-option=vendor:MSFT,2,1i

########################################
# STATIC LEASES
# There are many ways to assign these leases. See the man page for the .conf
########################################
# System
dhcp-host=AA:BB:CC:DD:EE,router,10.0.0.1,infinite

# Human 1
dhcp-host=00:11:22:33:44,ps3,10.0.0.24,48h
dhcp-host=01:11:22:33:44,ps4,10.0.0.25,48h

########################################
# DNS
########################################
# Listen on this network interface
interface=eth0
# The IP address of the Raspberry Pi
listen-address=10.0.0.33,127.0.0.1

# For debugging purposes, log each DNS query as it passes through dnsmasq.
# log-queries

# Tells dnsmasq to never forward A or AAAA queries for plain names, without dots or domain parts, to upstream nameservers. If the name is not known from /etc/hosts or DHCP then a "not found" answer is returned.
domain-needed

# Set the domain for dnsmasq. this is optional, but if it is set, it
# does the following things.
# 1) Allows DHCP hosts to have fully qualified domain names, as long
#     as the domain part matches this setting.
# 2) Sets the "domain" DHCP option thereby potentially setting the
#    domain of all systems configured by DHCP
# 3) Provides the domain part for "expand-hosts"
domain=home.local

# Add local-only domains here, queries in these domains are answered from /etc/hosts or DHCP only.
local=/home.local/

# Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc) which are not found in /etc/hosts or the DHCP leases file are answered with "no such domain" rather than being forwarded upstream.
bogus-priv

# Don't read /etc/resolv.conf. Get upstream servers only from the command line or the dnsmasq configuration file.
no-resolv

# Don't poll /etc/resolv.conf for changes.
no-poll

# Don't read the hostnames in /etc/hosts.
no-hosts

# Uses this file as a hosts file. Useful for simple DNS lookups.
addn-hosts=/etc/dnsmasq_static_hosts.conf

# If this is commented out, when resolving DNS for local systems, you'd have to append what is defined in the 'local=' option
expand-hosts

# Size of local DNS cache. Units=sites. cache-size=10000 means it'll cache 10,000 DNS names.
cache-size=10000

# Specify IP address of upstream servers directly.
# DNSMasq does DNS lookups against these public DNS servers
server=8.8.3.3  # Google DNS
server=8.8.8.8  # Google DNS

Updating DNS with Cron

For whatever reason, doing DNS queries against my Raspberry Pi with the host names defined in in /etc/dnsmasq.conf this way, binding the name to the MAC Address as I want, would fail. Queries would only return with an A record if I had put the IPs/Hostnames in the path with the addn-hosts option.

I didn’t want to have to define hosts in two different files. Without an obvious solution, I decided to set up a cron job to update /etc/dnsmasq_static_hosts.conf on a daily basis, taking just the static leases I wanted and formatting them just as would be done in /etc/hosts.

sudo crontab -e
0 4 * * * * cat /etc/dnsmasq.conf | grep dhcp-host | tr ',' ' ' | awk '{print$3, $2}' > /etc/dnsmasq_static_hosts.conf && dnsmasq --test; if [ $? -eq 0 ]; then systemctl restart dnsmasq; else echo "Error with DNSMasq Config"; fi

This cronjob will run at 4am and:

  1. cat: read out the DNSMasq configuration
  2. grep: locate only the lines for static leases
  3. tr: convert commas into spaces (as the option parameters are formatted like a CSV)
  4. awk: Extract the hostname and IP address and print only them in reverse order
  5. >: Overwrite the DNSMasq configuration file
  6. dnsmasq –test: Sees if the formatting of the config file is acceptable 1. If the syntax is correct, then restart the daemon
  7. Otherwise it has a syntax issue, don’t restart it. 1. (The echo isn’t needed for cron as it won’t be seen normally. I left it in for copying/pasting/testing)

What it writes to the file where you can resolve to your static leases by hostname: 10.0.0.11 router 10.0.0.24 ps3 10.0.0.25 ps4

Bash Alias to see current DHCP leases

  1. Edit your user’s .bashrc:
    cd ~
    sudo nano .bashrc
    
  2. Add the alias to print MAC / IP INFO (If I remember correctly)
    `alias leases="cat /var/lib/misc/dnsmasq.leases | awk '{print \$3, \$4, \$2}' | sort -t . -k 3,3n -k 4,4n"`
    

Logging

DHCP logs should look like:

tail -f /var/log/daemon.log Dec 30 03:18:58 raspberrypi dnsmasq-dhcp[5265]: DHCPDISCOVER(eth0) 10.0.0.24 0c:fe:45:54:69:36 Dec 30 03:18:58 raspberrypi dnsmasq-dhcp[5265]: DHCPOFFER(eth0) 10.0.0.24 0c:fe:45:54:69:36 Dec 30 03:18:58 raspberrypi dnsmasq-dhcp[5265]: DHCPREQUEST(eth0) 10.0.0.24 0c:fe:45:54:69:36 Dec 30 03:18:58 raspberrypi dnsmasq-dhcp[5265]: DHCPACK(eth0) 10.0.0.24 0c:fe:45:54:69:36 d-ps3

DNS logs should look like:

Dec 30 02:52:27 raspberrypi dnsmasq[23479]: query[A] ssum-sec.casalemedia.com from 10.0.0.185 Dec 30 02:52:27 raspberrypi dnsmasq[23479]: cached ssum-sec.casalemedia.com is <CNAME> Dec 30 02:52:27 raspberrypi dnsmasq[23479]: forwarded ssum-sec.casalemedia.com to 8.8.8.8 Dec 30 02:52:27 raspberrypi dnsmasq[23479]: query[A] ums.adtechus.com from 10.0.0.185 Dec 30 02:52:27 raspberrypi dnsmasq[23479]: forwarded ums.adtechus.com to 8.8.8.8

Problems

  • DHCP relay with guest network.

Further/Alternate Reading


© 2019. All rights reserved.

Powered by Hydejack v8.5.2