PF ipv6 NAT: prevent link-local address usage for NAT?

I'm running a pretty basic PF ruleset on my VPS and basicaly that ruleset _could_ be completely identical across almost all hosts, _if_ PF wouldn't use the IPv6 link-local address for NAT on egress packets. By default it randomly alternates between the link-local and the globally routable address, hence completely breaking any connections that are NATed on IPv6...

Currently I have to hardcode the IPv6 into the ruleset and force PF to use that for egress NAT from jails that are connected to lo0:

Code:
ext_ipv6="2a03:b0c0:3:d0::53a:c001"
[...]
nat on $ext_if from ::0/64 to any tag EGRESS -> $ext_ipv6

...which is rather stupid for automatic deployment of servers... :rolleyes:


Is there any 'sane'/scalable way to prevent PF from using a link-local address for NAT?
[man5]pf.conf[/man] isn't really helpful as it doesn't even mention IPv6 NAT.
 
I'm honestly surprised that pf does anything NAT related for IPv6, so bear that in mind :)

I suspect this is pf doing its usual thing of using all of the addresses on the interface, so perhaps doing '... -> ($ext_if:0)' will work.
 
The whole idea of IPv6 is to be able to connect everything without having to resort to silly constructs like NAT.
 
The whole idea of IPv6 is to be able to connect everything without having to resort to silly constructs like NAT.

True, but most hosters only give a single IPv6 to any VPS, hence you'd still need to attach jails to an internal interface (e.g.) lo0 and NAT traffic from/to jails...
 
I must have a good hoster, they gave me only 1 IPv4 address (understandable) and I got a /48 for IPv6, on a single VPS :D

I "solved" most of my NAT issues by running HAProxy on the host, that listens on both IPv4 and IPv6. The backends (a couple of jails) are running on lo0 and only have an RFC1918 IPv4 address. HAproxy is able to receive requests on IPv6 and proxy them to IPv4 backends.
 
I must have a good hoster, they gave me only 1 IPv4 address (understandable) and I got a /48 for IPv6, on a single VPS :D


That's great; but best I can get is a /124 (=16 hosts) at digitalocean; which is still not enough for some hosts.

So the problem still persists: I need to NAT IPv6 and PF is using the link-local address for outgoing packets.


update:
I reverted to just completely disable ipv6 link-local on my droplets via the net.inet6.ip6.auto_linklocal sysctl.
 
This is an old thread, but still relevant. Here is my solution in case it helps someone else.

Assuming you're using DHCP (otherwise, you could just hard-code the address), you can use a persistent table that's initially empty, and then populate it with a dhclient hook.

Code:
table <origin6> persist

nat on $ext_if from fd00::/8 to any -> <origin6>

In some dhclient hook or script:

Code:
pfctl -t origin6 -T replace "$new_ip6_address"

It isn't the prettiest solution, but it's a solution.
 
There's also this:

Code:
           Interface names and interface group names can have modifiers
           appended:


           :network      Translates to the network(s) attached to the interface.
           :broadcast    Translates to the interface's broadcast address(es).
           :peer         Translates to the point-to-point interface's peer
                         address(es).
           :0            Do not include interface aliases.


           Host names may also have the :0 option appended to restrict the name
           resolution to the first of each v4 and non-link-local v6 address found.

That's a relatively recent improvement. See #201695 for details.
 
Code:
           :network      Translates to the network(s) attached to the interface.
It's interesting that :network is the wrong solution for IPv4 NAT but the right solution for IPv6 NAT. This works just fine when the rules are kept separate. That's one less hack I need to worry about!

(Or maybe :network only works because my address is a /128?)
 
Back
Top