Congratulations on a successful 7.4 release! I'm writing with a gentle feature request for pf; I asked about this functionality a long time ago and have seen a few other related questions on the list since then. Now that I've played with another NAT64 implementation (Jool), I think I can articulate myself a little better.
Summary: request to modify pf to support the following syntax to embed IPv4 address in IPv6 source addresses after af-to translation: pass in inet af-to inet6 from <new-ipv6-src>/96 to <ipv6-dest-node> This would require modifying the "from" portion of the af-to to look for a mask of /96 (or smaller) on the from address and take the actions below. In the line above, everything you see is currently supported except for the "/96" on the "from" address. If the mask is greater or omitted (e.g. /128) then the current behavior is used, making it backwards-compatible when omitted. If a /96 on the "from" is detected, the packet is translated between families as currently, with one modification: the packet source address will have the IPv4 source address embedded in the lower 32 bits of the IPv6 source address. Example: In practice, this syntax would also typically include a matching portion for the original IPv4 destination address so traffic destined for a particular IPv4 destination can be forwarded to a specific IPv6 node. Thus, a typical invocation would be like: pass in inet to 192.0.2.10 af-to inet6 from 64:ff9b::/96 to 2001:db8:b::10 The line above would result in a packet with IPv4 source 203.0.113.42 and destined for 192.0.2.10 being translated to have IPv6 source 64:ff9b::cb00:712a and destination 2001:db8:b::10. Discussion: This would allow PF to support SIIT EAMT / SIIT-DC behavior (sometimes called "NAT46"). The use case here would be a dual-stack pf box at the network edge, and servers behind it with IPv6-only connectivity. IPv4 requests from the internet would hit the pf box, be translated and forwarded over IPv6 to the servers. Because the IPv6 address contains the embedded IPv4 source address, logging and analysis on the server would have access to the full source address, rather than all traffic being "squashed" to a single IPv6 source. It would be the responsibility of the network operator to ensure return traffic (to 64:ff9b::/96 in the above example) is routed back to the pf box. I feel pf is the best place to add this functionality (rather than relayd or other code) because it is already capable of performing the family translation, and only needs to have the address-embedding functionality added for source addresses (it already exists for destination addresses). Thus, the necessary concepts are already in place elsewhere in the code; they need to be replicated for source addresses. Specifically, pf can already map an IPv4 *destination* address into the lower 32 bits of an IPv6 address using af-to: pass in inet af-to inet6 from 2001:db8::1 to 2001:db8::/96 This supports CLAT-type functionality where IPv4 traffic needs to be sent to a PLAT (typically network edge). Additionally, pf can currently translate IPv4 traffic from any host to a specific destination: pass in inet to 192.0.2.10 af-to inet6 from 2001:db8:a::1 to 2001:db8:b::10 However, this relies on pf's state table much like traditional NAT44: all traffic is arbitrarily mapped to a new source address and the destination server sees only the pf box's address as the source of the traffic. This request is to enable IPv4 /96 embedding on the *source* address; nodes that come after the translation will be able to see the full IPv4 source address embedded in the IPv6 address. Because the entire IPv4 address space can be embedded in a single IPv6 /96 prefix, no information is lost and so the translation does not require state (the return traffic can be turned back into IPv4 by simply un-embedding the IPv4 address). However, I recognize that pf may only operate in a stateful manner due to the way af-to is implemented, and state may be desirable for other pf functionality. However, even without truly being "stateless", the address embedding would support the same functionality as true SIIT implementation. Syntax changes would be minimal; pfctl would need to recognize a /96 on the source "from" for the af-to and activate the embedding behavior. As embedding is already implemented for destinations of /96, I'm hoping there is some opportunity for reuse. If a /96 is not seen on the "from" specification, then pf's current behavior can be used. A small backwards compatibility issue exists in that the current af-to source specification allows addresses with a mask other than /128. However, so far as I can tell, any mask is ignored and only the specified address is used at the present time, so anyone specifying that in their config is using an unsupported mask option. Unfortunately, I am no C hacker, so I am unable to formulate a patch that would add this behavior. However, I hope that it is not too difficult and thus may be added in a future release. The typical deployment of pf as an edge routing/firewall device makes this functionality very useful for those trying to migrate to IPv6-native networks, while maintaining backwards compatibility with the IPv4 internet. Thanks, Jason