Hello Vadim. you wrote 12 ÉÀÎÑ 2006 Ç., 16:48:50: Vadim Goncharov> 12.06.06 _at_ 05:34 Eduardo Meyer wrote: >> I read the messages and man page but did not understand. Maybe it is >> my lack of knowledge regarding netgraph? Well, in man page it seems >> that you looked at ipfw source code (.h in fact) to find out the tag >> number. Can you explain this? Vadim Goncharov> Yes, netgraph always was a semi-programmer system, less or more, Vadim Goncharov> especially true with ng_tag, as it tries to be Vadim Goncharov> generalized mbuf_tags(9) Vadim Goncharov> manipulating interface, and this is more kernel internals. For simple Vadim Goncharov> using, however, you don't need to bother all that details - just remember Vadim Goncharov> magic number and where to place it, and it is now Vadim Goncharov> simple for use with ipfw Vadim Goncharov> tags. >> A practical example, how could I, for example, block Kazaa or >> bittorrent based on L7 with ng_tag? Can you please explain the steps >> on how to do this? Unfortunately i have never analyzed p2p protocols, but for ICQ solution is very simple. Of course, this is not what you asked for, but it is a practical example using ng_tag node At the beginning of icq session server always sends us 10 bytes length packet of data: 2A 01 XX XX 00 04 00 00 00 01 ^ ^ ^ ^ ^ ^ ^ ^ SEQ Length ^ Channel ICQ flap ID so we can easily match and block this packet with iplen = 50 in ipfw and by 8 bytes exact match in ng_bpf The following line is for ng_bpf(4) script from manpage PATTERN="ether[40:2] = 0x2A01 and ether[44:4] = 0x00040000 and ether[48:2] = 0x0001" Vadim Goncharov> The truth is that, in fact, ng_tag doesn't do any traffic analysis. It Vadim Goncharov> merely provides an easy way to distinguish different packets after Vadim Goncharov> returning to ipfw. Currently the only analyzing node in FreeBSD src tree Vadim Goncharov> is ng_bpf(4), but it merely splits incoming packets in two streams, Vadim Goncharov> matched and not. There are reasons to this, as netgraph needs to be Vadim Goncharov> modular, and each node does a small thing, but does it well. For long time Vadim Goncharov> ng_bpf was used for another purposes in the kernel, and now, as new ipfw Vadim Goncharov> features appeared, ng_tag came up for easy integration. Vadim Goncharov> So, that's merely a framework allowing you to create custom filters, and Vadim Goncharov> if you need to match some kind of traffic, you Vadim Goncharov> should sit, understand what Vadim Goncharov> patterns that traffic has and then program ng_bpf(4) with appropriate Vadim Goncharov> filter. In fact, it allows to create it from Vadim Goncharov> tcpdump(1) expressions, so Vadim Goncharov> you don't need to be a C programmer, and that's good, isn't it? :) >> I don't run -CURRENT but I need this kind of feature very much, I am >> downloading a 7.0 snapshot just to test this with ipfw tag. Vadim Goncharov> You'll be able to do this with RELENG_6 about two weeks later. I simply Vadim Goncharov> couldn't wait a month for MFC and wrote it earlier :) >> How this addresses the problem on system level L7 filtering? I always >> though that someone would show up with a userland application that >> tags packets and returns the tag to ipfw filtering, but you came up >> with a kernel approach. How better and why it is when compared to evil >> regexp evaluation on kernel or how efficient is this when compared to >> Linux L7 which is know to fail a lot (let a number of packets pass)? Vadim Goncharov> Yes, in general case you do - correct way is to have a userland Vadim Goncharov> application which will do analysis, this easier, simpler and safer Vadim Goncharov> (imagine a security flaw inside kernel matcher?). Like snort. But the Vadim Goncharov> main disadvantage - it is SLOW. And for many kinds of traffic you do not Vadim Goncharov> need to perform complete flow analysis, as that is simple enough to do Vadim Goncharov> per-packet matching, then to say "Huh.. I found such packet, so entire Vadim Goncharov> connection must be of that type". Actually, I've Vadim Goncharov> found Linux iptables P2P Vadim Goncharov> matching module named ipp2p at http://www.ipp2p.org/ which was told to Vadim Goncharov> work reasonable well, looked at the code and found that one-packet match Vadim Goncharov> is enough for this work. So, per-packet matching can be implemented in Vadim Goncharov> kernel. Vadim Goncharov> After that I've discovered that FreeBSD already have in-kernel packet Vadim Goncharov> matcher for a long time, since 4.0. Briefly Vadim Goncharov> inspecting ipp2p code shown Vadim Goncharov> that most recognized P2P types can be matched by tcpdump and thus are Vadim Goncharov> programmable on ng_bpf(4). For some patterns, still, that's not enough, as Vadim Goncharov> bpf can't search for a substring on a variable, not fixed, offset. Then we Vadim Goncharov> can imagine another netgraph node which will do substring search (like Vadim Goncharov> iptables --string), so with both bpf and Vadim Goncharov> string-matching all P2P traffic Vadim Goncharov> can be caught. Vadim Goncharov> Anyway, that work yet to be done. The main benefit of ng_tag at the moment Vadim Goncharov> is that everybody wishing this have no longer Vadim Goncharov> principial barriers to do, Vadim Goncharov> like needing skills to write kernel module or even userland matching Vadim Goncharov> daemon. >> Sorry for all those questions, but I am an end user in the average, >> so, I can not understand it myself only reading the code. >> >> Thank you for your work and help. It seems that I will have a 7.0 >> snapshot doing this job to me untill the ipfw tag MFC happens, if I >> can understand this approach. Vadim Goncharov> I hope that my explanation was helpful enough to understand :) Also, if Vadim Goncharov> you will be using 7.0, include BPF_JITTER in your kernel config as this Vadim Goncharov> will enable native code-compiling for bpf and ng_bpf - this will speed Vadim Goncharov> things up. Vadim Goncharov> ========================================================================== Vadim Goncharov> P.S. Here is quick-and-dirty primer how to convert ipp2p functions to Vadim Goncharov> ng_bpf(4) input expression for tcpdump(1). Go to Vadim Goncharov> http://www.ipp2p.org/ and Vadim Goncharov> download source, unpack and open file pt_ipp2p.c and find function for Vadim Goncharov> your P2P type, let it be BitTorrent for our example. So look (I've Vadim Goncharov> formatted that bad Linux code a little to be a more style(9)'ish): Vadim Goncharov> int Vadim Goncharov> search_bittorrent (const unsigned char *payload, const u16 plen) Vadim Goncharov> { Vadim Goncharov> if (plen > 20) { Vadim Goncharov> /* test for match 0x13+"BitTorrent protocol" */ Vadim Goncharov> if (payload[0] == 0x13) Vadim Goncharov> if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) Vadim Goncharov> return (IPP2P_BIT * 100); Vadim Goncharov> /* get tracker commandos, all starts with GET / Vadim Goncharov> * then it can follow: scrape| announce Vadim Goncharov> * and then ?hash_info= Vadim Goncharov> */ Vadim Goncharov> if (memcmp(payload,"GET /",5) == 0) { Vadim Goncharov> /* message scrape */ Vadim Goncharov> if (memcmp(payload+5, "scrape?info_hash=", 17)==0) Vadim Goncharov> return (IPP2P_BIT * 100 + 1); Vadim Goncharov> /* message announce */ Vadim Goncharov> if (memcmp(payload+5, "announce?info_hash=", 19)==0) Vadim Goncharov> return (IPP2P_BIT * 100 + 2); Vadim Goncharov> } Vadim Goncharov> } else { Vadim Goncharov> /* Vadim Goncharov> * bitcomet encryptes the first packet, so we have to detect another Vadim Goncharov> * one later in the flow Vadim Goncharov> */ Vadim Goncharov> /* first try failed, too many missdetections */ Vadim Goncharov> //if (size == 5 && get_u32(t,0) == Vadim Goncharov> __constant_htonl(1) && t[4] < 3) Vadim Goncharov> // return (IPP2P_BIT * 100 + 3); Vadim Goncharov> Vadim Goncharov> /* second try: block request packets */ Vadim Goncharov> if ((plen == 17) && Vadim Goncharov> (get_u32(payload,0) == __constant_htonl(0x0d)) && Vadim Goncharov> (payload[4] == 0x06) && Vadim Goncharov> (get_u32(payload,13) == __constant_htonl(0x4000))) Vadim Goncharov> return (IPP2P_BIT * 100 + 3); Vadim Goncharov> } Vadim Goncharov> return 0; Vadim Goncharov> } Vadim Goncharov> So, what do we see? BitTorrent packet can start with one of three fixed Vadim Goncharov> strings (we see memcmp() checks for them). Author of ipp2p employs one Vadim Goncharov> more check, but as we can see from comments, he's not sure. Vadim Goncharov> Let's find out what are the byte sequences for these strings: Vadim Goncharov> $ echo -n "BitTorrent protocol" | hd Vadim Goncharov> 00000000 42 69 74 54 6f 72 72 65 6e 74 20 70 72 6f 74 6f |BitTorrent Vadim Goncharov> proto| Vadim Goncharov> 00000010 63 6f 6c |col| Vadim Goncharov> 00000013 Vadim Goncharov> $ echo -n "GET /scrape?info_hash=" | hd Vadim Goncharov> 00000000 47 45 54 20 2f 73 63 72 61 70 65 3f 69 6e 66 6f |GET Vadim Goncharov> /scrape?info| Vadim Goncharov> 00000010 5f 68 61 73 68 3d |_hash=| Vadim Goncharov> 00000016 Vadim Goncharov> $ echo -n "GET /announce?info_hash=" | hd Vadim Goncharov> 00000000 47 45 54 20 2f 61 6e 6e 6f 75 6e 63 65 3f 69 6e |GET Vadim Goncharov> /announce?in| Vadim Goncharov> 00000010 66 6f 5f 68 61 73 68 3d |fo_hash=| Vadim Goncharov> 00000018 Vadim Goncharov> We can give 1, 2 or 4 bytes to tcpdump for comarison at one time. The Vadim Goncharov> "payload" variable in the source points to beginning of data in TCP Vadim Goncharov> packet. Remember from man ng_tag that tcpdump assumes packets to have Vadim Goncharov> 14-byte Ethernet header for it's arrays like Vadim Goncharov> "tcp[]", but packets come Vadim Goncharov> from ipfw to ng_bpf without this header, and that affects our offset Vadim Goncharov> calculations. So we must give offsets from very beginning of packets, Vadim Goncharov> which is done through "ether[]" tcpdump's prime, and parse headers Vadim Goncharov> manually. Let's assume (for simplicity and speed), however, that IP and Vadim Goncharov> TCP headers have no any options and thus always have length 20 bytes each, Vadim Goncharov> then ipp2p's "payload[0]" will be tcpdump's "ether[40]". Also, let's Vadim Goncharov> assume that ipfw checked packet len for us so we Vadim Goncharov> don't do that in netgraph Vadim Goncharov> too. Vadim Goncharov> Then, we simply take hex bytes in order hd(1) told us, as this is network Vadim Goncharov> byte order also, and write them as tcpdump Vadim Goncharov> expressions (remember that Vadim Goncharov> first string ("...protocol") actually have 0x13 Vadim Goncharov> prepended to it). So, we Vadim Goncharov> write follow in ng_bpf(4) script: Vadim Goncharov> PATTERN="(ether[40:4]=0x13426974 && Vadim Goncharov> ether[44:4]=0x546f7272 && Vadim Goncharov> ether[48:4]=0x656e7420 && Vadim Goncharov> ether[52:4]=0x70726f74 && Vadim Goncharov> ether[56:4]=0x6f636f6c Vadim Goncharov> ) || Vadim Goncharov> (ether[40:4]=0x47455420 && Vadim Goncharov> (ether[44:4]=0x2f736372 && Vadim Goncharov> ether[48:4]=0x6170653f && Vadim Goncharov> ether[52:4]=0x696e666f && Vadim Goncharov> ether[56:4]=0x5f686173 && Vadim Goncharov> ether[60:2]=0x683d Vadim Goncharov> ) || Vadim Goncharov> (ether[44:4]=0x2f616e6e && Vadim Goncharov> ether[48:4]=0x6f756e63 && Vadim Goncharov> ether[52:4]=0x653f696e && Vadim Goncharov> ether[56:4]=0x666f5f68 && Vadim Goncharov> ether[60:4]=0x6173683d) Vadim Goncharov> ) || Vadim Goncharov> (ether[2:2]=57 && Vadim Goncharov> ether[40:4]=0x0000000d && Vadim Goncharov> ether[44]=0x06 && Vadim Goncharov> ether[53:4]=0x00004000)" Vadim Goncharov> Note the last OR block in expression - this is Vadim Goncharov> translation of that "not Vadim Goncharov> sure" checking request packets. I've explicitly written packet length - Vadim Goncharov> plen=17 + 20 byte IP header len + 20 byte TCP header len, check at offset Vadim Goncharov> 2 in IP header, according to RFC 791. Construction "get_u32 == Vadim Goncharov> __constant_htonl()" means comparing 4-byte values at given offset. Vadim Goncharov> P.P.S. I have not tested that pattern on real packets, as I have no Vadim Goncharov> BitTorrent today, but it should work. -- Cheers, Alexander V. Chernikov mailto:admin_at_su29.netReceived on Wed Jun 14 2006 - 12:30:32 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:57 UTC