diff options
Diffstat (limited to 'target/linux/generic/patches-2.6.37')
| -rw-r--r-- | target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.22.patch (renamed from target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.21.patch) | 1456 | ||||
| -rw-r--r-- | target/linux/generic/patches-2.6.37/103-netfilter_layer7_2.6.36_fix.patch | 61 | 
2 files changed, 789 insertions, 728 deletions
| diff --git a/target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.21.patch b/target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.22.patch index ec46ecaf9..4d969e290 100644 --- a/target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.21.patch +++ b/target/linux/generic/patches-2.6.37/100-netfilter_layer7_2.22.patch @@ -1,47 +1,6 @@ ---- /dev/null -+++ b/include/linux/netfilter/xt_layer7.h -@@ -0,0 +1,13 @@ -+#ifndef _XT_LAYER7_H -+#define _XT_LAYER7_H -+ -+#define MAX_PATTERN_LEN 8192 -+#define MAX_PROTOCOL_LEN 256 -+ -+struct xt_layer7_info { -+    char protocol[MAX_PROTOCOL_LEN]; -+    char pattern[MAX_PATTERN_LEN]; -+    u_int8_t invert; -+}; -+ -+#endif /* _XT_LAYER7_H */ ---- a/include/net/netfilter/nf_conntrack.h -+++ b/include/net/netfilter/nf_conntrack.h -@@ -116,6 +116,22 @@ struct nf_conn { - 	u_int32_t secmark; - #endif -  -+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || \ -+    defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) -+	struct { -+		/* -+		 * e.g. "http". NULL before decision. "unknown" after decision -+		 * if no match. -+		 */ -+		char *app_proto; -+		/* -+		 * application layer data so far. NULL after match decision. -+		 */ -+		char *app_data; -+		unsigned int app_data_len; -+	} layer7; -+#endif -+ - 	/* Storage reserved for other modules: */ - 	union nf_conntrack_proto proto; -   --- a/net/netfilter/Kconfig  +++ b/net/netfilter/Kconfig -@@ -948,6 +948,27 @@ config NETFILTER_XT_MATCH_STATE +@@ -946,6 +946,27 @@ config NETFILTER_XT_MATCH_STATE   	  To compile it as a module, choose M here.  If unsure, say N. @@ -49,7 +8,7 @@  +	tristate '"layer7" match support'  +	depends on NETFILTER_XTABLES  +	depends on EXPERIMENTAL && (IP_NF_CONNTRACK || NF_CONNTRACK) -+       depends on NF_CT_ACCT ++       depends on NETFILTER_ADVANCED  +	help  +	  Say Y if you want to be able to classify connections (and their  +	  packets) based on regular expression matching of their application @@ -79,38 +38,675 @@   obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o   obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o   obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o ---- a/net/netfilter/nf_conntrack_core.c -+++ b/net/netfilter/nf_conntrack_core.c -@@ -212,6 +212,14 @@ destroy_conntrack(struct nf_conntrack *n - 	 * too. */ - 	nf_ct_remove_expectations(ct); -  -+	#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) -+	if(ct->layer7.app_proto) -+		kfree(ct->layer7.app_proto); -+	if(ct->layer7.app_data) -+	kfree(ct->layer7.app_data); +--- /dev/null ++++ b/net/netfilter/xt_layer7.c +@@ -0,0 +1,666 @@ ++/* ++  Kernel module to match application layer (OSI layer 7) data in connections. ++ ++  http://l7-filter.sf.net ++ ++  (C) 2003-2009 Matthew Strait and Ethan Sommer. ++ ++  This program is free software; you can redistribute it and/or ++  modify it under the terms of the GNU General Public License ++  as published by the Free Software Foundation; either version ++  2 of the License, or (at your option) any later version. ++  http://www.gnu.org/licenses/gpl.txt ++ ++  Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>, ++  xt_helper.c (C) 2002 Harald Welte and cls_layer7.c (C) 2003 Matthew Strait, ++  Ethan Sommer, Justin Levandoski. ++*/ ++ ++#include <linux/spinlock.h> ++#include <linux/version.h> ++#include <net/ip.h> ++#include <net/tcp.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter.h> ++#include <net/netfilter/nf_conntrack.h> ++#include <net/netfilter/nf_conntrack_core.h> ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) ++#include <net/netfilter/nf_conntrack_extend.h> ++#include <net/netfilter/nf_conntrack_acct.h> ++#endif ++#include <linux/netfilter/x_tables.h> ++#include <linux/netfilter/xt_layer7.h> ++#include <linux/ctype.h> ++#include <linux/proc_fs.h> ++ ++#include "regexp/regexp.c" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); ++MODULE_DESCRIPTION("iptables application layer match module"); ++MODULE_ALIAS("ipt_layer7"); ++MODULE_VERSION("2.21"); ++ ++static int maxdatalen = 2048; // this is the default ++module_param(maxdatalen, int, 0444); ++MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter"); ++#ifdef CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG ++	#define DPRINTK(format,args...) printk(format,##args) ++#else ++	#define DPRINTK(format,args...) ++#endif ++ ++/* Number of packets whose data we look at. ++This can be modified through /proc/net/layer7_numpackets */ ++static int num_packets = 10; ++ ++static struct pattern_cache { ++	char * regex_string; ++	regexp * pattern; ++	struct pattern_cache * next; ++} * first_pattern_cache = NULL; ++ ++DEFINE_SPINLOCK(l7_lock); ++ ++static int total_acct_packets(struct nf_conn *ct) ++{ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26) ++	BUG_ON(ct == NULL); ++	return (ct->counters[IP_CT_DIR_ORIGINAL].packets + ct->counters[IP_CT_DIR_REPLY].packets); ++#else ++	struct nf_conn_counter *acct; ++ ++	BUG_ON(ct == NULL); ++	acct = nf_conn_acct_find(ct); ++	if (!acct) ++		return 0; ++	return (acct[IP_CT_DIR_ORIGINAL].packets + acct[IP_CT_DIR_REPLY].packets); ++#endif ++} ++ ++#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG ++/* Converts an unfriendly string into a friendly one by ++replacing unprintables with periods and all whitespace with " ". */ ++static char * friendly_print(unsigned char * s) ++{ ++	char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); ++	int i; ++ ++	if(!f) { ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: out of memory in " ++					"friendly_print, bailing.\n"); ++		return NULL; ++	} ++ ++	for(i = 0; i < strlen(s); i++){ ++		if(isprint(s[i]) && s[i] < 128)	f[i] = s[i]; ++		else if(isspace(s[i]))		f[i] = ' '; ++		else 				f[i] = '.'; ++	} ++	f[i] = '\0'; ++	return f; ++} ++ ++static char dec2hex(int i) ++{ ++	switch (i) { ++		case 0 ... 9: ++			return (i + '0'); ++			break; ++		case 10 ... 15: ++			return (i - 10 + 'a'); ++			break; ++		default: ++			if (net_ratelimit()) ++				printk("layer7: Problem in dec2hex\n"); ++			return '\0'; ++	} ++} ++ ++static char * hex_print(unsigned char * s) ++{ ++	char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); ++	int i; ++ ++	if(!g) { ++	       if (net_ratelimit()) ++			printk(KERN_ERR "layer7: out of memory in hex_print, " ++					"bailing.\n"); ++	       return NULL; ++	} ++ ++	for(i = 0; i < strlen(s); i++) { ++		g[i*3    ] = dec2hex(s[i]/16); ++		g[i*3 + 1] = dec2hex(s[i]%16); ++		g[i*3 + 2] = ' '; ++	} ++	g[i*3] = '\0'; ++ ++	return g; ++} ++#endif // DEBUG ++ ++/* Use instead of regcomp.  As we expect to be seeing the same regexps over and ++over again, it make sense to cache the results. */ ++static regexp * compile_and_cache(const char * regex_string,  ++                                  const char * protocol) ++{ ++	struct pattern_cache * node               = first_pattern_cache; ++	struct pattern_cache * last_pattern_cache = first_pattern_cache; ++	struct pattern_cache * tmp; ++	unsigned int len; ++ ++	while (node != NULL) { ++		if (!strcmp(node->regex_string, regex_string)) ++		return node->pattern; ++ ++		last_pattern_cache = node;/* points at the last non-NULL node */ ++		node = node->next; ++	} ++ ++	/* If we reach the end of the list, then we have not yet cached ++	   the pattern for this regex. Let's do that now. ++	   Be paranoid about running out of memory to avoid list corruption. */ ++	tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); ++ ++	if(!tmp) { ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: out of memory in " ++					"compile_and_cache, bailing.\n"); ++		return NULL; ++	} ++ ++	tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); ++	tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC); ++	tmp->next = NULL; ++ ++	if(!tmp->regex_string || !tmp->pattern) { ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: out of memory in " ++					"compile_and_cache, bailing.\n"); ++		kfree(tmp->regex_string); ++		kfree(tmp->pattern); ++		kfree(tmp); ++		return NULL; ++	} ++ ++	/* Ok.  The new node is all ready now. */ ++	node = tmp; ++ ++	if(first_pattern_cache == NULL) /* list is empty */ ++		first_pattern_cache = node; /* make node the beginning */ ++	else ++		last_pattern_cache->next = node; /* attach node to the end */ ++ ++	/* copy the string and compile the regex */ ++	len = strlen(regex_string); ++	DPRINTK("About to compile this: \"%s\"\n", regex_string); ++	node->pattern = regcomp((char *)regex_string, &len); ++	if ( !node->pattern ) { ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: Error compiling regexp " ++					"\"%s\" (%s)\n",  ++					regex_string, protocol); ++		/* pattern is now cached as NULL, so we won't try again. */ ++	} ++ ++	strcpy(node->regex_string, regex_string); ++	return node->pattern; ++} ++ ++static int can_handle(const struct sk_buff *skb) ++{ ++	if(!ip_hdr(skb)) /* not IP */ ++		return 0; ++	if(ip_hdr(skb)->protocol != IPPROTO_TCP && ++	   ip_hdr(skb)->protocol != IPPROTO_UDP && ++	   ip_hdr(skb)->protocol != IPPROTO_ICMP) ++		return 0; ++	return 1; ++} ++ ++/* Returns offset the into the skb->data that the application data starts */ ++static int app_data_offset(const struct sk_buff *skb) ++{ ++	/* In case we are ported somewhere (ebtables?) where ip_hdr(skb) ++	isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ ++	int ip_hl = 4*ip_hdr(skb)->ihl; ++ ++	if( ip_hdr(skb)->protocol == IPPROTO_TCP ) { ++		/* 12 == offset into TCP header for the header length field. ++		Can't get this with skb->h.th->doff because the tcphdr ++		struct doesn't get set when routing (this is confirmed to be ++		true in Netfilter as well as QoS.) */ ++		int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); ++ ++		return ip_hl + tcp_hl; ++	} else if( ip_hdr(skb)->protocol == IPPROTO_UDP  ) { ++		return ip_hl + 8; /* UDP header is always 8 bytes */ ++	} else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) { ++		return ip_hl + 8; /* ICMP header is 8 bytes */ ++	} else { ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: tried to handle unknown " ++					"protocol!\n"); ++		return ip_hl + 8; /* something reasonable */ ++	} ++} ++ ++/* handles whether there's a match when we aren't appending data anymore */ ++static int match_no_append(struct nf_conn * conntrack,  ++                           struct nf_conn * master_conntrack,  ++                           enum ip_conntrack_info ctinfo, ++                           enum ip_conntrack_info master_ctinfo, ++                           const struct xt_layer7_info * info) ++{ ++	/* If we're in here, throw the app data away */ ++	if(master_conntrack->layer7.app_data != NULL) { ++ ++	#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG ++		if(!master_conntrack->layer7.app_proto) { ++			char * f =  ++			  friendly_print(master_conntrack->layer7.app_data); ++			char * g =  ++			  hex_print(master_conntrack->layer7.app_data); ++			DPRINTK("\nl7-filter gave up after %d bytes " ++				"(%d packets):\n%s\n", ++				strlen(f), total_acct_packets(master_conntrack), f); ++			kfree(f); ++			DPRINTK("In hex: %s\n", g); ++			kfree(g); ++		}  +	#endif  + ++		kfree(master_conntrack->layer7.app_data); ++		master_conntrack->layer7.app_data = NULL; /* don't free again */ ++	}  + - 	/* We overload first tuple to link into unconfirmed list. */ - 	if (!nf_ct_is_confirmed(ct)) { - 		BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); ---- a/net/netfilter/nf_conntrack_standalone.c -+++ b/net/netfilter/nf_conntrack_standalone.c -@@ -200,6 +200,12 @@ static int ct_seq_show(struct seq_file * - 		goto release; - #endif -  -+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) -+	if(ct->layer7.app_proto && -+           seq_printf(s, "l7proto=%s ", ct->layer7.app_proto)) -+		return -ENOSPC; ++	if(master_conntrack->layer7.app_proto){ ++		/* Here child connections set their .app_proto (for /proc) */ ++		if(!conntrack->layer7.app_proto) { ++			conntrack->layer7.app_proto =  ++			  kmalloc(strlen(master_conntrack->layer7.app_proto)+1,  ++			    GFP_ATOMIC); ++			if(!conntrack->layer7.app_proto){ ++				if (net_ratelimit()) ++					printk(KERN_ERR "layer7: out of memory " ++							"in match_no_append, " ++							"bailing.\n"); ++				return 1; ++			} ++			strcpy(conntrack->layer7.app_proto,  ++				master_conntrack->layer7.app_proto); ++		} ++ ++		return (!strcmp(master_conntrack->layer7.app_proto,  ++				info->protocol)); ++	} ++	else { ++		/* If not classified, set to "unknown" to distinguish from ++		connections that are still being tested. */ ++		master_conntrack->layer7.app_proto =  ++			kmalloc(strlen("unknown")+1, GFP_ATOMIC); ++		if(!master_conntrack->layer7.app_proto){ ++			if (net_ratelimit()) ++				printk(KERN_ERR "layer7: out of memory in " ++						"match_no_append, bailing.\n"); ++			return 1; ++		} ++		strcpy(master_conntrack->layer7.app_proto, "unknown"); ++		return 0; ++	} ++} ++ ++/* add the new app data to the conntrack.  Return number of bytes added. */ ++static int add_data(struct nf_conn * master_conntrack, ++                    char * app_data, int appdatalen) ++{ ++	int length = 0, i; ++	int oldlength = master_conntrack->layer7.app_data_len; ++ ++	/* This is a fix for a race condition by Deti Fliegl. However, I'm not  ++	   clear on whether the race condition exists or whether this really  ++	   fixes it.  I might just be being dense... Anyway, if it's not really  ++	   a fix, all it does is waste a very small amount of time. */ ++	if(!master_conntrack->layer7.app_data) return 0; ++ ++	/* Strip nulls. Make everything lower case (our regex lib doesn't ++	do case insensitivity).  Add it to the end of the current data. */ ++	for(i = 0; i < maxdatalen-oldlength-1 && ++		   i < appdatalen; i++) { ++		if(app_data[i] != '\0') { ++			/* the kernel version of tolower mungs 'upper ascii' */ ++			master_conntrack->layer7.app_data[length+oldlength] = ++				isascii(app_data[i])?  ++					tolower(app_data[i]) : app_data[i]; ++			length++; ++		} ++	} ++ ++	master_conntrack->layer7.app_data[length+oldlength] = '\0'; ++	master_conntrack->layer7.app_data_len = length + oldlength; ++ ++	return length; ++} ++ ++/* taken from drivers/video/modedb.c */ ++static int my_atoi(const char *s) ++{ ++	int val = 0; ++ ++	for (;; s++) { ++		switch (*s) { ++			case '0'...'9': ++			val = 10*val+(*s-'0'); ++			break; ++		default: ++			return val; ++		} ++	} ++} ++ ++/* write out num_packets to userland. */ ++static int layer7_read_proc(char* page, char ** start, off_t off, int count, ++                            int* eof, void * data) ++{ ++	if(num_packets > 99 && net_ratelimit()) ++		printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); ++ ++	page[0] = num_packets/10 + '0'; ++	page[1] = num_packets%10 + '0'; ++	page[2] = '\n'; ++	page[3] = '\0'; ++ ++	*eof=1; ++ ++	return 3; ++} ++ ++/* Read in num_packets from userland */ ++static int layer7_write_proc(struct file* file, const char* buffer, ++                             unsigned long count, void *data) ++{ ++	char * foo = kmalloc(count, GFP_ATOMIC); ++ ++	if(!foo){ ++		if (net_ratelimit()) ++			printk(KERN_ERR "layer7: out of memory, bailing. " ++					"num_packets unchanged.\n"); ++		return count; ++	} ++ ++	if(copy_from_user(foo, buffer, count)) { ++		return -EFAULT; ++	} ++ ++ ++	num_packets = my_atoi(foo); ++	kfree (foo); ++ ++	/* This has an arbitrary limit to make the math easier. I'm lazy. ++	But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ ++	if(num_packets > 99) { ++		printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); ++		num_packets = 99; ++	} else if(num_packets < 1) { ++		printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); ++		num_packets = 1; ++	} ++ ++	return count; ++} ++ ++static bool ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++match(const struct sk_buff *skbin, const struct xt_match_param *par) ++#else ++match(const struct sk_buff *skbin, ++      const struct net_device *in, ++      const struct net_device *out, ++      const struct xt_match *match, ++      const void *matchinfo, ++      int offset, ++      unsigned int protoff, ++      bool *hotdrop)  +#endif ++{ ++	/* sidestep const without getting a compiler warning... */ ++	struct sk_buff * skb = (struct sk_buff *)skbin;   + - 	if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) - 		goto release; -  ++	const struct xt_layer7_info * info =  ++	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++		par->matchinfo; ++	#else ++		matchinfo; ++	#endif ++ ++	enum ip_conntrack_info master_ctinfo, ctinfo; ++	struct nf_conn *master_conntrack, *conntrack; ++	unsigned char * app_data; ++	unsigned int pattern_result, appdatalen; ++	regexp * comppattern; ++ ++	/* Be paranoid/incompetent - lock the entire match function. */ ++	spin_lock_bh(&l7_lock); ++ ++	if(!can_handle(skb)){ ++		DPRINTK("layer7: This is some protocol I can't handle.\n"); ++		spin_unlock_bh(&l7_lock); ++		return info->invert; ++	} ++ ++	/* Treat parent & all its children together as one connection, except ++	for the purpose of setting conntrack->layer7.app_proto in the actual ++	connection. This makes /proc/net/ip_conntrack more satisfying. */ ++	if(!(conntrack = nf_ct_get(skb, &ctinfo)) || ++	   !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){ ++		DPRINTK("layer7: couldn't get conntrack.\n"); ++		spin_unlock_bh(&l7_lock); ++		return info->invert; ++	} ++ ++	/* Try to get a master conntrack (and its master etc) for FTP, etc. */ ++	while (master_ct(master_conntrack) != NULL) ++		master_conntrack = master_ct(master_conntrack); ++ ++	/* if we've classified it or seen too many packets */ ++	if(total_acct_packets(master_conntrack) > num_packets || ++	   master_conntrack->layer7.app_proto) { ++ ++		pattern_result = match_no_append(conntrack, master_conntrack,  ++						 ctinfo, master_ctinfo, info); ++ ++		/* skb->cb[0] == seen. Don't do things twice if there are  ++		multiple l7 rules. I'm not sure that using cb for this purpose  ++		is correct, even though it says "put your private variables  ++		there". But it doesn't look like it is being used for anything ++		else in the skbs that make it here. */ ++		skb->cb[0] = 1; /* marking it seen here's probably irrelevant */ ++ ++		spin_unlock_bh(&l7_lock); ++		return (pattern_result ^ info->invert); ++	} ++ ++	if(skb_is_nonlinear(skb)){ ++		if(skb_linearize(skb) != 0){ ++			if (net_ratelimit()) ++				printk(KERN_ERR "layer7: failed to linearize " ++						"packet, bailing.\n"); ++			spin_unlock_bh(&l7_lock); ++			return info->invert; ++		} ++	} ++ ++	/* now that the skb is linearized, it's safe to set these. */ ++	app_data = skb->data + app_data_offset(skb); ++	appdatalen = skb_tail_pointer(skb) - app_data; ++ ++	/* the return value gets checked later, when we're ready to use it */ ++	comppattern = compile_and_cache(info->pattern, info->protocol); ++ ++	/* On the first packet of a connection, allocate space for app data */ ++	if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] &&  ++	   !master_conntrack->layer7.app_data){ ++		master_conntrack->layer7.app_data =  ++			kmalloc(maxdatalen, GFP_ATOMIC); ++		if(!master_conntrack->layer7.app_data){ ++			if (net_ratelimit()) ++				printk(KERN_ERR "layer7: out of memory in " ++						"match, bailing.\n"); ++			spin_unlock_bh(&l7_lock); ++			return info->invert; ++		} ++ ++		master_conntrack->layer7.app_data[0] = '\0'; ++	} ++ ++	/* Can be here, but unallocated, if numpackets is increased near ++	the beginning of a connection */ ++	if(master_conntrack->layer7.app_data == NULL){ ++		spin_unlock_bh(&l7_lock); ++		return info->invert; /* unmatched */ ++	} ++ ++	if(!skb->cb[0]){ ++		int newbytes; ++		newbytes = add_data(master_conntrack, app_data, appdatalen); ++ ++		if(newbytes == 0) { /* didn't add any data */ ++			skb->cb[0] = 1; ++			/* Didn't match before, not going to match now */ ++			spin_unlock_bh(&l7_lock); ++			return info->invert; ++		} ++	} ++ ++	/* If looking for "unknown", then never match.  "Unknown" means that ++	we've given up; we're still trying with these packets. */ ++	if(!strcmp(info->protocol, "unknown")) { ++		pattern_result = 0; ++	/* If looking for "unset", then always match. "Unset" means that we ++	haven't yet classified the connection. */ ++	} else if(!strcmp(info->protocol, "unset")) { ++		pattern_result = 2; ++		DPRINTK("layer7: matched unset: not yet classified " ++			"(%d/%d packets)\n", ++                        total_acct_packets(master_conntrack), num_packets); ++	/* If the regexp failed to compile, don't bother running it */ ++	} else if(comppattern &&  ++		  regexec(comppattern, master_conntrack->layer7.app_data)){ ++		DPRINTK("layer7: matched %s\n", info->protocol); ++		pattern_result = 1; ++	} else pattern_result = 0; ++ ++	if(pattern_result == 1) { ++		master_conntrack->layer7.app_proto =  ++			kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); ++		if(!master_conntrack->layer7.app_proto){ ++			if (net_ratelimit()) ++				printk(KERN_ERR "layer7: out of memory in " ++						"match, bailing.\n"); ++			spin_unlock_bh(&l7_lock); ++			return (pattern_result ^ info->invert); ++		} ++		strcpy(master_conntrack->layer7.app_proto, info->protocol); ++	} else if(pattern_result > 1) { /* cleanup from "unset" */ ++		pattern_result = 1; ++	} ++ ++	/* mark the packet seen */ ++	skb->cb[0] = 1; ++ ++	spin_unlock_bh(&l7_lock); ++	return (pattern_result ^ info->invert); ++} ++ ++// load nf_conntrack_ipv4 ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++static bool check(const struct xt_mtchk_param *par) ++{ ++        if (nf_ct_l3proto_try_module_get(par->match->family) < 0) { ++                printk(KERN_WARNING "can't load conntrack support for " ++                                    "proto=%d\n", par->match->family); ++#else ++static bool check(const char *tablename, const void *inf, ++		 const struct xt_match *match, void *matchinfo, ++		 unsigned int hook_mask) ++{ ++        if (nf_ct_l3proto_try_module_get(match->family) < 0) { ++                printk(KERN_WARNING "can't load conntrack support for " ++                                    "proto=%d\n", match->family); ++#endif ++                return 0; ++        } ++	return 1; ++} ++ ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) ++	static void destroy(const struct xt_mtdtor_param *par) ++	{ ++		nf_ct_l3proto_module_put(par->match->family); ++	} ++#else ++	static void destroy(const struct xt_match *match, void *matchinfo) ++	{ ++		nf_ct_l3proto_module_put(match->family); ++	} ++#endif ++ ++static struct xt_match xt_layer7_match[] __read_mostly = { ++{ ++	.name		= "layer7", ++	.family		= AF_INET, ++	.checkentry	= check, ++	.match		= match, ++	.destroy	= destroy, ++	.matchsize	= sizeof(struct xt_layer7_info), ++	.me		= THIS_MODULE ++} ++}; ++ ++static void layer7_cleanup_proc(void) ++{ ++	remove_proc_entry("layer7_numpackets", init_net.proc_net); ++} ++ ++/* register the proc file */ ++static void layer7_init_proc(void) ++{ ++	struct proc_dir_entry* entry; ++	entry = create_proc_entry("layer7_numpackets", 0644, init_net.proc_net); ++	entry->read_proc = layer7_read_proc; ++	entry->write_proc = layer7_write_proc; ++} ++ ++static int __init xt_layer7_init(void) ++{ ++	need_conntrack(); ++ ++	layer7_init_proc(); ++	if(maxdatalen < 1) { ++		printk(KERN_WARNING "layer7: maxdatalen can't be < 1, " ++			"using 1\n"); ++		maxdatalen = 1; ++	} ++	/* This is not a hard limit.  It's just here to prevent people from ++	bringing their slow machines to a grinding halt. */ ++	else if(maxdatalen > 65536) { ++		printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, " ++			"using 65536\n"); ++		maxdatalen = 65536; ++	} ++	return xt_register_matches(xt_layer7_match, ++				   ARRAY_SIZE(xt_layer7_match)); ++} ++ ++static void __exit xt_layer7_fini(void) ++{ ++	layer7_cleanup_proc(); ++	xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match)); ++} ++ ++module_init(xt_layer7_init); ++module_exit(xt_layer7_fini);  --- /dev/null  +++ b/net/netfilter/regexp/regexp.c  @@ -0,0 +1,1197 @@ @@ -1461,672 +2057,76 @@  +	}  +	*dst++ = '\0';  +} ---- /dev/null -+++ b/net/netfilter/xt_layer7.c -@@ -0,0 +1,666 @@ -+/* -+  Kernel module to match application layer (OSI layer 7) data in connections. -+ -+  http://l7-filter.sf.net -+ -+  (C) 2003-2009 Matthew Strait and Ethan Sommer. -+ -+  This program is free software; you can redistribute it and/or -+  modify it under the terms of the GNU General Public License -+  as published by the Free Software Foundation; either version -+  2 of the License, or (at your option) any later version. -+  http://www.gnu.org/licenses/gpl.txt -+ -+  Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>, -+  xt_helper.c (C) 2002 Harald Welte and cls_layer7.c (C) 2003 Matthew Strait, -+  Ethan Sommer, Justin Levandoski. -+*/ -+ -+#include <linux/spinlock.h> -+#include <linux/version.h> -+#include <net/ip.h> -+#include <net/tcp.h> -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter.h> -+#include <net/netfilter/nf_conntrack.h> -+#include <net/netfilter/nf_conntrack_core.h> -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) -+#include <net/netfilter/nf_conntrack_extend.h> -+#include <net/netfilter/nf_conntrack_acct.h> -+#endif -+#include <linux/netfilter/x_tables.h> -+#include <linux/netfilter/xt_layer7.h> -+#include <linux/ctype.h> -+#include <linux/proc_fs.h> -+ -+#include "regexp/regexp.c" -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); -+MODULE_DESCRIPTION("iptables application layer match module"); -+MODULE_ALIAS("ipt_layer7"); -+MODULE_VERSION("2.21"); -+ -+static int maxdatalen = 2048; // this is the default -+module_param(maxdatalen, int, 0444); -+MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter"); -+#ifdef CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG -+	#define DPRINTK(format,args...) printk(format,##args) -+#else -+	#define DPRINTK(format,args...) -+#endif -+ -+/* Number of packets whose data we look at. -+This can be modified through /proc/net/layer7_numpackets */ -+static int num_packets = 10; -+ -+static struct pattern_cache { -+	char * regex_string; -+	regexp * pattern; -+	struct pattern_cache * next; -+} * first_pattern_cache = NULL; -+ -+DEFINE_SPINLOCK(l7_lock); -+ -+static int total_acct_packets(struct nf_conn *ct) -+{ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26) -+	BUG_ON(ct == NULL); -+	return (ct->counters[IP_CT_DIR_ORIGINAL].packets + ct->counters[IP_CT_DIR_REPLY].packets); -+#else -+	struct nf_conn_counter *acct; -+ -+	BUG_ON(ct == NULL); -+	acct = nf_conn_acct_find(ct); -+	if (!acct) -+		return 0; -+	return (acct[IP_CT_DIR_ORIGINAL].packets + acct[IP_CT_DIR_REPLY].packets); -+#endif -+} -+ -+#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG -+/* Converts an unfriendly string into a friendly one by -+replacing unprintables with periods and all whitespace with " ". */ -+static char * friendly_print(unsigned char * s) -+{ -+	char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); -+	int i; -+ -+	if(!f) { -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: out of memory in " -+					"friendly_print, bailing.\n"); -+		return NULL; -+	} -+ -+	for(i = 0; i < strlen(s); i++){ -+		if(isprint(s[i]) && s[i] < 128)	f[i] = s[i]; -+		else if(isspace(s[i]))		f[i] = ' '; -+		else 				f[i] = '.'; -+	} -+	f[i] = '\0'; -+	return f; -+} -+ -+static char dec2hex(int i) -+{ -+	switch (i) { -+		case 0 ... 9: -+			return (i + '0'); -+			break; -+		case 10 ... 15: -+			return (i - 10 + 'a'); -+			break; -+		default: -+			if (net_ratelimit()) -+				printk("layer7: Problem in dec2hex\n"); -+			return '\0'; -+	} -+} -+ -+static char * hex_print(unsigned char * s) -+{ -+	char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); -+	int i; -+ -+	if(!g) { -+	       if (net_ratelimit()) -+			printk(KERN_ERR "layer7: out of memory in hex_print, " -+					"bailing.\n"); -+	       return NULL; -+	} -+ -+	for(i = 0; i < strlen(s); i++) { -+		g[i*3    ] = dec2hex(s[i]/16); -+		g[i*3 + 1] = dec2hex(s[i]%16); -+		g[i*3 + 2] = ' '; -+	} -+	g[i*3] = '\0'; -+ -+	return g; -+} -+#endif // DEBUG -+ -+/* Use instead of regcomp.  As we expect to be seeing the same regexps over and -+over again, it make sense to cache the results. */ -+static regexp * compile_and_cache(const char * regex_string,  -+                                  const char * protocol) -+{ -+	struct pattern_cache * node               = first_pattern_cache; -+	struct pattern_cache * last_pattern_cache = first_pattern_cache; -+	struct pattern_cache * tmp; -+	unsigned int len; -+ -+	while (node != NULL) { -+		if (!strcmp(node->regex_string, regex_string)) -+		return node->pattern; -+ -+		last_pattern_cache = node;/* points at the last non-NULL node */ -+		node = node->next; -+	} -+ -+	/* If we reach the end of the list, then we have not yet cached -+	   the pattern for this regex. Let's do that now. -+	   Be paranoid about running out of memory to avoid list corruption. */ -+	tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); -+ -+	if(!tmp) { -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: out of memory in " -+					"compile_and_cache, bailing.\n"); -+		return NULL; -+	} -+ -+	tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); -+	tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC); -+	tmp->next = NULL; -+ -+	if(!tmp->regex_string || !tmp->pattern) { -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: out of memory in " -+					"compile_and_cache, bailing.\n"); -+		kfree(tmp->regex_string); -+		kfree(tmp->pattern); -+		kfree(tmp); -+		return NULL; -+	} -+ -+	/* Ok.  The new node is all ready now. */ -+	node = tmp; -+ -+	if(first_pattern_cache == NULL) /* list is empty */ -+		first_pattern_cache = node; /* make node the beginning */ -+	else -+		last_pattern_cache->next = node; /* attach node to the end */ -+ -+	/* copy the string and compile the regex */ -+	len = strlen(regex_string); -+	DPRINTK("About to compile this: \"%s\"\n", regex_string); -+	node->pattern = regcomp((char *)regex_string, &len); -+	if ( !node->pattern ) { -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: Error compiling regexp " -+					"\"%s\" (%s)\n",  -+					regex_string, protocol); -+		/* pattern is now cached as NULL, so we won't try again. */ -+	} -+ -+	strcpy(node->regex_string, regex_string); -+	return node->pattern; -+} -+ -+static int can_handle(const struct sk_buff *skb) -+{ -+	if(!ip_hdr(skb)) /* not IP */ -+		return 0; -+	if(ip_hdr(skb)->protocol != IPPROTO_TCP && -+	   ip_hdr(skb)->protocol != IPPROTO_UDP && -+	   ip_hdr(skb)->protocol != IPPROTO_ICMP) -+		return 0; -+	return 1; -+} -+ -+/* Returns offset the into the skb->data that the application data starts */ -+static int app_data_offset(const struct sk_buff *skb) -+{ -+	/* In case we are ported somewhere (ebtables?) where ip_hdr(skb) -+	isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ -+	int ip_hl = 4*ip_hdr(skb)->ihl; -+ -+	if( ip_hdr(skb)->protocol == IPPROTO_TCP ) { -+		/* 12 == offset into TCP header for the header length field. -+		Can't get this with skb->h.th->doff because the tcphdr -+		struct doesn't get set when routing (this is confirmed to be -+		true in Netfilter as well as QoS.) */ -+		int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); -+ -+		return ip_hl + tcp_hl; -+	} else if( ip_hdr(skb)->protocol == IPPROTO_UDP  ) { -+		return ip_hl + 8; /* UDP header is always 8 bytes */ -+	} else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) { -+		return ip_hl + 8; /* ICMP header is 8 bytes */ -+	} else { -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: tried to handle unknown " -+					"protocol!\n"); -+		return ip_hl + 8; /* something reasonable */ -+	} -+} -+ -+/* handles whether there's a match when we aren't appending data anymore */ -+static int match_no_append(struct nf_conn * conntrack,  -+                           struct nf_conn * master_conntrack,  -+                           enum ip_conntrack_info ctinfo, -+                           enum ip_conntrack_info master_ctinfo, -+                           const struct xt_layer7_info * info) -+{ -+	/* If we're in here, throw the app data away */ -+	if(master_conntrack->layer7.app_data != NULL) { -+ -+	#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG -+		if(!master_conntrack->layer7.app_proto) { -+			char * f =  -+			  friendly_print(master_conntrack->layer7.app_data); -+			char * g =  -+			  hex_print(master_conntrack->layer7.app_data); -+			DPRINTK("\nl7-filter gave up after %d bytes " -+				"(%d packets):\n%s\n", -+				strlen(f), total_acct_packets(master_conntrack), f); -+			kfree(f); -+			DPRINTK("In hex: %s\n", g); -+			kfree(g); -+		} +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -202,6 +202,14 @@ destroy_conntrack(struct nf_conntrack *n + 	 * too. */ + 	nf_ct_remove_expectations(ct); +  ++	#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) ++	if(ct->layer7.app_proto) ++		kfree(ct->layer7.app_proto); ++	if(ct->layer7.app_data) ++	kfree(ct->layer7.app_data);  +	#endif  + -+		kfree(master_conntrack->layer7.app_data); -+		master_conntrack->layer7.app_data = NULL; /* don't free again */ -+	} -+ -+	if(master_conntrack->layer7.app_proto){ -+		/* Here child connections set their .app_proto (for /proc) */ -+		if(!conntrack->layer7.app_proto) { -+			conntrack->layer7.app_proto =  -+			  kmalloc(strlen(master_conntrack->layer7.app_proto)+1,  -+			    GFP_ATOMIC); -+			if(!conntrack->layer7.app_proto){ -+				if (net_ratelimit()) -+					printk(KERN_ERR "layer7: out of memory " -+							"in match_no_append, " -+							"bailing.\n"); -+				return 1; -+			} -+			strcpy(conntrack->layer7.app_proto,  -+				master_conntrack->layer7.app_proto); -+		} -+ -+		return (!strcmp(master_conntrack->layer7.app_proto,  -+				info->protocol)); -+	} -+	else { -+		/* If not classified, set to "unknown" to distinguish from -+		connections that are still being tested. */ -+		master_conntrack->layer7.app_proto =  -+			kmalloc(strlen("unknown")+1, GFP_ATOMIC); -+		if(!master_conntrack->layer7.app_proto){ -+			if (net_ratelimit()) -+				printk(KERN_ERR "layer7: out of memory in " -+						"match_no_append, bailing.\n"); -+			return 1; -+		} -+		strcpy(master_conntrack->layer7.app_proto, "unknown"); -+		return 0; -+	} -+} -+ -+/* add the new app data to the conntrack.  Return number of bytes added. */ -+static int add_data(struct nf_conn * master_conntrack, -+                    char * app_data, int appdatalen) -+{ -+	int length = 0, i; -+	int oldlength = master_conntrack->layer7.app_data_len; -+ -+	/* This is a fix for a race condition by Deti Fliegl. However, I'm not  -+	   clear on whether the race condition exists or whether this really  -+	   fixes it.  I might just be being dense... Anyway, if it's not really  -+	   a fix, all it does is waste a very small amount of time. */ -+	if(!master_conntrack->layer7.app_data) return 0; -+ -+	/* Strip nulls. Make everything lower case (our regex lib doesn't -+	do case insensitivity).  Add it to the end of the current data. */ -+	for(i = 0; i < maxdatalen-oldlength-1 && -+		   i < appdatalen; i++) { -+		if(app_data[i] != '\0') { -+			/* the kernel version of tolower mungs 'upper ascii' */ -+			master_conntrack->layer7.app_data[length+oldlength] = -+				isascii(app_data[i])?  -+					tolower(app_data[i]) : app_data[i]; -+			length++; -+		} -+	} -+ -+	master_conntrack->layer7.app_data[length+oldlength] = '\0'; -+	master_conntrack->layer7.app_data_len = length + oldlength; -+ -+	return length; -+} -+ -+/* taken from drivers/video/modedb.c */ -+static int my_atoi(const char *s) -+{ -+	int val = 0; -+ -+	for (;; s++) { -+		switch (*s) { -+			case '0'...'9': -+			val = 10*val+(*s-'0'); -+			break; -+		default: -+			return val; -+		} -+	} -+} -+ -+/* write out num_packets to userland. */ -+static int layer7_read_proc(char* page, char ** start, off_t off, int count, -+                            int* eof, void * data) -+{ -+	if(num_packets > 99 && net_ratelimit()) -+		printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); -+ -+	page[0] = num_packets/10 + '0'; -+	page[1] = num_packets%10 + '0'; -+	page[2] = '\n'; -+	page[3] = '\0'; -+ -+	*eof=1; -+ -+	return 3; -+}  + -+/* Read in num_packets from userland */ -+static int layer7_write_proc(struct file* file, const char* buffer, -+                             unsigned long count, void *data) -+{ -+	char * foo = kmalloc(count, GFP_ATOMIC); -+ -+	if(!foo){ -+		if (net_ratelimit()) -+			printk(KERN_ERR "layer7: out of memory, bailing. " -+					"num_packets unchanged.\n"); -+		return count; -+	} -+ -+	if(copy_from_user(foo, buffer, count)) { -+		return -EFAULT; -+	} -+ -+ -+	num_packets = my_atoi(foo); -+	kfree (foo); -+ -+	/* This has an arbitrary limit to make the math easier. I'm lazy. -+	But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ -+	if(num_packets > 99) { -+		printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); -+		num_packets = 99; -+	} else if(num_packets < 1) { -+		printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); -+		num_packets = 1; -+	} -+ -+	return count; -+} -+ -+static bool -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -+match(const struct sk_buff *skbin, const struct xt_match_param *par) -+#else -+match(const struct sk_buff *skbin, -+      const struct net_device *in, -+      const struct net_device *out, -+      const struct xt_match *match, -+      const void *matchinfo, -+      int offset, -+      unsigned int protoff, -+      bool *hotdrop) + 	/* We overload first tuple to link into unconfirmed list. */ + 	if (!nf_ct_is_confirmed(ct)) { + 		BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -178,6 +178,12 @@ static int ct_seq_show(struct seq_file * + 		goto release; + #endif +  ++#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) ++	if(ct->layer7.app_proto && ++           seq_printf(s, "l7proto=%s ", ct->layer7.app_proto)) ++		return -ENOSPC;  +#endif -+{ -+	/* sidestep const without getting a compiler warning... */ -+	struct sk_buff * skb = (struct sk_buff *)skbin;  -+ -+	const struct xt_layer7_info * info =  -+	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -+		par->matchinfo; -+	#else -+		matchinfo; -+	#endif -+ -+	enum ip_conntrack_info master_ctinfo, ctinfo; -+	struct nf_conn *master_conntrack, *conntrack; -+	unsigned char * app_data; -+	unsigned int pattern_result, appdatalen; -+	regexp * comppattern; -+ -+	/* Be paranoid/incompetent - lock the entire match function. */ -+	spin_lock_bh(&l7_lock); -+ -+	if(!can_handle(skb)){ -+		DPRINTK("layer7: This is some protocol I can't handle.\n"); -+		spin_unlock_bh(&l7_lock); -+		return info->invert; -+	} -+ -+	/* Treat parent & all its children together as one connection, except -+	for the purpose of setting conntrack->layer7.app_proto in the actual -+	connection. This makes /proc/net/ip_conntrack more satisfying. */ -+	if(!(conntrack = nf_ct_get(skb, &ctinfo)) || -+	   !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){ -+		DPRINTK("layer7: couldn't get conntrack.\n"); -+		spin_unlock_bh(&l7_lock); -+		return info->invert; -+	} -+ -+	/* Try to get a master conntrack (and its master etc) for FTP, etc. */ -+	while (master_ct(master_conntrack) != NULL) -+		master_conntrack = master_ct(master_conntrack); -+ -+	/* if we've classified it or seen too many packets */ -+	if(total_acct_packets(master_conntrack) > num_packets || -+	   master_conntrack->layer7.app_proto) { -+ -+		pattern_result = match_no_append(conntrack, master_conntrack,  -+						 ctinfo, master_ctinfo, info); -+ -+		/* skb->cb[0] == seen. Don't do things twice if there are  -+		multiple l7 rules. I'm not sure that using cb for this purpose  -+		is correct, even though it says "put your private variables  -+		there". But it doesn't look like it is being used for anything -+		else in the skbs that make it here. */ -+		skb->cb[0] = 1; /* marking it seen here's probably irrelevant */ -+ -+		spin_unlock_bh(&l7_lock); -+		return (pattern_result ^ info->invert); -+	} -+ -+	if(skb_is_nonlinear(skb)){ -+		if(skb_linearize(skb) != 0){ -+			if (net_ratelimit()) -+				printk(KERN_ERR "layer7: failed to linearize " -+						"packet, bailing.\n"); -+			spin_unlock_bh(&l7_lock); -+			return info->invert; -+		} -+	} -+ -+	/* now that the skb is linearized, it's safe to set these. */ -+	app_data = skb->data + app_data_offset(skb); -+	appdatalen = skb_tail_pointer(skb) - app_data; -+ -+	/* the return value gets checked later, when we're ready to use it */ -+	comppattern = compile_and_cache(info->pattern, info->protocol); -+ -+	/* On the first packet of a connection, allocate space for app data */ -+	if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] &&  -+	   !master_conntrack->layer7.app_data){ -+		master_conntrack->layer7.app_data =  -+			kmalloc(maxdatalen, GFP_ATOMIC); -+		if(!master_conntrack->layer7.app_data){ -+			if (net_ratelimit()) -+				printk(KERN_ERR "layer7: out of memory in " -+						"match, bailing.\n"); -+			spin_unlock_bh(&l7_lock); -+			return info->invert; -+		} -+ -+		master_conntrack->layer7.app_data[0] = '\0'; -+	} -+ -+	/* Can be here, but unallocated, if numpackets is increased near -+	the beginning of a connection */ -+	if(master_conntrack->layer7.app_data == NULL){ -+		spin_unlock_bh(&l7_lock); -+		return info->invert; /* unmatched */ -+	} -+ -+	if(!skb->cb[0]){ -+		int newbytes; -+		newbytes = add_data(master_conntrack, app_data, appdatalen); -+ -+		if(newbytes == 0) { /* didn't add any data */ -+			skb->cb[0] = 1; -+			/* Didn't match before, not going to match now */ -+			spin_unlock_bh(&l7_lock); -+			return info->invert; -+		} -+	} -+ -+	/* If looking for "unknown", then never match.  "Unknown" means that -+	we've given up; we're still trying with these packets. */ -+	if(!strcmp(info->protocol, "unknown")) { -+		pattern_result = 0; -+	/* If looking for "unset", then always match. "Unset" means that we -+	haven't yet classified the connection. */ -+	} else if(!strcmp(info->protocol, "unset")) { -+		pattern_result = 2; -+		DPRINTK("layer7: matched unset: not yet classified " -+			"(%d/%d packets)\n", -+                        total_acct_packets(master_conntrack), num_packets); -+	/* If the regexp failed to compile, don't bother running it */ -+	} else if(comppattern &&  -+		  regexec(comppattern, master_conntrack->layer7.app_data)){ -+		DPRINTK("layer7: matched %s\n", info->protocol); -+		pattern_result = 1; -+	} else pattern_result = 0;  + -+	if(pattern_result == 1) { -+		master_conntrack->layer7.app_proto =  -+			kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); -+		if(!master_conntrack->layer7.app_proto){ -+			if (net_ratelimit()) -+				printk(KERN_ERR "layer7: out of memory in " -+						"match, bailing.\n"); -+			spin_unlock_bh(&l7_lock); -+			return (pattern_result ^ info->invert); -+		} -+		strcpy(master_conntrack->layer7.app_proto, info->protocol); -+	} else if(pattern_result > 1) { /* cleanup from "unset" */ -+		pattern_result = 1; -+	} -+ -+	/* mark the packet seen */ -+	skb->cb[0] = 1; -+ -+	spin_unlock_bh(&l7_lock); -+	return (pattern_result ^ info->invert); -+} -+ -+// load nf_conntrack_ipv4 -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -+static bool check(const struct xt_mtchk_param *par) -+{ -+        if (nf_ct_l3proto_try_module_get(par->match->family) < 0) { -+                printk(KERN_WARNING "can't load conntrack support for " -+                                    "proto=%d\n", par->match->family); -+#else -+static bool check(const char *tablename, const void *inf, -+		 const struct xt_match *match, void *matchinfo, -+		 unsigned int hook_mask) -+{ -+        if (nf_ct_l3proto_try_module_get(match->family) < 0) { -+                printk(KERN_WARNING "can't load conntrack support for " -+                                    "proto=%d\n", match->family); + 	if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) + 		goto release; +  +--- a/include/net/netfilter/nf_conntrack.h ++++ b/include/net/netfilter/nf_conntrack.h +@@ -116,6 +116,22 @@ struct nf_conn { + 	u_int32_t secmark; + #endif +  ++#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || \ ++    defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) ++	struct { ++		/* ++		 * e.g. "http". NULL before decision. "unknown" after decision ++		 * if no match. ++		 */ ++		char *app_proto; ++		/* ++		 * application layer data so far. NULL after match decision. ++		 */ ++		char *app_data; ++		unsigned int app_data_len; ++	} layer7;  +#endif -+                return 0; -+        } -+	return 1; -+}  + + 	/* Storage reserved for other modules: */ + 	union nf_conntrack_proto proto; +  +--- /dev/null ++++ b/include/linux/netfilter/xt_layer7.h +@@ -0,0 +1,13 @@ ++#ifndef _XT_LAYER7_H ++#define _XT_LAYER7_H  + -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) -+	static void destroy(const struct xt_mtdtor_param *par) -+	{ -+		nf_ct_l3proto_module_put(par->match->family); -+	} -+#else -+	static void destroy(const struct xt_match *match, void *matchinfo) -+	{ -+		nf_ct_l3proto_module_put(match->family); -+	} -+#endif ++#define MAX_PATTERN_LEN 8192 ++#define MAX_PROTOCOL_LEN 256  + -+static struct xt_match xt_layer7_match[] __read_mostly = { -+{ -+	.name		= "layer7", -+	.family		= AF_INET, -+	.checkentry	= check, -+	.match		= match, -+	.destroy	= destroy, -+	.matchsize	= sizeof(struct xt_layer7_info), -+	.me		= THIS_MODULE -+} ++struct xt_layer7_info { ++    char protocol[MAX_PROTOCOL_LEN]; ++    char pattern[MAX_PATTERN_LEN]; ++    u_int8_t invert;  +};  + -+static void layer7_cleanup_proc(void) -+{ -+	remove_proc_entry("layer7_numpackets", init_net.proc_net); -+} -+ -+/* register the proc file */ -+static void layer7_init_proc(void) -+{ -+	struct proc_dir_entry* entry; -+	entry = create_proc_entry("layer7_numpackets", 0644, init_net.proc_net); -+	entry->read_proc = layer7_read_proc; -+	entry->write_proc = layer7_write_proc; -+} -+ -+static int __init xt_layer7_init(void) -+{ -+	need_conntrack(); -+ -+	layer7_init_proc(); -+	if(maxdatalen < 1) { -+		printk(KERN_WARNING "layer7: maxdatalen can't be < 1, " -+			"using 1\n"); -+		maxdatalen = 1; -+	} -+	/* This is not a hard limit.  It's just here to prevent people from -+	bringing their slow machines to a grinding halt. */ -+	else if(maxdatalen > 65536) { -+		printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, " -+			"using 65536\n"); -+		maxdatalen = 65536; -+	} -+	return xt_register_matches(xt_layer7_match, -+				   ARRAY_SIZE(xt_layer7_match)); -+} -+ -+static void __exit xt_layer7_fini(void) -+{ -+	layer7_cleanup_proc(); -+	xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match)); -+} -+ -+module_init(xt_layer7_init); -+module_exit(xt_layer7_fini); ++#endif /* _XT_LAYER7_H */ diff --git a/target/linux/generic/patches-2.6.37/103-netfilter_layer7_2.6.36_fix.patch b/target/linux/generic/patches-2.6.37/103-netfilter_layer7_2.6.36_fix.patch new file mode 100644 index 000000000..e9aa3c967 --- /dev/null +++ b/target/linux/generic/patches-2.6.37/103-netfilter_layer7_2.6.36_fix.patch @@ -0,0 +1,61 @@ +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -781,6 +781,27 @@ config NETFILTER_XT_MATCH_IPVS +  + 	  If unsure, say N. +  ++config NETFILTER_XT_MATCH_LAYER7 ++	tristate '"layer7" match support' ++	depends on EXPERIMENTAL ++	depends on NETFILTER_XTABLES ++	depends on NETFILTER_ADVANCED ++	depends on NF_CONNTRACK ++	help ++	  Say Y if you want to be able to classify connections (and their ++	  packets) based on regular expression matching of their application ++	  layer data.   This is one way to classify applications such as ++	  peer-to-peer filesharing systems that do not always use the same ++	  port. ++ ++	  To compile it as a module, choose M here.  If unsure, say N. ++ ++config NETFILTER_XT_MATCH_LAYER7_DEBUG ++	bool 'Layer 7 debugging output' ++	depends on NETFILTER_XT_MATCH_LAYER7 ++	help ++	  Say Y to get lots of debugging output. ++ + config NETFILTER_XT_MATCH_LENGTH + 	tristate '"length" match support' + 	depends on NETFILTER_ADVANCED +@@ -966,26 +987,11 @@ config NETFILTER_XT_MATCH_STATE +  + 	  To compile it as a module, choose M here.  If unsure, say N. +  +-config NETFILTER_XT_MATCH_LAYER7 +-	tristate '"layer7" match support' +-	depends on NETFILTER_XTABLES +-	depends on EXPERIMENTAL && (IP_NF_CONNTRACK || NF_CONNTRACK) +-       depends on NETFILTER_ADVANCED +-	help +-	  Say Y if you want to be able to classify connections (and their +-	  packets) based on regular expression matching of their application +-	  layer data.   This is one way to classify applications such as +-	  peer-to-peer filesharing systems that do not always use the same +-	  port. +- +-	  To compile it as a module, choose M here.  If unsure, say N. +- + config NETFILTER_XT_MATCH_LAYER7_DEBUG +-        bool 'Layer 7 debugging output' +-        depends on NETFILTER_XT_MATCH_LAYER7 +-        help +-          Say Y to get lots of debugging output. +- ++	bool 'Layer 7 debugging output' ++	depends on NETFILTER_XT_MATCH_LAYER7 ++	help ++	  Say Y to get lots of debugging output. +  + config NETFILTER_XT_MATCH_STATISTIC + 	tristate '"statistic" match support' | 
