Dangling states problem

  • pf consults its states table before the rule set. So even after adding a rule to block certain connections, the ones that have a corresponding entry in the state table will continue uninterrupted.

    Correct me if I am wrong, but it seems that pf does not have any built-in/native mechanism to automatically terminate states that go against the current rule set.

    Sifting through the states and manually "pfctl -k"ing unwanted states does not look like a sustainable solution to this problem.

    I am writing a python script to automate this process, as much as possible.

    Do you know any other projects aiming at this?

    Is there anything on the roadmap for the pf project to address this issue?

    Are there any major road blocks to implementing this directly in pf?

    Can someone please shed more light on this.


  • That's pretty much the way a stateful firewall works.  Packet comes in, if it does not match existing state, the rules get evaluated.  If a permit/allow rule is matched, state is created.
    If rules were evaluated before state, state becomes irrelevant and then you are evaluating rules for every single packet, which would be a performance hit.  As it is, evaluating rules for the first packet in a given stream, you take a "hit" for only the first packet, which becomes noise over the life of the stream.

    One can always go to the web interface and reset all states after adding block rules (Diagnostics, States, Reset States).

  • @mer:

    One can always go to the web interface and reset all states after adding block rules (Diagnostics, States, Reset States).

    But wouldn't that kill all legitimate connections, too?
    There are other h.323/ftp/http download connections/etc going on. Flushing the state table will disrupt them too.
    AFAIK, new TCP states are usually added only when seeing S/SA packets, right?

  • Yes, that would kill legitimate connections too.
    Technically new states are added on the first packet of any stream that matches a pass rule that says keep state (which is the default).  But for TCP rules, yes, they are added when the S out of the SA flags are set.
    But what you are describing is you already have state established for a stream due to existing pass rules, now you add a block rule that affects only that stream and you want to kill the state for that stream but not others.

    man pfctl looks like it can take a a bunch of different options on the -k and -K commands, so combined with creative use of pfctl -s state -vv and grep/awk/sed you may be able to make it "easy" to kill the states.  I'm guessing (because I'm just a user of pfSense) that something like that could be offered back up to the project for potential inclusion, because when you're adding the block rule you pretty much have both sides of everything needed to kill existing states (at least at a host level).  If you have multiple streams from a single host but you don't want to kill all of them, it becomes a little bit more difficult.

  • Evaluating whether any of the existing states "goes against" the current ruleset is a non-trivial problem. To do so you'd have to simulate the creation of every existing state with rules that are currently loaded. PF was not designed for such use and that's why there are no provisions built-in for that.

    Edit: It also gets very hairy when you have states from rules that are triggered by not just IP header information but also by rate limiting options. PF does not keep track of  (for example) the timing information of packets that created the state.