--- /dev/null
+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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/ip.h>
++#include <asm/uaccess.h>
++#include <linux/spinlock.h>
++
++#include <linux/netfilter_ipv4/ipt_ipp2p.h>
++
++#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
+