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

Re: Possible Setup

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
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
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. :)