On Thu, Mar 30, 2006 at 02:29:19PM +0200, Fredrik Widlund wrote:

> So, there are indeed 2 states, one without wscaling. I don't understand
> why the returning state (S->C) is created, and not matched to the
> initial NAT state? Is it because I create the state on "out" and is this
> then invalid?! I use this normally without problems on many routers.

A state entry is always bound to the direction of the packet that
creates it. For instance, if you have a pf box with two interfaces and a
connection flowing through it, you'll get two separate state entries,
one on each interface. The entry on the first interface won't match
packets on the second interface, because, there, packets flow in the
opposite direction. In short, a state entry does not allow packets of
one connection _through_ the firewall as a whole, but generally only
through one interface.

There are of course special cases, like when you simply don't filter on
one of the interfces, but in general, requiring multiple states per
connection is intentional. It allows more fine-grained control of what
interfaces a connection may flow through (compared to a blanket 'allowed
to pass through anywhere'). See the pf.conf(5) parts about if-bound vs.
floating, for more details.

The difference between if-bound and floating is NOT that floating is
that blanket check 'through the firewall'. It's a more subtle difference
for the case where you have more than two interfaces, like

                ---- $out1
   $in ---- pf <
                ---- $out2

With static routing, one connection will only pass through either $out1
or $out2 exclusively, so if-bound states are fine. But when you have
dynamic routing (or load balancing), you might want to allow packets of
one connection to pass through both $out1 and $out2. THEN you'd use
floating states instead of if-bound. But no matter whether you use
if-bound or floating states on the $out interfaces, those states will
never match packets on $in, because there the direction is reversed.

Now, given that there are two states, one per interface involved, check
again that each state gets created on the initial SYN of the connection.

> I have a very large ruleset, with 10+ segments and many hosts, but I
> have only one state rule: "pass out keep state". I have default deny on
> everything. In essence the stripped ruleset relevant for the case is:

> block log all
> pass out keep state
> nat on vlan_external from vlan_x:network to $internet -> $gateway
> pass in on vlan_x from vlan_x:network to $internet

The last rule is suspicious, it could allow an initial SYN in (on
vlan_x) without creating state. That SYN then passes out (on another
interface), creating the state there correctly. The SYN+ACK will pass in
on the other interface (based on the state created there), and then gets
routed out through vlan_x. There, it doesn't match any state, and passes
based on the generic 'pass out keep state' rule. Hence, you crate state
on vlan_x on the SYN+ACK instead of the initial SYN. Breaking wscale
support.

In short, ANY 'pass' rule without 'keep state' is always suspicious.
Also, adding 'flags S/SA' to all 'pass' rules helps spot these problems
early, as they are not (unintentionally) matching SYN+ACKs.

Daniel

Reply via email to