Daniel,
I agree, I have no idea how the internals of PF work, and what it is capable of, which is why I emailed the list :)
Would it be possible or feasible to write a daemon that does perform logic and state tracking w/ regex, that could possibly speak to the PF internals to add rules dynamically? Then again, I am slow, because I just realized I could just use SNORT and its Plugins to dynamically add rulesets. Forgive my ignorance, I am going to now go shoot myself.
regards,
chris


Daniel Hartmeier wrote:

On Mon, Jun 28, 2004 at 03:16:15PM -0700, cloper wrote:



drop in log quick on $ext_if layer 7 "edonkey login"
drop in log quick on $ext_if layer 7 "aim send message"



While for applications TCP is a byte stream protocol, packet filters (as the name implies) operate on a lower level. They do not see payload as an ordered stream, but see individual packets containing chunks of payload. In general, the payload is broken into chunks at arbitrary borders, chunks can arrive in non-sequential order and there can be gaps and overlaps.

So, if you look at these individual packets as they pass through, you
can't really 'look for the string "edonkey"' inside the stream. All you
could do is look for the string inside one packet's payload.

But that's generally useless, as

 a) the string could be broken into multiple packets by chance
    legitimately (not very likely, but it will occur)

 b) the sender can intentionally break the string into multiple
    packets to bypass the filter (very likely and very easy to
    do), send chunks out of order or create overlaps.

 c) there will be many unexpected false positives. If you had the
    above rules in place, you wouldn't have been able to send your
    email, would you? If you'd browse the lists archive over HTTP,
    you couldn't load the page containing this reply. There's an
    endless list of protocols that might legally contain these
    strings, and you can't rely on P2P protocols to not use arbitrary
    ports.

If you'd be happy with that, this would be easy to hack into pf. Just
add a char array to struct pf_rule, make pfctl parse the search
arguments into rules, and have the kernel search for the arguments
inside each packet. But given a)-c), it will prove useless, IMO.
A P2P client can cause a string to get split up using one or two lines
of simple userland socket option fiddling. I wouldn't be surprised if
some of them already do that just for this purpose. If they don't, their
next releases will for sure. Either you have a solid reliable solution,
or you write code that will be useless in two months when the opponents
catch up.

So, you'll end up wanting to reassemble packets into streams before
searching for strings. And you'll end up adding protocol awareness to
the code (so a HTML document containing the sequence "edonkey login"
sent over HTTP doesn't match). Restricting rules to ports won't help
much, as P2P protocols intentionally use port 80 and HTTP-alike
protocols exactly to get through firewalls and proxies more easily.

You'll find that a single simple piece of code won't do, instead you'll
need to implement stateful logic for all protocols you don't want to
block outright.

Once you're there, you'll find that doing this in kernel makes it

 a) harder (writing your own TCP reassembly in kernel is certainly
    more complex than just getting a stream in userland).
 b) more dangerous (mistakes easily produce remotely exploitable
    crashes or kernel compromises)

compared to doing the same in userland as application level proxies.

The most simple and reliable solution, in the end, would be to pick
existing proxies for the protocols you need to forward (like squid for
HTTP) and add the filtering there, if they do not already support such
features.

I think the idea of layer 7 filtering in packet filters is popular
because it appears to make things simple (just block "edonkey login"
in the packet filter and be done, no need to think about different
protocols etc.), but it's just flawed. Feel free to prove me wrong,
but I won't spend time writing code just to prove the point that the
idea doesn't work. :)

Daniel


Reply via email to