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

Reply via email to