Today I was playing with OpenBSD routing domains the first time. Traditionally, multiple interfaces are connected to one routing table. A global switch called 'IP forwarding' will turn packet flows between all interfaces on or off. A more fine-grained control requires some kernel level packet filtering, usually done by PF on OpenBSD. However, with rdomains one can easily isolate traffic to specific routing domains, to separate networks in kernel space.

Excerpt from the rdomain(4) man page:

The traditional kernel routing system had a single table for routes and allowed only non-conflicting IP address assignments. The rtable feature allows multiple lookup tables for routes. The rdomain feature provides a way to logically segment a router between network paths.

Setup

The following, non-persistent example uses VLAN 71 as the underlying interface. Of course, any physical device can be specified as well. Please note one should always configure the rdomain first, interface IP second. The last command executes the route command for our newly created rdomain 71, providing a default gateway for that very routing table.

# ifconfig vlan71 rdomain 71 # ifconfig vlan71 192.168.71.1/24 # route -T71 -n add default 192.168.71.1

Our interface and rdomain should be up and running now. Note the newly appearing "rdomain 71":

$ ifconfig vlan71 vlan71: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> rdomain 71 mtu 1500 lladdr 32:37:36:64:33:33 index 15 priority 0 llprio 3 vlan: 71 parent interface: vio0 vnetid: 71 parent: vio0 groups: vlan status: active inet 192.168.71.1 netmask 0xffffff00 broadcast 192.168.71.255

To show the routing table content, issue the route command with the already learned -T flag:

$ route -T 71 -n show

Persistence!

In order to make that configuration survive a reboot, a hostname.vlan71 needs to be created in /etc as usual. It may look like this:

$ cat /etc/hostname.vlan71 rdomain 71 inet 192.168.71.1 255.255.255.0 NONE vlandev vio0 !route -T71 -n add default 192.168.71.1

Again, beware the order. rdomain definition first, IP assignments second.

rdomain-aware daemons

OpenBSD ships a number of daemons of which some are even rdomain-aware. Meaning, they are able to not only serve rdomain 0 but even 254 more :) One example is ntpd, that can be configured to offer network time for a specific routing table. Let's have a look at its self-explanatory configuration file:

$ cat /etc/ntpd.conf

listen on 192.168.26.1 listen on 192.168.71.1 rtable 71 server 0.ch.pool.ntp.org server 1.ch.pool.ntp.org server 2.ch.pool.ntp.org server 3.ch.pool.ntp.org sensor * constraints from "https://www.google.com"

rdomain ignorance

However, not all daemons are able to handle rdomains themselves. There's a nice way overcoming this little issue: rcctl(8) to the rescue.

The following commands will 'clone' the dhcpd daemon resource script by soft-linking it, so rcctl(8) is able to treat them separately, with individual flags:

# ln -s /etc/rc.d/dhcpd /etc/rc.d/dhcpd71 # rcctl enable dhcpd71 # rcctl set dhcpd71 rtable 71 # rcctl set dhcpd71 flags "-c /etc/dhcpd71.conf"

One can always double check the generated rc(8) configuration file /etc/rc.conf.local. That's it! Of course, the content of dhcpd71.conf needs to be adjusted, so it only serves addresses for the newly created routing domain. One can now start/stop both dhcpd daemons:

# rcctl start dhcpd dhcpd (ok) # rcctl start dhcpd71 dhcpd71 (ok)

The ps(8) command is able to show which process is running in which routing domain, using the "-o rtable" flags (see last column):

# ps aux -o rtable | grep dhcp _dhcp 63587 0.0 0.1 636 1508 ?? Isp 12:16PM 0:00.00 /usr/sbin/dhcpd 0 _dhcp 32192 0.0 0.1 588 1464 ?? Isp 12:20PM 0:00.05 /usr/sbin/dhcpd 71

Packet filtering

Depening on the use case, the OpenBSD packet filter is used to control the packet flow between routing domains. A couple of example rules will provide an idea of what's possible. More detailed information can be found in the according man pages: pfctl, pf.conf.

match out on rdomain 71 to !vlan71 nat-to egress rtable 0 pass in log on rdomain 71 proto tcp to port 80

Summary

OpenBSD rdomains are a very elegant way to isolate routing traffic from each other. Daemons can serve for specific rdomains which obsolete clunky ip or listener restrictions. Management of multiple daemons of a kind is easily possible using rcctl. Packet flow between routing domains is managed by the packet filter PF.

References

Virtualizing the OpenBSD Routing Table - Joel Knight