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