NAT states
Daniel Hartmeier
daniel at benzedrine.cx
Thu Oct 13 05:45:54 PDT 2005
On Thu, Oct 13, 2005 at 08:33:43AM +0400, Artemiev Igor wrote:
> By default, if an interface is not specified, state operates on any
> interface. State was created on "self" aka any local interface,
> but didn`t match passing packets.
> I tried to set "set state-policy floating" explicitly, but to no effect.
That does not apply when the state involves address/port translation.
In your case, the incoming replies from the external peer match the
state entry on the external interface. Right then, the translation is
reversed. Then (afterwards), the packet passes back through the stack
and then gets filtered again on the internal interface. There, it does
NOT match the same state, because the (re-translated) address does not
match.
Example:
nat pass from <locals> to any -> ($extif:0)
block in log all
pass on $lanif from $lanif:network to $lanif:network allow-opts
pass out on $extif from $extif to any keep state allow-opts
LAN host 10.1.2.3 (source port 65000) connects to external host
62.65.145.30 (destination port 80).
The TCP SYN looks like this:
src dst
10.1.2.3:65000 -> 62.65.145.30:80
It passes in on $lanif statelessly (not creating state), last matching
your first pass rule.
It then passes out on $extif, last matching your second pass rule,
creating a translating state:
lan gwy ext
10.1.2.3:65000 24.25.26.27:20000 62.65.145.30:80
where 24.25.26.27 is your $extif address and 20000 is a random proxy
port.
Then, the peer's reply SYN-ACK arrives in on $extif, it looks like this:
src dst
62.65.145.30:80 -> 24.25.26.27:20000
Incoming packets cause a state lookup with
src = ext AND dst = gwy (replacing dst with lan, if different)
which matches your state entry above. So the packet is passed according
to this state entry. Since lan != gwy, the destination address is
replaced, i.e. dst := lan. The packet now looks like this:
src dst
62.65.145.30:80 -> 10.1.2.3:65000
It is now filtered outgoing on $lanif. Outgoing packets cause a state
lookup with
src = lan AND dst = ext (replacing src with gwy, if different)
This does not match your state entry, both conditions are false. The
ruleset is evaluated. The last matching rule is 'block in log all'.
Packet dropped. Handshake fails.
So, even a floating state does not allow packets related to a connection
to pass through all interfaces in arbitrary directions. And translation
is applied whenever a packet does match a state. It's unlikely that the
same packet, after translation, will match the same state on another
interface again.
Daniel
More information about the freebsd-pf
mailing list