Configure DNS and DHCP
DHCP is the process your LAN clients perform when they are first
connected to the network: the client asks the router to configure an
IP address for them, they recieve the address, and can now get online.
DNS is how your LAN clients can ask the router what the IP address is
for any domain name, allowing you to easily navigate the Internet by
entering names like example.com
.
To configure DHCP and DNS for your LAN will require two interrelated services to run on the router:
-
dnscrypt-proxy is a local caching DNS proxy which can be configured to use Cloudflare DNS over HTTP (DoH) as the upstream resolver, or any other provider you choose.
-
dnsmasq is a DHCP server and DNS forwarder for small networks.
dnscrypt-proxy will be set to only listen on localhost port 53, therfore the LAN client cannot directly communicate with it. Dnsmasq is what the LAN client will interact with. In addition to being the DHCP server for the LAN, dnsmasq has the job of forwarding any DNS queries to the dnscrypt resolver on localhost.
Configure dnscrypt-proxy
## Configure the listen address for localhost only:
## Set the upstream cloudflare DNS resolver:
sed -i \
-e "s/^listen_addresses =.*/listen_addresses = ['127.0.0.1:53','[::1]:53']/" \
-e "s/^# server_names =.*/server_names = ['cloudflare']/" \
/etc/dnscrypt-proxy/dnscrypt-proxy.toml
## Hard code the dnscrypt resolver as the default:
## Lock the resolv config so it cannot be modified again:
chattr -i /etc/resolv.conf || true
rm -f /etc/resolv.conf
cat <<EOF > /etc/resolv.conf
nameserver ::1
nameserver 127.0.0.1
options edns0
EOF
chattr +i /etc/resolv.conf
## Enable the dnscrypt service:
systemctl enable dnscrypt-proxy
systemctl restart dnscrypt-proxy
Create dnsmasq service definition
## Create instantiable dnsmasq service file:
cat <<'EOF' > /etc/systemd/system/dnsmasq@.service
[Unit]
Description=dnsmasq for %i
Documentation=man:dnsmasq(8)
After=network.target
Before=network-online.target nss-lookup.target
Wants=nss-lookup.target
[Service]
ExecStart=/usr/local/sbin/dnsmasq-%i.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
PrivateDevices=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
EOF
## Reload systemd service files:
systemctl daemon-reload
Configure dnsmasq
nifty-filter can also configure dnsmasq. Specify your entire config in
a shell script /usr/local/sbin/dnsmasq-lan.sh
:
cat <<'EOF' > /usr/local/sbin/dnsmasq-lan.sh
#!/bin/bash
set -e
## Bind to the lan interface:
export INTERFACE=lan
export LISTEN_ADDRESS=192.168.10.1
## DHCP config:
export DOMAIN_LAN=lan.example.com
export GATEWAY_LAN=192.168.10.1
export DHCP_LAN_RANGE_START=192.168.10.50
export DHCP_LAN_RANGE_END=192.168.10.250
export DHCP_LAN_LEASE=12h
## Static DHCP Leases:
## bash array of "MAC_ADDRESS,IP_ADDRESS,HOST_NAME,LEASE_TIME"
STATIC_LEASES=(
## "9c:69:b4:65:7d:f8,192.168.10.2,arch-client1,12h"
## "9c:69:b4:65:7d:f9,192.168.10.3,arch-client2,12h"
)
## convert array to string:
export DHCP_LAN_STATIC_LEASES="${STATIC_LEASES[@]}"
## DNS config - Forward DNS to dnscrypt on localhost
export DNS_LAN=192.168.10.1
export DNS_UPSTREAM_1=::1
export DNS_UPSTREAM_2=127.0.0.1
nifty-filter dnsmasq | dnsmasq -C - --test
echo "## Applying dnsmasq config:"
(echo "## This file is generated by nifty-filter. DO NOT EDIT."; \
nifty-filter dnsmasq) > /tmp/dnsmasq-${INTERFACE}.conf
dnsmasq -C /tmp/dnsmasq-${INTERFACE}.conf -d --user=dnsmasq --pid-file
EOF
chmod +x /usr/local/sbin/dnsmasq-lan.sh
ln -sf /usr/local/sbin/dnsmasq-lan.sh ~/dnsmasq-lan.sh
Make sure to edit the following config variables:
DOMAIN_LAN
customize your own LAN domain name.DHCP_LAN_STATIC_LEASES
customize your own list of hosts that should have static DHCP leasesSTATIC_LEASES
is an intermediate array to help buildDHCP_LAN_STATIC_LEASES
, with a set of examples commented out.
Enable the dnsmasq service
systemctl enable dnsmasq@lan.service
systemctl restart dnsmasq@lan.service
systemctl status dnsmasq@lan.service --no-pager
Custom host names
dnsmasq is setup to prioritize any host names defined in /etc/hosts
and to resolve these by itself (without forwarding the query to
dnscrypt). You can put any names you want in this file, whether they
are masking real domains, or even if they are completely made up.
# Example /etc/hosts file
192.168.10.2 foo foo.lan.example.com
192.168.10.3 bar boatymcboatface bar.lan.example.com
Dnscrypt will only read the hosts file on startup, so you must restart
the dnsmasq service each time you edit /etc/hosts
:
systemctl restart dnsmasq@lan
## All names from /etc/hosts are resolved.
## Short, long, made up, doesn't matter:
$ dig foo
...
;; ANSWER SECTION:
foo. 0 IN A 192.168.10.2
$ dig foo.lan.example.com
...
;; ANSWER SECTION:
foo.lan.example.com. 0 IN A 192.168.10.2
$ dig boatymcboatface
...
;; ANSWER SECTION:
boatymcboatface. 0 IN A 192.168.10.3