diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig linux-2.6.0-test9/net/ipv4/netfilter/Kconfig --- linux-2.6.0-test9.org/net/ipv4/netfilter/Kconfig 2003-11-04 11:53:04.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/Kconfig 2003-11-04 11:12:46.000000000 +0100 @@ -5,6 +5,11 @@ menu "IP: Netfilter Configuration" depends on INET && NETFILTER +config IP_NF_P2P + tristate "P2P netfilter" + help + empty + config IP_NF_CONNTRACK tristate "Connection tracking (required for masq/NAT)" ---help--- diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/Makefile linux-2.6.0-test9/net/ipv4/netfilter/p2p/Makefile --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/Makefile 2003-11-04 11:03:39.000000000 +0100 @@ -0,0 +1,4 @@ +ipt_p2p-objs := main.o match_http.o match_edonkey.o match_dc.o match_bittorrent.o + +obj-$(CONFIG_IP_NF_P2P) := ipt_p2p.o + diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/main.c linux-2.6.0-test9/net/ipv4/netfilter/p2p/main.c --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/main.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/main.c 2003-11-04 11:15:28.000000000 +0100 @@ -0,0 +1,103 @@ +/* + * p2p iptables match module + * filipe@rnl.ist.utl.pt + */ + + +#include +#include +#include + +#include +#include + + +#define KERNEL_2_6 + + +MODULE_AUTHOR("Filipe Almeida "); +MODULE_DESCRIPTION("IP tables p2p match module"); +MODULE_LICENSE("GPL"); + +int +match_http( const unsigned char *data, + const unsigned char *end); +int +match_edonkey( const unsigned char *data, + const unsigned char *end); +int +match_dc( const unsigned char *data, + const unsigned char *end); +int +match_bittorrent( const unsigned char *data, + const unsigned char *end); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + int *hotdrop) +{ + const struct iphdr *iph = skb->nh.iph; + const struct tcphdr *tcph; + const unsigned char *data; + const unsigned char *end; + + int datalen; + datalen = skb->len - (iph->ihl<<2); + + if ( !iph || iph->protocol != IPPROTO_TCP) return 0; + + tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4; + data = (const unsigned char *) tcph + tcph->doff * 4; + end = data + datalen - tcph->doff * 4; + + if (match_http(data, end)) return 1; + if (match_edonkey(data, end)) return 1; + if (match_dc(data, end)) return 1; + if (match_bittorrent(data, end)) return 1; + + return 0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(0)) + return 0; + + return 1; +} + + +/* +static struct ipt_match p2p_match += { { NULL, NULL }, "p2p", &match, &checkentry, NULL, THIS_MODULE }; +*/ + +static struct ipt_match p2p_match = { + .name = "p2p", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + printk(KERN_INFO "Module ipt_p2p loaded.\n"); + return ipt_register_match(&p2p_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&p2p_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_bittorrent.c linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_bittorrent.c --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_bittorrent.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_bittorrent.c 2003-10-18 00:33:35.000000000 +0200 @@ -0,0 +1,43 @@ +/* + * match_bittorrent.c + * + * filipe@rnl.ist.utl.pt + * + */ + +#define __NO_VERSION__ + +#include + +/* +#ifdef CONFIG_MODVERSIONS +#include +#endif +*/ + +#include +#include +#include +#include +#include + +#include + + +#define SIZE_MIN 20 +#define SIZE_MAX 500 + +const unsigned char bittorrent_string[] = "\x13" + "BitTorrent protocol" + "\x0\x0\x0\x0\x0\x0\x0\x0"; + + +int +match_bittorrent( const unsigned char *data, + const unsigned char *end) +{ + if (end - data < SIZE_MIN || end - data > SIZE_MAX) return 0; + + if(memcmp(data, bittorrent_string, sizeof(bittorrent_string) - 1) == 0) return 1; + return 0; +} diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_dc.c linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_dc.c --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_dc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_dc.c 2003-10-18 20:14:34.000000000 +0200 @@ -0,0 +1,65 @@ +/* + * match_dc.c + * + * filipe@rnl.ist.utl.pt + * + */ + +#define __NO_VERSION__ + +#include + +/* +#ifdef CONFIG_MODVERSIONS +#include +#endif +*/ + +#include +#include +#include +#include +#include + +#include + + +#define SIZE_MIN 30 +#define SIZE_MAX 200 + +static const unsigned char *dc_cmd[] = { + "MyNick", + "Lock", + NULL +}; + +static const unsigned char *next_cmd( const unsigned char *data, + const unsigned char *end) +{ + while(data <= end) + if(*data++ == '|') return data; + return NULL; +} + +int +match_dc( const unsigned char *data, + const unsigned char *end) +{ + int count=0; + + if (end - data < SIZE_MIN || end - data > SIZE_MAX) return 0; + + while(dc_cmd[count]) { + if(*data != '$') return 0; /* Quick Exit */ + if(end - data < strlen(dc_cmd[count])) return 0; + if(memcmp(data + 1, dc_cmd[count], strlen(dc_cmd[count]))) return 0; + + data = next_cmd(data, end); + if(!data) return 0; + + count++; + } + + + return 1; +} diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_edonkey.c linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_edonkey.c --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_edonkey.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_edonkey.c 2003-10-18 20:14:52.000000000 +0200 @@ -0,0 +1,78 @@ +/* + * eDonkey iptables match module + * filipe@rnl.ist.utl.pt + */ + +#define __NO_VERSION__ + +#include +#include + +#define get_u8(X,O) (*(__u8 *)(X + O)) +#define get_u16(X,O) (*(__u16 *)(X + O)) +#define get_u32(X,O) (*(__u32 *)(X + O)) + +#define EDONKEY_PACKET 0xe3 +#define TYPE_HELLO 0x01 +#define TAG_NAME 0x01000102 +#define TAG_VERSION 0x11000103 +#define TAG_PORT 0x0f000103 + +#define POS_MAGIC 0 +#define POS_LEN 1 +#define POS_TYPE 5 +#define POS_TAGCOUNT 28 +#define POS_FIRSTTAG 32 + +#define SIZE_MIN 30 +#define SIZE_MAX 200 /* TODO: Um nome muito grande será maior que isto? */ + +int +match_edonkey( const unsigned char *data, + const unsigned char *end) +{ + int packet_len; + int tag_count, tag_type; + + if (end - data < POS_FIRSTTAG) return 0; + if (get_u8(data, POS_MAGIC) != EDONKEY_PACKET) return 0; + packet_len = get_u32(data, POS_LEN); + + if (packet_len < SIZE_MIN || packet_len > SIZE_MAX) return 0; + if (get_u8(data, POS_TYPE) != TYPE_HELLO ) return 0; /* Not Hello Packet */ + + tag_count = get_u32(data, POS_TAGCOUNT); + if(tag_count != 2 && tag_count != 3) { + data++; + tag_count = get_u32(data, POS_TAGCOUNT); + if(tag_count != 2 && tag_count != 3) return 0; + } + + data += POS_FIRSTTAG; + + while(tag_count--) { + tag_type = get_u32(data,0); + data += 4; + if (data > end) return 0; + + switch(tag_type) { + case TAG_NAME: + data += 2 + get_u16(data,0); + if (data > end) return 0; + break; + case TAG_VERSION: + data += 4; + if (data > end) return 0; + break; + case TAG_PORT: + data += 4; + if (data > end) return 0; + break; + default: + return 0; + } + } + + return 1; +} + diff -Nur linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_http.c linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_http.c --- linux-2.6.0-test9.org/net/ipv4/netfilter/p2p/match_http.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test9/net/ipv4/netfilter/p2p/match_http.c 2003-10-18 20:14:40.000000000 +0200 @@ -0,0 +1,82 @@ +/* + * match_http.c + * + * filipe@rnl.ist.utl.pt + */ + +#define __NO_VERSION__ + +#include + +/* +#ifdef CONFIG_MODVERSIONS +#include +#endif +*/ + +#include +#include +#include +#include +#include + +#define SIZE_MIN 30 +#define SIZE_MAX 1000 +#define HEADER_SIZE_MIN 15 + +static const unsigned char *methods_list[] = { + "GET /get/", + "GET /uri-res/", + "GET /.hash=", + "HTTP/1.1", + NULL +}; + +static const unsigned char *headers_list[] = { + "X-Kazaa-", + "X-Gnutella-", + NULL +}; + +static inline const unsigned char * +next_line(const unsigned char *data, + const unsigned char *end) +{ + while(data <= end) + if(*data++ == '\n') return data; + + return NULL; +} + +static inline int +string_match(const unsigned char *data, + const unsigned char **strings) +{ + int i = 0; + while (strings[i]) { + if(memcmp(data, strings[i], sizeof(strings[i]) - 1) == 0) + return 1; + i++; + } + return 0; +} + + +int +match_http( const unsigned char *data, + const unsigned char *end) +{ + if (end - data < SIZE_MIN || end - data > SIZE_MAX) return 0; + + if( string_match(data, methods_list) == 0 ) + return 0; + + while ( (data = next_line(data, end)) ) { + if(end - data < HEADER_SIZE_MIN) + return 0; + if( string_match(data, headers_list) ) + return 1; /* match */ + } + + return 0; +}