[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: pf and statesfull filtering on a bridge



Daniel, thanks!

I'm wondering if you've tried to use "return-rst"/"return-icmp"
with pf filtering on bridge? I have a default deny policy for
tcp protocol with rules like:

1. block return-rst  in   log proto tcp all
2. block return-rst  out  log proto tcp all

When tcp packet gets blocked on normal interface (non-bridged),
it's blocked by rule #1, and rst packet is sent succesfully.
But in case of the bridge, it seems that rst packet gets blocked
by rule #2? Could it be the case?

Thanks,
-albertr

Daniel Hartmeier writes:

> Several people have asked about stateful filtering with pf for bridges,
> and I wasn't sure myself about what's possible until I actually tried it
> today :)
> 
> Assume we want to build a stealth ethernet bridge that does stateful packet
> filtering using pf. First set up the bridge and verify it's working correctly:
> 
>   /etc/hostname.rl0
>   up
> 
>   /etc/hostname.rl1
>   up
> 
>   /etc/bridgename.bridge0
>   add rl0 add rl1 up
> 
> Now enable pf with an empty rule set (passing all packets by default), and
> observe how everything is still working.
> 
> To better understand how pf sees the packets, we add these four rules:
> 
>   pass in  log on rl0 inet proto icmp
>   pass out log on rl0 inet proto icmp
>   pass in  log on rl1 inet proto icmp
>   pass out log on rl1 inet proto icmp
> 
> We send an echo-request (ping) from a host on the rl0 side of the bridge
> to a host on the rl1 side, and an echo-reply comes back. We see the following
> log entries:
> 
>   rule 0, pass in on rl0, icmp echo-request
>   rule 3, pass out on rl1, icmp echo-request
>   rule 2, pass in on rl1, icmp echo-reply
>   rule 1, pass out on rl0, icmp echo-reply
> 
> As you can see, each packet goes through pf twice. It comes in on one
> interface and goes out through the other.
> 
> With pf (unlike ipf), we can actually address each of these cases, both
> directions on both interfaces.
> 
> If we filter statefully, there's one thing to keep in mind: the states in
> the state table are sorted by a key which consists of the two address and
> port pairs of the connection. The order of these two pairs is relevant.
> If an outgoing packet from A to B creates state, pf will let pass outgoing
> packets from A to B and incoming packets from B to A. But it will still
> block outgoing packets from B to A and incoming packets from A to B. In
> a non-bridging case this is perfectly clear and obvious.
> 
> But in our bridging case, the same packet goes through pf twice, once through
> each interface. And the order of the key pairs is different in both cases.
> 
> There are two solutions. The first one is to create two states per
> connection, one for each direction, using two 'keep state' rules.
> I don't think anyone will want to do that. Especially since the second
> solution is very simple and elegant:
> 
> From pf perspective, packets go through our bridge twice. If you look at
> either interface, you see exactly the same traffic, only the direction
> is reversed. Hence, we can ignore one interface and do all the filtering
> on the other one.
> 
> Here's an example:
> 
>   # we want to filter on rl0, hence just pass anything on rl1.
>   pass in  quick on rl1 all
>   pass out quick on rl1 all
> 
>   # as an example, we block eveything by default, and let pass only
>   # icmp echo requests related replies (both directions, statefully).
>   block in  on rl0 all
>   block out on rl0 all
>   pass in  on rl0 inet proto icmp all icmp-type echoreq keep state
>   pass out on rl0 inet proto icmp all icmp-type echoreq keep state
> 
> This works equally well for more complex rules. The general recipe is
> to pick one interface you want to filter on. Start with two rules
> that let pass anything on the other interface (quick). After that,
> filter only on the interface you picked.
> 
> Regards,
> Daniel