Vladimir Sedach

Have Emacs - Will Hack

July 24, 2018

IPv6 home LAN with OpenBSD

IPv6 usage has really taken off and is on track to encompass half of all Internet traffic in the next couple of years. I decided to spend some time configuring IPv6 on my home network. It is really exciting to get real, globally routable IP addresses for all of your machines. I plan on using this capability to expand the services I self-host, as well as to increase my participation in federated and peer-to-peer networks. I wrote up some notes about my experience setting up IPv6 with OpenBSD. Hopefully they will help you join an equal, NAT-free Internet!

Machines on my home network are set up with /etc/hosts aliases to enable convenient access, no matter whether they connect from an Ethernet port or Wi-Fi or switch between the two. One of the things this enables are automated backups (using cron, rsync, and hardlink snapshots) between each of the machines whenever they are running and connected to my home network. To start, I added IPv6 to this local network configuration.

This is what the initial network configuration looked like:

The router has all local network interfaces (several Ethernet and one Wi-Fi) bridged with a virtual Ethernet interface holding the IP address assignment.

/etc/hostname.bridge0
add vether0
add em0
add em1
add em2
add athn0
up
/etc/hostname.emX
up
/etc/hostname.athn0
mode 11n mediaopt hostap chan 1 nwid YourWifi wpakey ClearTextPassword
up

The interesting part is all done on the virtual interface:

/etc/hostname.vether0
inet 10.0.0.1 255.255.255.0 10.0.0.255

dhcpd is configured to hand out IPv4 addresses to any computers that connect to the Ethernet or Wi-Fi, and assign fixed addresses to my own machines, so that laptops get the same IP address whether they connect via Ethernet or Wi-Fi:

/etc/dhcpd.conf
subnet 10.0.0.0 netmask 255.255.255.0 {
	option domain-name-servers 10.0.0.1;
	option domain-name "oneofus.la";
	option routers 10.0.0.1;
	range 10.0.0.50 10.0.0.99;

	host desktop {
		hardware ethernet AA:AA:AA:AA:AA:AA;
		fixed-address 10.0.0.2;
	}

	host laptop1_wifi {
                hardware ethernet BB:BB:BB:BB:BB:BB;
		fixed-address 10.0.0.3;
	}

	host laptop1_ethernet {
		hardware ethernet CC:CC:CC:CC:CC:CC;
		fixed-address 10.0.0.3;
	}
}

On the host machines, trunking between Ethernet and Wi-Fi enables automatic, uninterrupted hand-off between the two:

/etc/hostname.alc0
up
/etc/hostname.wpi0
nwid YourWifi wpakey ClearTextPassword
up
/etc/hostname.trunk0
trunkproto failover trunkport alc0
trunkport wpi0
dhcp
/etc/hosts
10.0.0.1	router
10.0.0.2	desktop
10.0.0.3	laptop1

The problem with this approach is that there are only three private ranges of addresses used for IPv4. If you take your laptop somewhere else that is configured to hand out 10.0.0.x addresses over DHCP, the aliases in /etc/hosts will point to random computers. If you have periodic scripts running from cron that reference these aliases, you might get unexpected errors, depending on what the scripts try to do.

You can get around this by resolving hostnames with multicast DNS (trading off the possibility of address collisions on other networks to name collisions on other networks) or running a split-horizon DNS server on your home network, instead of using /etc/hosts. Fortunately, IPv6 provides several excellent alternatives that avoid this complexity.

The simplest alternative is to use dynamic DNS for the publicly routable IPv6 addresses that your ISP provides you. The pros of this approach is that your home computers can now be reached even when you are away from home - the cron backup scripts can now provide private offsite backups when you are away. The cons are that you might not want the backup scripts to run and use up bandwidth when you are on a low-speed outside connection; you will not be able to do the DNS lookups if your Internet connection goes down; and your ISP might not provide you with IPv6.

The next alternative is to use unique local addresses to provide your home network with its own private IPv6 network address range (similar to IPv4 private address ranges), one that is very unlikely to be used on any other network (a big improvement over IPv4 private address ranges). The cons is that this involves work to configure your network, either setting up a SLAAC or DHCPv6 server, or doing static address allocation. With IPv6, we can do better.

IPv6 comes with automatic provisioning of IP addresses on local networks via a mechanism called link-local addresses. Link-local addresses are derived from persistent machine configuration information (usually MAC addresses) in a way that makes collisions highly unlikely, and are only reachable on the current network segment. This makes link-local addresses ideal for the small home network use case.

By using link-local addresses on bridged or trunked virtual interfaces in OpenBSD, you can have /etc/hosts aliases unique to your home network, that work across Ethernet and Wi-Fi connections automatically.

One of the great things about IPv6 is that it makes it easy to have any number of IP addresses bound to a single interface, so you can use any combination of the above techniques at the same time to fit your particular network.

The following is how the configuration given above can be extended to dual-stack IPv6 using link-local addresses:

On the router:

/etc/hostname.vether0
inet 10.0.0.1 255.255.255.0 10.0.0.255
inet6 eui64

On the hosts:

/etc/hostname.trunk0
trunkproto failover trunkport alc0
trunkport wpi0
dhcp
inet6 eui64
/etc/hosts
fe80::AAAA:AAAA:AAAA:AAAA%trunk0	router
fe80::BBBB:BBBB:BBBB:BBBB%trunk0	desktop
fe80::CCCC:CCCC:CCCC:CCCC%trunk0	laptop1

Note that link-local addresses must be suffixed with the interface they apply to (the link in link-local).

Debian 9 and probably other GNU/Linux distributions do not support link-local addresses in /etc/hosts. They can be accommodated with a statically assigned unique-local address scheme:

On the router:

/etc/hostname.vether0
inet 10.0.0.1 255.255.255.0 10.0.0.255
inet6 eui64
inet6 alias fdXX:XXXX:XXXX::1

Where X is a randomly generated hexadecimal digit (see RFC-4193 for details).

On the hosts:

/etc/hostname.trunk0
trunkproto failover trunkport alc0
trunkport wpi0
dhcp
inet6 eui64
inet6 alias fdXX:XXXX:XXXX::2
/etc/hosts
fdXX:XXXX:XXXX::1	router
fdXX:XXXX:XXXX::2	desktop
fdXX:XXXX:XXXX::3	laptop1