diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ipp2p.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ipp2p.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ipp2p.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ipp2p.h 2003-12-11 00:02:06.929074768 +0100 @@ -0,0 +1,9 @@ +#ifndef __IPT_IPP2P_H +#define __IPT_IPP2P_H +#define IPP2P_VERSION "0.5a" + +struct ipt_p2p_info { + int cmd; +}; + +#endif //__IPT_IPP2P_H diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ipp2p.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_ipp2p.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ipp2p.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_ipp2p.c 2003-12-11 00:02:06.930074616 +0100 @@ -0,0 +1,510 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define get_u16(X,O) (*(__u16 *)(X + O)) + +MODULE_AUTHOR("Eicke Friedrich"); +MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic."); +MODULE_LICENSE("GPL"); + +/*Search for appleJuice commands*/ +int +search_apple (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + t += head_len; + + if ((memcmp(t, "ajprot", 6) == 0) && (t[6] == 0x0d) && (t[7] == 0x0a)) return 1; + + return 0; +} + + +/*Search for BitTorrent commands*/ +int +search_bittorrent (unsigned char *haystack, int head_len) +{ + + unsigned char *t = haystack; + if (*(haystack+head_len) != 0x13) return 0; //Bail out of first byte != 0x13 + + t += head_len + 1; + + if (memcmp(t, "BitTorrent protocol", 19) == 0) return 1; + + return 0; +} + + + +/*check for Kazaa get command*/ +int +search_kazaa (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + + if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; + + t += head_len; + if (memcmp(t, "GET /.hash=", 11) == 0) + return 1; + else + return 0; +} + + +/*check for gnutella get command*/ +int +search_gnu (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + + if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; + + t += head_len; + if (memcmp(t, "GET /get/", 9) == 0) return 1; + if (memcmp(t, "GET /uri-res/", 13) == 0) return 1; + + return 0; +} + + +/*check for gnutella get commands and other typical data*/ +int +search_all_gnu (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + int c; + + if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; + + t += head_len; + + if (memcmp(t, "GNUTELLA CONNECT/", 17) == 0) return 1; + if (memcmp(t, "GNUTELLA/", 9) == 0) return 1; + + if ((memcmp(t, "GET /get/", 9) == 0) || (memcmp(t, "GET /uri-res/", 13) == 0)) + { + c = head_len + 8; + t += 8; + while (c < packet_len - 22) + { + if (t[0] == 0x0d) + { + t++; + c++; + if (t[0] == 0x0a) + { + t++; + c++; + if ( memcmp(t, "X-Gnutella-", 11) == 0 ) return 1; + } + } + else + { + t++; + c++; + } + } + } + + return 0; +} + + +/*check for KaZaA download commands and other typical data*/ +int +search_all_kazaa (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + int c; + + if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; + + t += head_len; + if (memcmp(t, "GIVE ", 5) == 0) return 1; + + if (memcmp(t, "GET /.hash=", 11) == 0) + { + c = head_len + 8; + t += 8; + while (c < packet_len - 22) + { + if (t[0] == 0x0d) + { + t++; + c++; + if (t[0] == 0x0a) + { + t++; + c++; + if ( memcmp(t, "UserAgent:", 10) == 0 ) return 1; + } + } + else + { + t++; + c++; + } + } + } + + return 0; +} + +/*fast check for edonkey file segment transfer command*/ +int +search_edk (unsigned char *haystack, int head_len) +{ + if (*(haystack+head_len) != 0xe3) + return 0; + else + { + if (*(haystack+head_len+5) == 0x47) + return 1; + else + return 0; + } +} + + + +/*intensive but slow search for some edonkey packets incl. size-check*/ +int +search_all_edk (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + int cmd; + +//Comment the next lines to turn OFF debug information +//debug starts here + if (*(haystack+head_len) == 0xc5) //search for additional eMule packets + { + t += head_len; + cmd = get_u16(t, 1); + + if (cmd == (packet_len - head_len - 5)) + { + if (t[5] == 0x01) return 1; + if (t[5] == 0x02) return 1; + if (t[5] == 0x60) return 1; + if (t[5] == 0x81) return 1; + if (t[5] == 0x82) return 1; + if (t[5] == 0x85) return 1; + if (t[5] == 0x86) return 1; + if (t[5] == 0x87) return 1; + if (t[5] == 0x40) return 1; +// printk("IPP2P.search_all_edk: new eMule match: %x %x %x %x %x %x (size %i ok)\n", t[0], t[1], t[2], t[3], t[4], t[5], packet_len); + return 0; + } + +/* if (cmd > packet_len - head_len - 5) + { + if (t[cmd+5] == 0xe3) + { + printk("IPP2P.search_all_edk: new eMule match with second eDonkey match: %x %x %x %x %x %x (packet: %i)\n", t[0], t[1], t[2], t[3], t[4], t[5], packet_len); + return 0; + } + if (t[cmd+5] == 0xc5) + { + printk("IPP2P.search_all_edk: new eMule match with second eDonkey match: %x %x %x %x %x %x (packet: %i)\n", t[0], t[1], t[2], t[3], t[4], t[5], packet_len); + return 0; + } + }*/ + return 0; + } +//debug ends here + + + if (*(haystack+head_len) != 0xe3) + return 0; + else + { + t += head_len; + cmd = get_u16(t, 1); + if (cmd == (packet_len - head_len - 5)) + { + t += 5; + if (t[0] == 0x01) return 1; //Client: hello or Server:hello + if (t[0] == 0x50) return 1; //Client: file status + if (t[0] == 0x16) return 1; //Client: search + if (t[0] == 0x58) return 1; //Client: file request + if (t[0] == 0x48) return 1; //??? + if (t[0] == 0x54) return 1; //??? + if (t[0] == 0x47) return 1; //Client: file segment request + if (t[0] == 0x46) return 1; //Client: download segment + if (t[0] == 0x4c) return 1; //Client: Hello-Answer + if (t[0] == 0x4f) return 1; //Client: file status request + if (t[0] == 0x59) return 1; //Client: file request answer + if (t[0] == 0x65) return 1; //Client: ??? + if (t[0] == 0x66) return 1; //Client: ??? + if (t[0] == 0x51) return 1; //Client: ??? + if (t[0] == 0x52) return 1; //Client: ??? + if (t[0] == 0x4d) return 1; //Client: ??? + if (t[0] == 0x5c) return 1; //Client: ??? + if (t[0] == 0x38) return 1; //Client: ??? + if (t[0] == 0x69) return 1; //Client: ??? + if (t[0] == 0x19) return 1; //Client: ??? + if (t[0] == 0x42) return 1; //Client: ??? + if (t[0] == 0x34) return 1; //Client: ??? + if (t[0] == 0x94) return 1; //Client: ??? +//Comment the next line to turn OFF debug information +// printk("IPP2P.search_all_edk: size (%i) ok, no match (%x)\n", packet_len, t[0]); + return 0; + } + else + { + if (cmd > packet_len - head_len - 5) + { + if ((t[3] == 0x00) && (t[4] == 0x00)) + { + if (t[5] == 0x01) return 1; + if (t[5] == 0x4c) return 1; + } + return 0; + + } //non edk packet + if (t[cmd+5] == 0xe3) return 1; //found another edk-command + if (t[cmd+5] == 0xc5) return 1; //found an emule-command +//Comment the next line to turn OFF debug information +// printk("IPP2P.search_all_edk: size (%i vs %i) WRONG, no second match: %x %x %x %x %x %x - %x %x %x %x %x %x\n", packet_len, cmd, t[0], +// t[1], t[2], t[3], t[4], t[5], t[cmd+5], t[cmd+6], t[cmd+7], t[cmd+8], t[cmd+9], t[cmd+10]); + return 0; + } + } +} + + +/*fast check for Direct Connect send command*/ +int +search_dc (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + + if (*(haystack+head_len) != 0x24 ) + return 0; + else + { + t += head_len + 1; + if (memcmp(t, "Send|", 5) == 0) + return 1; + else + return 0; + } + +} + + +/*intensive but slower check for all direct connect packets*/ +int +search_all_dc (unsigned char *haystack, int packet_len, int head_len) +{ + unsigned char *t = haystack; + + if ((*(haystack + head_len) == 0x24) && (*(haystack + packet_len - 1) == 0x7c)) + { + t += head_len + 1; + if (memcmp(t, "Lock ", 5) == 0) return 1; //hub: hello + if (memcmp(t, "Key ", 4) == 0) return 1; //client: hello + if (memcmp(t, "Hello ", 6) == 0) return 1; //hub:connected + if (memcmp(t, "MyNick ", 7) == 0) return 1; //client-client: hello + if (memcmp(t, "Search ", 7) == 0) return 1; //client: search + if (memcmp(t, "Send", 4) == 0) return 1; //client: start download +//Comment the next line to turn OFF debug information +// printk("IPP2P.search_all_dc:$ %x%x%x%x%x%x%x%x%x%x |\n",t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9]); + return 0; + } + else + return 0; + + +} + + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_p2p_info *info = matchinfo; + unsigned char *haystack; + struct iphdr *ip = skb->nh.iph; + int p2p_result = 0; + int head_len; + + int hlen = ntohs(ip->tot_len)-(ip->ihl*4); //hlen = packet-data length + haystack=(char *)ip+(ip->ihl*4); //haystack = packet data + + + if (((*(haystack+13)) & 1) == 1) return 0; //if FIN bit is set bail out + if (((*(haystack+13)) & 2) == 2) return 0; //if SYN bit is set bail out + if (((*(haystack+13)) & 4) == 4) return 0; //if RST bit is set bail out + + + head_len = (*(haystack+12))/4; //get TCP-Header-Size + + + if (((info->cmd & 8) == 8) || ((info->cmd & 4) == 4)) //cmd: kazaa-data || ipp2p-data + { + if (hlen > 200) + { + p2p_result = search_kazaa(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + + } + + + if (((info->cmd & 2) == 2) || ((info->cmd & 1) == 1)) //cmd: edk || ipp2p + { + if (hlen > 40) + { + p2p_result = search_all_edk(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + + + + if (((info->cmd & 16) == 16) || ((info->cmd & 4) == 4)) //cmd: edk-data || ipp2p-data + { + if (hlen > 60) + { + p2p_result = search_edk(haystack, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + if (((info->cmd & 32) == 32) || ((info->cmd & 4) == 4)) //cmd: dc-data || ipp2p-data + { + if (hlen == 26) + { + p2p_result = search_dc(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + if (((info->cmd & 64) == 64) || ((info->cmd & 1) == 1)) //cmd: dc || ipp2p + { + if (hlen > 25) + { + p2p_result = search_all_dc(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + if (((info->cmd & 128) == 128) || ((info->cmd & 4) == 4)) //cmd: gnu-data || ipp2p-data + { + if (hlen > 40) + { + p2p_result = search_gnu(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + if (((info->cmd & 256) == 256) || ((info->cmd & 1) == 1)) //cmd: gnu || ipp2p + { + if (hlen > 35) + { + p2p_result = search_all_gnu(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + + if (((info->cmd & 1) == 1) || ((info->cmd & 512) == 512)) //cmd: ipp2p || kazaa + { + if (hlen > 35) + { + p2p_result = search_all_kazaa(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + + + if ((info->cmd & 1024) == 1024) //cmd: bit + { + if (hlen > 40) + { + p2p_result = search_bittorrent(haystack, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + + if ((info->cmd & 2048) == 2048) //cmd: apple + { + if (hlen > 20) + { + p2p_result = search_apple(haystack, hlen, head_len); + if (p2p_result == 1) return p2p_result; + } + } + + + return p2p_result; +} + + + + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Must specify -p tcp */ + if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { + printk("ipp2p: Only works on TCP packets, use -p tcp\n"); + return 0; + } + + + return 1; +} + + + + +static struct ipt_match ipp2p_match += { + { NULL, NULL }, + "ipp2p", + &match, + &checkentry, + NULL, + THIS_MODULE }; + + +static int __init init(void) +{ + return ipt_register_match(&ipp2p_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipp2p_match); +} + +module_init(init); +module_exit(fini); + + diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/Makefile linux-2.6.0-test11/net/ipv4/netfilter/Makefile --- linux-2.6.0-test11.org/net/ipv4/netfilter/Makefile 2003-12-10 23:24:46.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/Makefile 2003-12-11 00:02:07.013062000 +0100 @@ -96,6 +96,7 @@ obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o +obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o --- linux-2.6.0-test11.org/net/ipv4/netfilter/Kconfig 2003-12-10 23:13:25.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/Kconfig 2003-12-11 00:20:03.590397368 +0100 @@ -611,5 +611,16 @@ To compile it as a module, choose M here. If unsure, say N. +config IP_NF_MATCH_IPP2P + tristate ' IPP2P match support (EXPERIMENTAL)' + depends on IP_NF_IPTABLES + help + IPP2P allows you to match certain packets of some popular + peer-to-peer networks. Use it to drop packets or mark them + for further use (with CONNMARK for example). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + endmenu