DNS, DHCP and routing for the internal network

Since your home network is connected only to your home server (right?), in order to be able to navigate and use the home network you must configure some services on your home server.

In detail, you will need:

  • one DNS server, so that devices in the home network can resolve names to addresses (and filter ads)
  • one DHCP server, so provide devices in the home network with automatic configuration
  • one default gateway and router: to allow devices in the home network to access stuff on the internet

At first i have been using DNSmasq, which is a seemingly easy approach to both DNS and DHCP for the home network. After a lengthly and annoying debugging session with Android devices i found out that DNS has evolved a lot and DNSMasq is today a bit outdated.

I decided then to go straight to the Gentoo standard DHCP server and Unbound DNS resolver/forwarder, and i couldn't be happier.

For future reference, the older DNSMasq information has been moved to a separate page.

To create a router, you will be using the Linux built-in great nftables tools that today has replaced the older iptables.

Unbound, your very own DNS resolver

The DNS (Domain Name System) is how _names_ are converted to _addresses_ on the internet. Historically one of the oldest Internet Services still in use today, it suffers from a lot of drawbacks and issues, specially on the privacy side of things. The original plain-text protocol (on port 53, UDP) has been extended over the years with a few improvements like DNS over TLS (DoT) and DNS over HTTPS (DoH). Both the new extensions provide more privacy, as the requests are encrypted your ISP and middleman cannot snoop every website you visit, and more robustness as, paired with DNSSEC, it is now more difficult to feed you malicious DNS responses and redirect your traffic to bad websites (think of malaware and such).

Unbound is a modern DNS server which is capable of resolving and forwarding your requests using DoT and DoH. I will show you how to use Unbound for your home network using DoT. DoH has some drawbacks (it requires port 443) and is currently not really standardized.

It's very simple to setup on Gentoo (see here) and it also support DNSSEC (which, at this time, i have not configured yet).

So, first of all enable DNSCrypt for Unbound by creating the file /etc/package.use/unbound:

unbound
net-dns/unbound dnscrypt

then emerge Unbound:

emerge unbound

I am using the following /etc/unbound/unbound.conf:

unbound.conf
server:
        verbosity: 1
        num-threads: 2
        interface: 10.0.0.1     # Listen to home interface
        interface: 127.0.0.1   #  and listen to localhost as well
        port: 53                      
        so-reuseport: yes
        cache-min-ttl: 300
        cache-max-ttl: 86400
        do-ip4: yes
        do-ip6: yes
        do-udp: yes
        do-tcp: yes
        use-systemd: no
        do-daemonize: yes
       # For security reasons, only clients on the home interface can use the DNS service        
       access-control: 10.0.0.0/24 allow   
        access-control: 127.0.0.1/8 allow     # and, of course, localhost as well
        use-syslog: yes
        hide-identity: yes
        hide-version: yes
        harden-short-bufsize: yes
        harden-large-queries: yes
        harden-glue: yes
        harden-dnssec-stripped: yes
        harden-below-nxdomain: yes
        harden-referral-path: yes
        harden-algo-downgrade: yes
        qname-minimisation: yes
        qname-minimisation-strict: no
        aggressive-nsec: yes
        use-caps-for-id: yes
        prefetch: yes
        rrset-roundrobin: yes
        minimal-responses: yes
        # This will enable DoT (upstream)
        tls-cert-bundle: "/etc/ssl/certs/ca-certificates.crt"
        # This will add Ad blocking
        include: /etc/unbound/adservers.conf
       # Add a local resolve for the home server
        local-zone: "home.mydomain.com." redirect
        local-data: "casa.gardiol.org. A 10.0.0.1"

remote-control:
        control-enable: yes

forward-zone:
        name: "."
        # Use Google DNS as upstream DNS (put here your preferred ones if not Google)
        forward-tls-upstream: yes
        forward-addr: 8.8.8.8@853
        forward-addr: 8.8.4.4@853

To configure specific _internal_ hosts, you need to define a local-zone and a matching local-data rows as defined above. You might want to move these information to specific files to include (like the adservers.conf) for easier maintenance if you have lots of internal names.

At this point, read the Ads Blocking page to create the /etc/unbound/adservers.conf file before continuing.

You need to populate your /etc/resolv.conf with Unbound as the default nameserver:

resolv.conf
# My own local DNS resolver (Unbound)
nameserver 127.0.0.1

Don't forget to autostart Unbound service:

rc-update add unbound default
/etc/init.d/unbound start

NOTE: as far as i managed to understand, DoT is always enabled on the upstream connection only. You do not need, not want, DoT within your home network.

NOTE 2: DoH is still a work in progress and since it require a interface with the local NGINX reverse proxy, because it's based on HTTPS and port 443, i have not bothered yet to set it up. This doesn't play well with newer Android devices and causes the Unbound to be ignored no matter what i tried, but in any case being port 443 shared with any other web traffic, it is impossible to force DoH on Android devices the way you can force standard DNS traffic on port 53, so probably not useful to bother about it anyway.

DHCP server

Using the ISC DHCP server is the best and easier choice.

You should disable the ISC DHCP client as it is deprecated (and you already have the Gentoo's DHCPCD client anyway), so create the file /etc/portage/package.use/dhcp:

dhcp
net-misc/dhcp -client

then just emerge it:

emerge net-misc/dhcp

Edit the DHCP configuration file /etc/dhcp/dhcpd.conf:

dhcpd.conf
authoritative;
subnet 192.168.0.0 netmask 255.255.255.0 {
     # disable DHCP on ISP#1 upstream network
}
subnet 192.168.1.0 netmask 255.255.255.0 {
     # disable DHCP on ISP#2 upstream network
}
subnet 10.0.0.0 netmask 255.255.255.0 {
  range 10.0.0.100 10.0.0.250;
  option domain-name-servers 10.0.0.1;
  option domain-name "mydomain.com";
  option routers 10.0.0.1;
}
host fixed-ip-pc {
    hardware ethernet 12:34:56:78:9a:bc;
    fixed-address 10.0.0.95;
}

Here i assign a pool od dynamic IP addresses (from 100 to 254) on the 10.0.0.0 subnet. Addresses under 100 can be used for static assignments. For example, i use static IPs for all my OpenWRT Access Points and wired security cameras, and dynamic for all other devices. I have also defined my two ISP's subnets to explicitly disable DHCP assignments on them, which is not needed and might be an attack vector.

This config will also ensure that all devices will use the home server both as DNS server and gateway.

This will not work for devices that use hard-coded DNS servers (like Fire Sticks and Google Chromecasts…) but there is a workaround for those too, and i will show you on Routing on the Home Server.

This will not work with some Android devices either, and it's a massive PITA, because Android is moving to DoH and this will totally bypass your internal Unbound resolver, and there is no way to fix it. This means also issues with Ad Blocking, go figure why Google is pushing this hard.

Well, this is almost all. Start dhcp service and make it start on boot:

rc-update add dhcp default
/etc/init.t/dhcp start

Now you can connect your devices to the home network and they will get an IP address and a full network configuration to go with it.