Using dnsmasq as local DHCP and DNS server
Preface
Having many devices inside a local network can be cumbersome, when trying to reach a specific one, but not knowing the correct IP address for it. But there’s a nice solution for that called a local DNS1 server. DNS servers are the ones who know to what IP to go, when we enter www.google.com
address in our browser, so having one in our LAN would be awesome. Here comes dnsmasq to the rescue.
dnsmasq
Dnsmasq2 provides network infrastructure for small networks, with services like DNS and DHCP3. It’s very lightweight and perfect for our Pogoplug E02 server.
Installation
It’s very simple on Arch Linux using pacman
.
$ sudo pacman -Sy dnsmasq
Configuration
At first we need to enter hostnames into /etc/hosts
file for dnsmasq to know what hostname goes with which IP address. Here’s an example where I entered tp-link
(my router), pogo
(Pogoplug E02) and asus
(laptop). A good practice for deciding what to use for .localdomain
part is that it’s not resolvable online, so there’s no issues when using with other services, it should only be resolveable in the local network. If you own a domain name, use a subdomain as in this example.
#
# /etc/hosts: static lookup table for host names
#
#<ip-address> <hostname.domain.org> <hostname>
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
192.168.1.1 tplink.lan.tdkl.eu tplink
192.168.1.2 pogo.lan.tdkl.eu pogo
192.168.1.10 asus.lan.tdkl.eu asus
# End of file
We also need to edit the DNS entries in the /etc/systemd/resolved.conf
file for the external DNS servers. In this example, Google and OpenDNS servers are used.
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# See resolved.conf(5) for details
[Resolve]
DNS=8.8.8.8 208.67.222.222
Then we edit the file /etc/resolvconf.conf
and enter 127.0.0.1
(localhost) address, since dnsmasq will operate as a local caching DNS server.
# Configuration for resolvconf(8)
# See resolvconf.conf(5) for details
resolv_conf=/etc/resolv.conf
# If you run a local name server, you should uncomment the below line and
# configure your subscribers configuration files below.
name_servers=127.0.0.1
In the initial ALARM installation we configured a static IP for the Pogoplug and also entered DNS servers there. Now we need to edit that again to change the DNS entry to 127.0.0.1
. The configuration is in /etc/systemd/network/eth0.network
.
[Match]
Name=eth0
[Network]
#DHCP=yes
DNS=127.0.0.1
Address=192.168.1.2/24
Gateway=192.168.1.1
Now we only need to edit the /etc/dnsmasq.conf
configuration file, which includes all the configuration for desired services. An example is shown here, I’ve included the comments what everything means line by line.
# Configuration file for dnsmasq.
#
# Format is one option per line, legal options are the same
# as the long options legal on the command line. See
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
# Never forward plain names (without a dot or domain part)
domain-needed
# Never forward addresses in the non-routed address spaces.
bogus-priv
# Local domain used inside the local network, use something you own, or
# a domain that doesn't exist online
domain=lan.tdkl.eu
# Interface where dnsmasq will listen on, we need it on localhost(lo) and network(eth0)
interface=lo
interface=eth0
# IP pool range for our DHCP allocation and expiration time
dhcp-range=192.168.1.10,192.168.1.40,24h
# Setting up the TPlink router as a gateway
dhcp-option=3,192.168.1.1
# List of external DNS servers, our server (pogo) as primary, then others (OpenDNS)
dhcp-option=6,192.168.1.2,208.67.222.222
# Asus (laptop) ethernet, fixed IP & hostname
dhcp-host=11:11:11:11:11:11,192.168.1.10,asus
# Nexus5 fixed hostname
dhcp-host=22:22:22:22:22:22,nexus5
Using the dhcp-host
line we can set specific rules for naming a device stating its MAC address. In examples above, I’ve set my asus
laptop to always get the same IP address and hostname. Then below, I’ve similarly set a fixed hostname nexus5
to my phone. Since the device will be always reachable via that hostname, it doesn’t matter what IP address it has.
Note: I’ve masked the MAC addresses on purpose, since they’re uniquely identifiable.
For our Pogoplug E02 to server as a local DHCP server, we need to disable those services first on our existing router/modem. See the device instructions for that.
Now we start the dnsmasq service and enable it for starting automatically at boot.
$ sudo systemctl start dnsmasq
$ sudo systemctl enable dnsmasq
Testing
At first we can check the logs if the devices were properly identified using DHCP.
$ sudo journalctl -b | grep dnsmasq-dhcp
Aug 24 06:55:37 pogo dnsmasq-dhcp[1209]: DHCPREQUEST(eth0) 192.168.1.18 22:22:22:22:22:22
Aug 24 06:55:37 pogo dnsmasq-dhcp[1209]: DHCPACK(eth0) 192.168.1.18 22:22:22:22:22:22 nexus5
Aug 24 08:42:51 pogo dnsmasq-dhcp[22173]: DHCPDISCOVER(eth0) 11:11:11:11:11:11
Aug 24 08:42:51 pogo dnsmasq-dhcp[22173]: DHCPOFFER(eth0) 192.168.1.10 11:11:11:11:11:11
Aug 24 08:42:51 pogo dnsmasq-dhcp[22173]: DHCPREQUEST(eth0) 192.168.1.10 11:11:11:11:11:11
Aug 24 08:42:51 pogo dnsmasq-dhcp[22173]: DHCPACK(eth0) 192.168.1.10 11:11:11:11:11:11 asus
Now we try and reach devices amongst themselves in the network using their hostname. Here’s an example for the pinging the asus
laptop from pogo
.
$ sudo ping -c 4 asus.lan.tdkl.eu
PING asus.lan.tdkl.eu (192.168.1.10) 56(84) bytes of data.
64 bytes from asus.lan.tdkl.eu (192.168.1.10): icmp_seq=1 ttl=128 time=0.382 ms
64 bytes from asus.lan.tdkl.eu (192.168.1.10): icmp_seq=2 ttl=128 time=0.446 ms
64 bytes from asus.lan.tdkl.eu (192.168.1.10): icmp_seq=3 ttl=128 time=0.430 ms
64 bytes from asus.lan.tdkl.eu (192.168.1.10): icmp_seq=4 ttl=128 time=0.415 ms
We can also notice the asus
got the correct IP as we’ve set it above.
Now let’s ping nexus5
phone from pogo
.
$ sudo ping -c 4 nexus5.lan.tdkl.eu
PING nexus5.lan.tdkl.eu (192.168.1.18) 56(84) bytes of data.
64 bytes from nexus5.lan.tdkl.eu (192.168.1.18): icmp_seq=1 ttl=64 time=171 ms
64 bytes from nexus5.lan.tdkl.eu (192.168.1.18): icmp_seq=2 ttl=64 time=297 ms
64 bytes from nexus5.lan.tdkl.eu (192.168.1.18): icmp_seq=3 ttl=64 time=133 ms
64 bytes from nexus5.lan.tdkl.eu (192.168.1.18): icmp_seq=4 ttl=64 time=249 ms
Also the Nexus 5 phone is reachable per its name across all clients in the network. To test that, here’s the same ping command from the nexus5
phone to asus
laptop.
And vice versa.
C:\Windows\system32>ping nexus5.lan.tdkl.eu
Pinging nexus5.lan.tdkl.eu [192.168.1.18] with 32 bytes of data:
Reply from 192.168.1.18: bytes=32 time=85ms TTL=64
Reply from 192.168.1.18: bytes=32 time=90ms TTL=64
Reply from 192.168.1.18: bytes=32 time=302ms TTL=64
Reply from 192.168.1.18: bytes=32 time=122ms TTL=64
As per tests, DHCP and LAN clients name resolving work correctly.
Now let’s try with testing if the local caching DNS server works. We’ll use the dig
tool. If you’re missing it, install it via pacman
.
$ sudo pacman -Sy dnsutils
With dig
installed, we’ll query an address and compare the results between initial hit and cached result. At first we try with a non cached query.
$ dig www.google.com
; <<>> DiG 9.9.2-P2 <<>> www.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64525
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 235 IN A 173.194.66.106
www.google.com. 235 IN A 173.194.66.147
www.google.com. 235 IN A 173.194.66.99
www.google.com. 235 IN A 173.194.66.103
www.google.com. 235 IN A 173.194.66.104
www.google.com. 235 IN A 173.194.66.105
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Aug 24 09:31:45 2014
;; MSG SIZE rcvd: 139
The address resolved properly with status: NO ERROR
, query answer time was 10 miliseconds. Now if we repeat the query again, dnsmasq won’t query an external DNS server for the result, but use the cached result to return the answer much faster.
$ dig www.google.com
; <<>> DiG 9.9.2-P2 <<>> www.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2027
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 232 IN A 173.194.66.105
www.google.com. 232 IN A 173.194.66.104
www.google.com. 232 IN A 173.194.66.103
www.google.com. 232 IN A 173.194.66.99
www.google.com. 232 IN A 173.194.66.147
www.google.com. 232 IN A 173.194.66.106
;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Aug 24 09:31:48 2014
;; MSG SIZE rcvd: 139
In the repeated query, the time for answer was 3 miliseconds, which is quite a speed up and demonstrates the benefits of a local caching DNS server.