... via OpenBSD's packetfilter!
Initial writeup: 2024-11-27
Now, say that you have a cheap VPS that you use as a VPN "server" for it to route your traffic through the interwebz. In that case, you probably also received a IPv6 prefix for your fancy new virtual box. Depending on the prefixlength, you now have an enormous address space to make use of! But what can you do with it actually? After all, there is _no_ way that any single person can utilize it...
Next, say that somewhere in your pf.conf you NAT your internal VPN clients' v4 addresses to your external server addresses, like so:
match out on egress from (wg0:network) nat-to (egress)
This will actually also work for v6 addresses, given that you gave your egress interface a v6 address and that the VPN clients have a v6 address configured which is not part of your server's v6 prefix. Yes you have heard me correct: NAT on IPv6? Who in the world would be crazy enough to do something as stupid as this? I am! And this is gonna get even stupider >:)
In a world of IPv4 NAT, there is this certainty that any given public IP address coming from a residential area is just a "catch all" for multiple users behind, well, a NAT, each in possibly their own LANs with their own NAT, in case the ISP does carrier-grade NAT. Driving you NATs already? (Pun intended.)
This makes an IPv4 address a somewhat weak handle to keep track of indivitual users across the internet - after all, it could be anyone from that geographic area that is associated with the IP. Since IPv6 solves the address-exhaustion-problem the IP by itself becomes a more useful handle for a user, or worse, for individual devices of that user. This doesn't mean that IP addresses are the only thing to worry about when you are paranoid about online privacy, they are just one small part of the whole picture. But in case you have a VPS which only you really use that routes everything through the single same address, you are kind of working against your objective.
Now of course, IPv4-only VPN routers are whack. This is now a given, for my argument to keep making sense, because otheriwse, you don't run into this "more-specific-handle" problem if you just don't use IPv6 routing.
Say that you want to be able to connect to v6-only networks using clients of your VPN server. The canonical option here is to assign an individual v6 address from your v6 prefix. Alternatively, you can also just NAT to the v6 address of your VPS's public interface. (Definitely the uncanonical solution.) Third option: you NAT your client's "private" v6 to a random address that is part of your public prefix, and you cycle it periodically - this actually works quite nicely with OpenBSD's packetfilter.
Given your clients under an internal v6 prefix that is not part of your VPS's public prefix, you can just say:
v6_nat_prefix = "2001:7ca:ff17:1337::/64" match out on egress inet6 from (wg0:network) \ nat-to $v6_nat_prefix random sticky-address
Setting the prefix like this actually didn't work properly for me - increasing the prefixlength to anything greater than 64 worked though.
With this, pf will choose a random address from your v6 prefix for each stateful connection of your clients. Adding sticky-address will cause the chosen address to be consistent accross multiple simultaneous connections. If all states expire, a new address is set. However, this may not be what you want, since e.g. logging into a webpage will not necessarily keep a connection alive. This assignment of new addresses can be limited by setting:
set timeout src.track 300 # 5 minutes
Such that only after five minutes after the last stateful connection, a new address is assigned.
Of course, more details are available in the pf.conf(5) manpage:
https://man.openbsd.org/pf.conf
I am really amazed at how easily this is possible with OpenBSD pf. It is literally just about replacing the initial
match out on egress from (wg0:network) nat-to (egress)
with:
match out on egress inet from (wg0:network) \ nat-to (egress) match out on egress inet6 from (wg0:network) \ nat-to 2001:7ca:ff17:1337:b00b:cafe::/96 random sticky-address
and you are good to go.
Whether or not this is an _actual_ improvement on privacy... I cannot tell. After all, many online services are smart and able to aggregate IP-addresses - Google for example just blocks YouTube streaming to Hetzner IP ranges, only giving you a login request.
But hey, at least you are making use of your v6 prefix :)
Cheers!