Page MenuHomeFreeBSD

WIP: pf: Add RFC5549 support for route-to
Needs ReviewPublic

Authored by vegeta_tuxpowered.net on Jun 10 2025, 7:45 PM.
Tags
None
Referenced Files
F123708523: D50781.id156797.diff
Fri, Jul 18, 12:43 AM
Unknown Object (File)
Fri, Jul 4, 5:10 PM
Unknown Object (File)
Tue, Jul 1, 7:56 PM
Unknown Object (File)
Mon, Jun 30, 5:15 PM
Unknown Object (File)
Mon, Jun 30, 4:59 AM
Unknown Object (File)
Mon, Jun 30, 12:31 AM
Unknown Object (File)
Sun, Jun 29, 10:18 AM
Unknown Object (File)
Thu, Jun 26, 8:01 PM

Details

Reviewers
kp
Summary

When pfctl parses a pool it is aware of address family of each host,
at least when a host is an explicitly given IP address, not a pool or
interface. But kernel can't receive nor store this information in
struct pf_kpooladdr. Introduce pfctl_pooladdr and modify pf_kpooladdr
so that address family can be preserved. Struct pf_nl_pooladdr already
contains a variable for address family, but it was not used. Use it
to send address family with pool addresses when loading pools.
Another option would be to modify struct pf_pooladdr but that is used
in the old ioctls and those can't be modified without breaking
compatibility. Modify pfctl's print_pool to not recover address family
from rule but use the stored address family for each address.

Update source nodes to handle two address families: of the search
address and of the redirection address. Modify nat and route source
node creation to use pre-nat address family for search address and
pool address family for redirection address. Even without RFC5549 this
solves issues with source tracking for nat64 rules: it's the original
IPv6 source address which gets mapped on an IPv4 gateway or IPv4 SNAT
address.

When reading states using netlink introduce PF_ST_RT_AF, so that pfctl
does not need to recover route-to gateway's address family from the
rule.

Modify pf_map_addr() so that it is given a wanted adress family which
is then compared to address family of stored addresses. For RFC5549
operation in round-robin mode each address (which can be a table or
an interface) is evaluated twice: first for IPv6, then for IPv4.
For RFC5549 operation the found address family will overwrite
the requested wanted address family.

In pf_route() check rt_af, it is not guaranteed to be AF_INET anymore
because pf_map_addr() could have changed it. Construct appropriate
gateway using rt_addr.

  • 8< ----

I still need to see how this works with pool types other than round-robin and single hosts, and there seems something wrong with source tracking for af-to.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

I'm going to need to take a deeper look later (probably when I'm back home from BSDCan). First impressions are that the implementation is probably good, but I really dislike the 'RFC5549' naming of the flag and variables. Unfortunately I don't immediately have a better suggestion.

In D50781#1159156, @kp wrote:

really dislike the 'RFC5549' naming of the flag and variables. Unfortunately I don't immediately have a better suggestion.

How about:

  • prefer-ipv6-nexthop
  • prefer-ipv6-nh
  • ipv6-nexthop
  • ipv6-nh

The term "next hop" is often preferred over "gateway", at least by networking people, and is already used in man pf.conf. The option with the word "prefer" hints that the IPv6 next hop is preferred, not enforced, because the code will first try to get an IPv6 address from the pool, but if that's impossible it will try IPv4, at least for IPv4 packets. Options with "nh" instead of "nexthop" make the option shorter, for those of us who want their rules to fit in 80 columns ;)

In D50781#1159156, @kp wrote:

really dislike the 'RFC5549' naming of the flag and variables. Unfortunately I don't immediately have a better suggestion.

How about:

  • prefer-ipv6-nexthop
  • prefer-ipv6-nh
  • ipv6-nexthop
  • ipv6-nh

The term "next hop" is often preferred over "gateway", at least by networking people, and is already used in man pf.conf. The option with the word "prefer" hints that the IPv6 next hop is preferred, not enforced, because the code will first try to get an IPv6 address from the pool, but if that's impossible it will try IPv4, at least for IPv4 packets. Options with "nh" instead of "nexthop" make the option shorter, for those of us who want their rules to fit in 80 columns ;)

Yeah, "ipv6-nexthop" seems pretty good.

Couple small remarks (I do still owe you a deeper look, probably sometime next week during the hackathon):

  • we need to add something to the man page about this. In the man page we should reference the RFC.
  • there are a couple of small cleanup changes that would be better as part of a separate commit. Things like introducing struct pfctl_pooladdr, and changing 'af' from int to sa_family_t. That makes reviewing this patch easier (because smaller), and the small cleanup patches are trivially obviously correct.

I don't have strong views on the use of rfc5549 in the test names. It's fine there, but if you prefer to use ipv6_nexthop or something that's fine too.