Redundant OpenBSD Firewalls

Part 5 - Redundant Network Services

In Part 5 we will configure the internal redundant services. Most of these steps take place on fw2, but not all. As we go along, we will have to modify some of our existing configurations on fw1. You’ll have to pay close attention so you don’t do stuff on the wrong server.

Time server

We configure NTP exactly the way we did on fw1 with the exception of the IP address we listen on.

Enable the ntp daemon:

fw2# rcctl enable ntpd

Now add a few lines to /etc/sync-fw-config:

# ntpd configuration
dosync /etc/ntpd.conf
sed -i "/^listen on $FW1/s/$FW1/$FW2/" /etc/ntpd.conf
rcctl restart ntpd

With the second time server running, we now need to modify our DHCP server configuration on fw1 so it will give out both time servers to the clients on our internal network. Change the following line in /etc/dhcpd.conf:

option ntp-servers,;

And restart the service:

fw1# rcctl restart isc_dhcpd

Sync the changes on fw2, which will start the NTP service for us:

fw2# sh /etc/sync-fw-config

Authoritative name server

We have a couple of options for how to create a redundant authoritative name server. One option would be to set up zone transfers between the two instances of nsd. The other option is to have our sync-fw-config script do it. I chose to use the script, which keeps nsd only listening on localhost.

Start by enabling nsd on fw2:

fw2# nsd-control-setup
fw2# rcctl enable nsd

On fw2 add the following lines to /etc/sync-fw-config:

# sync nsd
dosync /var/nsd/etc/nsd.conf
dosync /var/nsd/zones/
rcctl restart nsd

And then resync:

fw2# sh /etc/sync-fw-config

Caching resolver

When we set up fw1 we created CARP addresses for our two name service IP addresses. We now need to add fw2 to those CARP groups.

On fw2 put the following into /etc/hostname.carp1:

inet vhid 132 carpdev vr0 pass vhid132passwd advskew 128 description "name server 1"

And this into /etc/hostname.carp2:

inet vhid 133 carpdev vr0 pass vhid133passwd advskew 128 description "name server 2"

Bring up the interfaces:

fw2# sh /etc/netstart carp1 carp2

Configure unbound:

fw2# rcctl enable unbound
fw2# unbound-control-setup

Add a few lines to /etc/sync-fw-config:

# unbound
dosync /var/unbound/etc/unbound.conf
sed -r -i "/^[[:space:]]*interface:[[:space:]]*$FW1/s/$FW1/$FW2/" /var/unbound/etc/unbound.conf
dosync /var/unbound/etc/root.hints
rcctl restart unbound

And resync our configs:

fw2# sh /etc/sync-fw-configs

To properly test this new redundant configuration we need to do it from another host on the internal network.

$ dig @ www.eff.org
$ dig @ fw2.kotfu.net

Force the carp interfaces to fail over to fw2 by shutting them down on fw1:

fw1# ifconfig carp1 down
fw1# ifconfig carp2 down

Then test again from our internal network host.

$ dig @ www.eff.org
$ dig @ fw2.kotfu.net

Make fw1 the primary again:

fw1# ifconfig carp1 up
fw1# ifconfig carp2 up


First we need to install and enable the reference dhcpd server on fw2:

fw2# pkg_add -vv isc-dhcp-server
fw2# rcctl enable isc_dhcpd
fw2# rcctl set isc_dhcpd flags "-user _isc-dhcp -group _isc-dhcp vr0"

Now we need to create our configuration files. Most of the configuration can be shared with fw1, but not all of it. So we are going to split the configuration on fw1 into two files, with all the common elements in a single file which we can copy to fw2.

On fw1:

fw1# cd /etc
fw1# cp dhcpd.conf dhcpd.shared.conf

Change /etc/dhcpd.conf so it contains:

# dhcpd configuration
failover peer "failover-partner" {
  port 519;
  peer address;
  peer port 520;
  max-response-delay 60;
  max-unacked-updates 10;
  mclt 3600;
  split 128;
  load balance max seconds 3;

include "/etc/dhcpd.shared.conf";

Then edit /etc/dhcpd.shared.conf and remove the entire section that starts with failover peer "failover-parther".

With the configuration split into two files, restart the server:

fw1# rcctl restart isc_dhcpd

On fw2 we will create the configuration for the secondary dhcp server. Create /etc/dhcpd.conf:

# dhcpd configuration
failover peer "failover-partner" {
  port 520;
  peer address;
  peer port 519;
  max-response-delay 60;
  max-unacked-updates 10;
  load balance max seconds 3;

include "/etc/dhcpd.shared.conf";

Now add the following lines to /etc/sync-fw-config:

# dhcpd
dosync /etc/dhcpd.shared.conf
rcctl restart isc_dhcpd

Then run the sync script:

fw2# sh /etc/sync-fw-config

If it’s all working you should see a bunch of logs in /var/log/daemon about the DHCP server synchronizing, and then an entry that says "Both servers normal".

This method of DHCP redundancy requires synchronized time on both servers. If you don’t see "Both servers normal" in the logs, or if the failover doesn’t appear to be working, check the function of the time server. Once you are certain the clocks on both servers are synchronized, you can force the two dhcpd instances to rebuild and resynchronize their lease databases. Execute the following commands on both servers:

fw2# rcctl stop isc_dhcpd
fw2# rm /var/db/dhcpd.leases

Once that’s done, then restart the DHCP daemon on both servers. It’s important that you don’t restart either daemon until you have removed the lease databases for both servers.

fw2# rcctl start isc_dhcpd

Redundant OpenBSD Firewall Guide