Adding IPv6 to My Home Network (2024-11-03)

Background

So there I was, going through life without giving a second thought to IPv6. IPv4 worked fine for me, and why change what isn't broken, right? Well, sometimes life changes, and you start work for a new company, and that company actually uses IPv6. At that point, learning IPv6 becomes important, I think we'll all agree.

This documents how I added IPv6 to my home network, which runs OpenBSD, using OpenBSD's ifconfig, slaacd, dhcp6leased, rad, and unbound. This should serve as a guide to other people in the same situation, but be aware you need to be running at least OpenBSD 7.6, as that is the version that added support for dhcp6leased and updated rad to handle DHCPv6 PD (prefix delegation). For older OpenBSD versions, you'll have to use ports, and there are multiple guides for that, use your friendly neighborhood search engine.

I use AT&T as my internet service provider, and am stuck with DSL, as AT&T still, in this day and age, does not support fiber at my address. The firewall for my home network has two physical interfaces, em0 (internal network) and em1 (connection to the AT&T DSL modem, a BGW-210).

IPv6 Setup

Not wanting to use IPv6 previously, on my firewall, I had the following in /etc/hostname.em1:

-inet6
dhcp

and the following in /etc/hostname.em0:

-inet6
inet 10.XX.YY.1 255.255.255.0 NONE

I don't think the -inet6 lines were actually needed, as that's the default behavior for interfaces on OpenBSD, except for lo0.

So as a first step, I needed to enable IPv6 on both interfaces, and set autoconf on the external interface. On the internal interface, I also added an IPv6 ULA alias, so that computers in the internal network can use a static IPv6 address to access the firewall, in addition to the dynamic internet-routable IPv6 address:

# ifconfig em1 inet6 autoconf
# ifconfig em0 inet6
# ifconfig em0 inet6 alias fd00:XXYY::1/64

As slaacd is enabled by default on OpenBSD, I had previously disabled it in rc.conf.local:

slaacd_flags=NO

So I needed to start slaacd:

# rcctl -f start slaacd # -f to force starting as it is disabled

Unfortunately, using ifconfig and slaacd did not result in getting a public IPv6 address, only a link-local IPv6 address. With some help from my friends, and some more searching online, I found I needed to update pf.conf to add a firewall rule for slaacd to work, and another would that would be needed later for DHCPv6 to work:

pass in on $ei inet6 proto icmp6 all
pass in on $ei inet6 proto udp from fe80::/10 port dhcpv6-server to fe80::/10 port dhcpv6-client no state

This type of firewall rule isn't needed in the IPv4 case, because dhcpleased (used for DHCPv4 on OpenBSD) uses bpf, which is not subject to firewall rules.

Anyway, after updating /etc/pf.conf, and then reloading the firewall rules:

# pfctl -f /etc/pf.conf

I was able to get a public IPv6 address on the external interface of the firewall.

Next step was allowing the firewall to route IPv6 traffic:

# sysctl net.inet6.ip6.forwarding=1

To get DHCPv6 PD to work, I needed to use dhcp6leased, which is configured through a simple dhcp6leased.conf configuration file, which only requires one line:

request prefix delegation on em1 for { em0 }

Then I needed to start dhcp6leased:

# rcctl -f start dhcp6leased

To assign IPv6 addresses to clients on the internal network, I had to create a rad.conf configuration file, which was more complex than dhcp6leased.conf, but still not too bad:

dns {
  nameserver {
    fd00:XXYY::1
  }
}

interface em0

Anyway, after editing that configuration file, I needed to start rad:

# rcctl -f start rad

After that change, devices on my internal network could get both public IPv6 addresses as well as ULA addresses. For my OpenBSD desktop, I had to allow IPv6 (ifconfig em0 inet6 autoconf), and also start slaacd.

After getting everything working, I needed to make sure the changes stick around after a reboot. So on the firewall, I edited the /etc/hostname.em1 (replacing dhcp with the more modern inet autoconf):

inet autoconf
inet6 autoconf

and /etc/hostname.em0 files:

inet 10.XX.YY.1 255.255.255.0 NONE
inet6
inet6 alias fd00:XXYY::1/64

I also set slaacd, dhcp6leased, and rad to be automatically enabled at boot:

# rcctl enable slaacd dhcp6leased rad

I also needed to allow IPv6 routing by default by adding the following to sysctl.conf:

net.inet6.ip6.forwarding=1

For my desktop, I updated hostname.em0:

inet 10.XX.YY.1 255.255.255.0 NONE
inet6 autoconf

and enabled slaacd there as well:

# rcctl enable slaacd

DNS

Just in case I wanted to have a IPv6-only client in my internal network, and I wanted that client to be able to resolve non-public DNS names, I needed my DNS infrastructure to handle IPv6. My existing unbound.conf configuration started with:

server:
        interface: 0.0.0.0
        num-threads: 1
        do-ip6: no

        access-control: 0.0.0.0/0 refuse
        access-control: 127.0.0.0/8 allow
        access-control: 10.XX.YY.0/24 allow

I needed to edit it to allow IPv6:

server:
        interface: 0.0.0.0
        interface: ::0
        num-threads: 1
        do-ip6: yes

        access-control: 0.0.0.0/0 refuse
        access-control: 127.0.0.0/8 allow
        access-control: 10.XX.YY.0/24 allow

        access-control: ::0/0 refuse
        access-control: ::1/128 allow
        access-control: fd00:XXYY::0/16 allow

Then I added IPv6 entries for the existing IPv4 entries, in the form: local-data: "host.domain.local. IN AAAA fd00:XXYY::1"

Then I needed to restart unbound (not just reload, due to the interface addition):

# rcctl restart unbound

Then I could resolve DNS address using IPv6, both on the same machine and from other machines, served by my local DNS server:

$ dig @fd00:XXYY::1 +short AAAA host.domain.local
fd00:XXYY::1

Conclusion

Overall, IPv6 and DHCPv6 PD is very easy to setup on OpenBSD 7.6, using only tools provided in the base system, with no need for ports. Using both dynamic global IPv6 addresses as well as static ULA IPv6 addresses works fairly well. It's still additional complexity, since you still have to run an IPv4 network to connect to IPv4-only hosts. However, if some day in the future, IPv4 goes away, at least I'm prepared. Also, I can now to to ipv6.google.com in my browser and have it load!

Update (2024-11-04)

After I posted this, a fellow OpenBSD developer pointed out that I didn't need the following lines in rad.conf:

managed address configuration yes
other configuration yes

These lines are used when you are running a DHCPv6 server on your network, and I'm only running a DHCPv6 client. So I removed these lines from the rad.conf configuration above.