What is more annoying to people at home, that having their internet services go down? How about the internet service is still working, but other services like DHCP and DNS aren't working and therefore blaming the internet service.
As it turns out, my wifi router at home isn't great at running both of those services. Not only that but because they're on the router, I can't do things like block malware and ads like you can with a pi-hole. If you don't know about the pi-hole, I really think you should give take a look at it. Using a Raspberry Pi, you can run DNS and even DHCP on it and it'll filter all of those ads for you. So, I did that.
Service DID improve quite a bit. People were happy! But, whenever I had to do work on the Pi, like update it, reboot it, etc, then the service would once again go down.
That was when I decided to look at creating a more robust service. Enter 2 Raspberry Pi and ISC's implementation of DHCP. And while I was at it, thought I'd look to see if I could get the same malware and ad blocking as you can with ISC's BIND. The short answer to that was, yes, yes you can.
DHCP
Install DHCP with apt.
sudo apt install isc-dhcpd
DHCP as HA is a piece of cake. Just following the documentation at
https://kb.isc.org/docs/aa-00502
You can copy the configs and set the options that are right for your environment. I've put a copy (but slightly modified) version of what I am using. The main thing is to change the key and your IP ranges. Also, if you don't have a domain, you should buy one, they're relatively cheap. You could use the pseudo-tld ".home" so setting up "ns1.yourname.home" would work instead of "ns1.example.org" shown below.
Primary dhcp server
# option definitions common to all supported networks...
option domain-name "bulteel.home";
option domain-name-servers ns1.bulteel.home, ns2.bulteel.home;
default-lease-time 3600;
max-lease-time 7200;
# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
failover peer "failover-partner" {
primary;
address dhcp-primary.bulteel.home;
port 519;
peer address dhcp-secondary.bulteel.home;
peer port 520;
max-response-delay 60;
max-unacked-updates 10;
mclt 3600;
split 128;
load balance max seconds 3;
}
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1, router.bulteel.home;
pool {
failover peer "failover-partner";
range 192.168.1.50 192.168.1.250;
}
}
# insert this (with your own key text substituted) into dhcpd.conf on primary and secondary.
omapi-port 7911;
omapi-key omapi_key;
key omapi_key {
algorithm hmac-md5;
secret generate-this-with-dnssec-keygen-see-isc-docs==;
}
Secondary dhcp server
# option definitions common to all supported networks...
option domain-name "bulteel.home";
option domain-name-servers ns1.bulteel.home, ns2.example.bulteel.home;
default-lease-time 3600;
max-lease-time 7200;
# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;
# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
# This is a very basic subnet declaration.
#subnet 10.254.239.0 netmask 255.255.255.224 {
# range 10.254.239.10 10.254.239.20;
# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
#}
failover peer "failover-partner" {
secondary;
address dhcp-secondary.bulteel.home;
port 520;
peer address dhcp-primary.bulteel.home;
peer port 519;
max-response-delay 60;
max-unacked-updates 10;
load balance max seconds 3;
}
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1, router.bulteel.home;
option domain-name-servers 192.168.1.7, 192.168.1.9;
pool {
failover peer "failover-partner";
range 192.168.1.50 192.168.1.250;
}
}
# insert this (with your own key text substituted) into dhcpd.conf on primary and secondary.
omapi-port 7911;
omapi-key omapi_key;
key omapi_key {
algorithm hmac-md5;
secret generate-this-with-dnssec-keygen-see-isc-docs-copy-from-primary==;
}
Just restart both dhcp servers and make sure they're set to boot up. (systemctl enable isc-dhcp-server ; systemctl restart isc-dhcp-server)
DNS
Now there are two things you need to do for DNS. You need to setup RPZ(s) and then a master/slave setup. Neither of these is hard to do.
First, let's do the master/slave setup.
Install the software on both Pi.
sudo apt install bind9 dns-utils
Configure the master. Configure the slave. Job done. Do you have your own domain and you want to have internal DNS resolution of a host? You can even setup DHCP to dynamically update DNS.
Bind on Debian separates things into named.conf.local and named.conf.options files.
In the named.conf.local of the master
zone "rpz.example.com" {
type master;
also-notify { 192.168.1.5; };
file "/var/lib/bind/db.rpz.example.com";
};
zone "bulteel.home" {
type master;
also-notify { 192.168.1.5; };
file "/var/lib/bind/bulteel.home.hosts";
allow-transfer { 192.168.0.9; };
allow-update { key "rndc-key"; };
};
zone "1.168.192.in-addr.arpa" {
type master;
also-notify { 192.168.1.5; };
file "/var/lib/bind/db.1.168.192.in-addr.arpa";
allow-transfer { 192.168.1.5; };
allow-update { key "rndc-key"; };
};
In the named.conf.local of the slave:
zone "rpz.example.com" {
type slave;
file "/var/lib/bind/db.rpz.example.com";
masters { 192.168.1.4; };
};
zone "bulteel.home" {
type slave;
file "/var/lib/bind/bulteel.home.hosts";
masters { 192.168.1.4; };
};
zone "1.168.192.in-addr.arpa" {
type slave;
file "/var/lib/bind/db.1.168.192.in-addr.arpa";
masters { 192.168.1.4; };
};
Once that's done, you add domains to the RPZ file using the py-hole-bind script located
https://github.com/glenpp/py-hole/blob/master/py-hole-bind9RPZ
So, you might be asking about how to get stats and a nice dashboard? Well, that'll be for another blog post.