pf rtables and setfib in FreeBSD

If one has multiple outgoing links to which one would like to use different routing tables the FreeBSD provides possibility through the setfib command but in order to have multiple routing tables one has to first compile a custom kernel with option ROUTETABLES in example simple kernel config:

include GENERIC
options         ROUTETABLES=4

After the kernel has been built and rebooted the different routing tables can be accessed as shown in the setfib(1) man page by issuing command setfib 0 netstat -rn. 0 is the default routing table.

After this one has to create the second routing table by prepending every route add command with setfib 1 route add… e.g:

# setfib 1 route add -net default

With packet filter one can control how the routing table is selected by using rtable option but it should be noted that this selection can only be done on the input of the packets as the routing decision is done at the input not at the output. Here is an example of very simple pf.conf that uses rtable rules and NATs everything to the external interface address:

# Macros
INT_IF = "em0"
EXT_IF = "bge0"
EXT_IF2 = "bge1"

table <private_nets> persist { 127/8, 172.16/12, 192.168/16, 169.254/16 }

# Options and default policy
set block-policy drop
set state-policy if-bound

# Packet normalization
scrub in                          all
scrub out on $EXT_IF all random-id
scrub        on $EXT_IF all reassemble tcp

# NAT/redirects

nat on $EXT_IF from <private_nets> to any -> ($EXT_IF)
nat on $EXT_IF2 from <private_nets> to any -> ($EXT_IF2)

# Filter rules
pass all
pass in from to any rtable 0
pass in from to any rtable 1