diff options
Diffstat (limited to 'package/linux/kernel-patches')
| -rw-r--r-- | package/linux/kernel-patches/306-netfilter-layer7-0.9.1 | 2022 | 
1 files changed, 2022 insertions, 0 deletions
| diff --git a/package/linux/kernel-patches/306-netfilter-layer7-0.9.1 b/package/linux/kernel-patches/306-netfilter-layer7-0.9.1 new file mode 100644 index 000000000..4dd1fce2b --- /dev/null +++ b/package/linux/kernel-patches/306-netfilter-layer7-0.9.1 @@ -0,0 +1,2022 @@ +diff -Nurp linux-2.4.26-stock/Documentation/Configure.help linux-2.4.26-layer7-clean/Documentation/Configure.help +--- linux-2.4.26-stock/Documentation/Configure.help	2004-04-14 08:05:24.000000000 -0500 ++++ linux-2.4.26-layer7-clean/Documentation/Configure.help	2004-06-21 00:18:14.000000000 -0500 +@@ -28819,6 +28819,23 @@ CONFIG_SOUND_WM97XX +    +   If unsure, say N. +  ++CONFIG_IP_NF_MATCH_LAYER7 ++   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_IP_NF_MATCH_LAYER7_DEBUG ++   Say Y to get lots of debugging output. ++ ++CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN ++   Size of the buffer that the application layer data is stored in. ++   Unless you know what you're doing, leave it at the default of 2048 ++   Bytes. ++ + # + # A couple of things I keep forgetting: + #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, +diff -Nurp linux-2.4.26-stock/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.26-stock/include/linux/netfilter_ipv4/ip_conntrack.h	2004-04-14 08:05:40.000000000 -0500 ++++ linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ip_conntrack.h	2004-06-21 00:18:28.000000000 -0500 +@@ -207,6 +207,17 @@ struct ip_conntrack + 	} nat; + #endif /* CONFIG_IP_NF_NAT_NEEDED */ +  ++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) ++	struct { ++		unsigned int numpackets; /* surely this is kept track of somewhere else, right? I can't find it... */ ++		char * app_proto; /* "http", "ftp", etc.  NULL if unclassifed */ ++		 ++		/* the application layer data so far.  NULL if ->numpackets > numpackets */ ++		char * app_data;  ++ ++		unsigned int app_data_len; ++	} layer7; ++#endif + }; +  + /* get master conntrack via master expectation */ +diff -Nurp linux-2.4.26-stock/include/linux/netfilter_ipv4/ipt_layer7.h linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ipt_layer7.h +--- linux-2.4.26-stock/include/linux/netfilter_ipv4/ipt_layer7.h	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ipt_layer7.h	2004-06-21 00:18:28.000000000 -0500 +@@ -0,0 +1,26 @@ ++/*  ++  By Matthew Strait <quadong@users.sf.net>, Dec 2003. ++  http://l7-filter.sf.net ++ ++  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 ++*/ ++ ++#ifndef _IPT_LAYER7_H ++#define _IPT_LAYER7_H ++ ++#define MAX_PATTERN_LEN 8192 ++#define MAX_PROTOCOL_LEN 256 ++ ++typedef char *(*proc_ipt_search) (char *, char, char *); ++ ++struct ipt_layer7_info { ++    char protocol[MAX_PROTOCOL_LEN]; ++    char invert:1; ++    char pattern[MAX_PATTERN_LEN]; ++}; ++ ++#endif /* _IPT_LAYER7_H */ +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/Config.in linux-2.4.26-layer7-clean/net/ipv4/netfilter/Config.in +--- linux-2.4.26-stock/net/ipv4/netfilter/Config.in	2003-08-25 06:44:44.000000000 -0500 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/Config.in	2004-06-21 00:15:23.000000000 -0500 +@@ -43,6 +43,10 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ];  +   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES +     dep_tristate '  Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES ++    dep_tristate '  Layer 7 match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7 $CONFIG_IP_NF_CONNTRACK ++    dep_mbool '  Layer 7 debugging output (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7_DEBUG $CONFIG_IP_NF_MATCH_LAYER7 ++    int  '  Buffer size for application layer data (256-65536)' CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN 2048 ++  +   fi + # The targets +   dep_tristate '  Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES  +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/Makefile linux-2.4.26-layer7-clean/net/ipv4/netfilter/Makefile +--- linux-2.4.26-stock/net/ipv4/netfilter/Makefile	2003-08-25 06:44:44.000000000 -0500 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/Makefile	2004-06-21 00:15:22.000000000 -0500 +@@ -87,6 +87,8 @@ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += i + obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o + obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +  ++obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o ++ + # targets + obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o + obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_core.c +--- linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_core.c	2004-02-18 07:36:32.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_core.c	2004-06-21 00:15:22.000000000 -0500 +@@ -339,6 +339,15 @@ destroy_conntrack(struct nf_conntrack *n + 		} + 		kfree(ct->master); + 	} ++ ++	#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) ++	/* This ought to get free'd somewhere.  How about here? */ ++	if(ct->layer7.app_proto) /* this is sufficient, right? */ ++		kfree(ct->layer7.app_proto); ++	if(ct->layer7.app_data) ++		kfree(ct->layer7.app_data); ++	#endif ++	 + 	WRITE_UNLOCK(&ip_conntrack_lock); +  + 	if (master) +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_standalone.c +--- linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-02-18 07:36:32.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-06-21 00:15:22.000000000 -0500 +@@ -107,6 +107,13 @@ print_conntrack(char *buffer, struct ip_ + 		len += sprintf(buffer + len, "[ASSURED] "); + 	len += sprintf(buffer + len, "use=%u ", + 		       atomic_read(&conntrack->ct_general.use)); ++ ++	#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) ++	if(conntrack->layer7.app_proto) ++		len += sprintf(buffer + len, "l7proto=%s ", ++				conntrack->layer7.app_proto);  ++	#endif ++ + 	len += sprintf(buffer + len, "\n"); +  + 	return len; +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/ipt_layer7.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ipt_layer7.c +--- linux-2.4.26-stock/net/ipv4/netfilter/ipt_layer7.c	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ipt_layer7.c	2004-06-27 19:06:51.000000000 -0500 +@@ -0,0 +1,540 @@ ++/*  ++  Kernel module to match application layer (OSI layer 7)  ++  data in connections. ++   ++  http://l7-filter.sf.net ++ ++  By Matthew Strait and Ethan Sommer, 2003. ++ ++  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> ++  and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski ++*/ ++ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter_ipv4/ip_conntrack.h> ++#include <linux/proc_fs.h> ++#include <linux/ctype.h> ++#include <net/ip.h> ++#include <net/tcp.h> ++ ++#include "regexp/regexp.c" ++ ++#include <linux/netfilter_ipv4/ipt_layer7.h> ++#include <linux/netfilter_ipv4/ip_tables.h> ++ ++MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("iptables application layer match module"); ++ ++#if defined(CONFIG_IP_NF_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 = 8; ++ ++static struct pattern_cache { ++  char * regex_string; ++  regexp * pattern; ++  struct pattern_cache * next; ++} * first_pattern_cache = NULL; ++ ++/* I'm new to locking.  Here are my assumptions: ++ ++- No one is going to write to /proc/net/layer7_numpackets over and over ++  within a short period of time, and if they did, nothing awful would happen. ++ ++- This code will never be processing the same packet twice at the same time, ++  because iptables rules need to be traversed in order. ++ ++- It doesn't matter if two packets from different connections are in here at  ++  the same time, because they don't share any data. ++ ++- It _does_ matter if two packets from the same connection are here at the same ++  time.  In this case, the things we have to protect are the conntracks and ++  the list of compiled patterns. ++*/ ++DECLARE_RWLOCK(ct_lock); ++DECLARE_LOCK(list_lock); ++ ++/* 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(char * regex_string, 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) { ++		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); ++ ++	if(!tmp->regex_string || !tmp->pattern) { ++		printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); ++		kfree(tmp->regex_string); ++		kfree(tmp->pattern); ++		kfree(tmp); ++		return NULL; ++	} ++ ++        tmp->next = 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); ++	node->pattern = regcomp(regex_string, &len); ++        if ( !node->pattern ) { ++                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; ++} ++ ++#if 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) { ++               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 (char)(i + '0'); ++			break; ++		case 10 ... 15: ++			return (char)(i - 10 + 'a'); ++			break; ++		default: ++			printk("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) { ++               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 ++ ++ ++/* The following functions are here in case we get ported into an environment ++(ebtables?) where skb->nh.iph->protocol isn't set. They assume that skb->data ++points at the beginning of the IP datagram, which is true for iptables (but in ++QoS it points to the beginning of the Ethernet frame). */ ++#if 0 ++#define IP_PROTO_OFFSET 9 ++static int is_tcp_over_ipv4 (const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_TCP );} ++static int is_udp_over_ipv4 (const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_UDP );} ++static int is_icmp_over_ipv4(const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_ICMP);} ++#endif ++ ++static int can_handle(const struct sk_buff *skb) ++{ ++	if(!skb->nh.iph) /* not IP */ ++		return 0; ++	if(skb->nh.iph->protocol != IPPROTO_TCP && ++	   skb->nh.iph->protocol != IPPROTO_UDP && ++	   skb->nh.iph->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 skb->nh.iph  ++	isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ ++        int ip_hl = 4*skb->nh.iph->ihl; ++ ++        if( skb->nh.iph->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( skb->nh.iph->protocol == IPPROTO_UDP  ) { ++                return ip_hl + 8; /* UDP header is always 8 bytes */ ++        } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { ++                return ip_hl + 8; /* ICMP header is 8 bytes */ ++        } else { ++                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 ip_conntrack * conntrack,  ++			struct ip_conntrack * master_conntrack, ++			struct ipt_layer7_info * info) ++{ ++	/* If we're in here, we don't care about the app data anymore */ ++	WRITE_LOCK(&ct_lock); ++	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("\nGave up on the %d length stream: \n%s\n", ++	                       master_conntrack->layer7.app_data_len, f); ++		       	DPRINTK("\nIn hex: %s\n", g); ++                       	kfree(f); ++		       	kfree(g); ++               	} ++               	#endif ++ ++		kfree(master_conntrack->layer7.app_data); ++		master_conntrack->layer7.app_data = NULL; /* don't free again */ ++	} ++	WRITE_UNLOCK(&ct_lock); ++ ++	/* Is top-level master (possibly self) classified? */ ++	if(master_conntrack->layer7.app_proto) {  ++		if(!strcmp(master_conntrack->layer7.app_proto, info->protocol)) ++		{ ++		    	/* set own .protocol (for /proc/net/ip_conntrack) */ ++			WRITE_LOCK(&ct_lock); ++		    	if(!conntrack->layer7.app_proto) { ++		        	conntrack->layer7.app_proto = kmalloc(strlen(info->protocol), GFP_ATOMIC); ++                                if(!conntrack->layer7.app_proto){ ++                                       printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); ++                                       WRITE_UNLOCK(&ct_lock); ++                                       return 1; ++                                } ++ ++		        	strcpy(conntrack->layer7.app_proto, info->protocol); ++		    	} ++			WRITE_UNLOCK(&ct_lock); ++	 ++		    	return 1; ++		} else return 0; ++	} else return 0; /* no clasification */ ++} ++ ++/* add the new app data to the conntrack.  Return number of bytes added. */ ++static int add_data(struct ip_conntrack * master_conntrack,  ++			char * app_data, int appdatalen) ++{ ++	int length = 0, i; ++	int oldlength = master_conntrack->layer7.app_data_len; ++ ++        /* 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 < CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN-oldlength-1 &&  ++		   i < appdatalen; i++) { ++		if(app_data[i] != '\0') { ++			master_conntrack->layer7.app_data[length+oldlength] =  ++				/* the kernel version of tolower mungs 'upper ascii' */ ++				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; ++} ++ ++/* Returns true on match and false otherwise.  */ ++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) ++{ ++	struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; ++        enum ip_conntrack_info master_ctinfo, ctinfo; ++        struct ip_conntrack *master_conntrack, *conntrack; ++	unsigned char * app_data;   ++	unsigned int pattern_result, appdatalen; ++	regexp * comppattern; ++ ++	if(!can_handle(skb)){ ++		DPRINTK("layer7: This is some protocol I can't handle\n"); ++		return info->invert; ++	} ++ ++	LOCK_BH(&list_lock); ++	comppattern = compile_and_cache(info->pattern, info->protocol); ++	UNLOCK_BH(&list_lock); ++	/* the return value gets checked later, when we're ready to use it */ ++ ++	app_data = skb->data + app_data_offset(skb); ++	appdatalen = skb->tail - app_data; ++ ++	/* Treat the parent and all its children together as one connection,  ++	except for the purpose of setting conntrack->layer7.pattern in the  ++	actual connection. This makes /proc/net/ip_conntrack somewhat more  ++	satisfying. */ ++        if(!(conntrack        = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || ++           !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { ++                DPRINTK("layer7: packet is not from a known connection, giving up.\n"); ++		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); ++ ++	/* skb->cb[0] == seen. Avoid doing things twice if there are two layer7  ++	rules. I'm not sure that using cb for this purpose is correct, although  ++	it says "put your private variables there" and this seems to qualify.   ++	But it doesn't look like it's being used for anything else in the  ++	sk_buffs that make it here. I'm open to suggestions for how to be able  ++	to write to cb without making the compiler angry.  That I can't figure  ++	this out is an argument against this being correct. */ ++	if(!skb->cb[0]){ ++		WRITE_LOCK(&ct_lock); ++		master_conntrack->layer7.numpackets++;/*starts at 0 via memset*/ ++		WRITE_UNLOCK(&ct_lock); ++	} ++ ++	/* On the first packet of a connection, allocate space for app data */ ++	WRITE_LOCK(&ct_lock); ++	if(master_conntrack->layer7.numpackets == 1 && !skb->cb[0]) { ++		master_conntrack->layer7.app_data = kmalloc(CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN, GFP_ATOMIC); ++                if(!master_conntrack->layer7.app_data){                                                          ++                        printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); ++                        WRITE_UNLOCK(&ct_lock); ++                        return info->invert; ++                } ++ ++		master_conntrack->layer7.app_data[0] = '\0'; ++	} ++	WRITE_UNLOCK(&ct_lock); ++ ++	/* if we've classified it or seen too many packets */ ++	if(master_conntrack->layer7.numpackets > num_packets ||  ++	   master_conntrack->layer7.app_proto) { ++	 ++		pattern_result = match_no_append(conntrack, master_conntrack, info); ++	 ++		/* mark the packet seen (probably irrelevant, but consistant) */ ++		skb->cb[0] = 1; ++ ++	        return (pattern_result ^ info->invert); ++	} ++	 ++	/* Can end up here, but unallocated, if numpackets is increased during  ++	the beginning of a connection */ ++	if(master_conntrack->layer7.app_data == NULL) ++		return (info->invert); /* unmatched */ ++ ++	if(!skb->cb[0])	{ ++	 	int newbytes; ++		WRITE_LOCK(&ct_lock); ++		newbytes = add_data(master_conntrack, app_data, appdatalen); ++		WRITE_UNLOCK(&ct_lock); ++ ++		if(newbytes == 0) { /* didn't add any data */ ++			skb->cb[0] = 1; ++			/* Didn't match before, not going to match now */ ++			return info->invert; ++		} ++	} ++ ++	/* If the regexp failed to compile, don't bother running it */ ++	if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { ++		DPRINTK("layer7: regexec positive: %s!\n", info->protocol); ++		pattern_result = 1; ++	} else pattern_result = 0; ++ ++	if(pattern_result) { ++		WRITE_LOCK(&ct_lock); ++		conntrack->layer7.app_proto = kmalloc(strlen(info->protocol), GFP_ATOMIC); ++                if(!conntrack->layer7.app_proto){ ++                        printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); ++                        WRITE_UNLOCK(&ct_lock); ++                        return (pattern_result ^ info->invert); ++                        } ++  ++		strcpy(conntrack->layer7.app_proto, info->protocol); ++		WRITE_UNLOCK(&ct_lock); ++	} ++ ++	/* mark the packet seen */ ++	skb->cb[0] = 1; ++ ++    	return (pattern_result ^ info->invert); ++} ++ ++static int checkentry(const char *tablename, const struct ipt_ip *ip, ++           void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++       if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info)))  ++               return 0; ++       return 1; ++} ++ ++static struct ipt_match layer7_match = {  ++	.name = "layer7",  ++	.match = &match,  ++	.checkentry = &checkentry,  ++	.me = THIS_MODULE  ++}; ++ ++/* 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) ++                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){ ++                printk(KERN_ERR "layer7: out of memory, bailing.  num_packets unchanged.\n"); ++                return count; ++        } ++ ++        /* copy in the data from userland */ ++        copy_from_user(foo, buffer, count); ++ ++        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; ++} ++ ++/* register the proc file */ ++static void layer7_init_proc(void) ++{ ++        struct proc_dir_entry* entry; ++ ++        /* create the file */ ++        entry = create_proc_entry("layer7_numpackets", 0644, proc_net); ++ ++        /* set the callback functions */ ++	entry->read_proc = layer7_read_proc; ++	entry->write_proc = layer7_write_proc; ++} ++ ++static void layer7_cleanup_proc(void) ++{ ++        remove_proc_entry("layer7_numpackets", proc_net); ++} ++ ++static int __init init(void) ++{ ++        layer7_init_proc(); ++	return ipt_register_match(&layer7_match); ++} ++ ++static void __exit fini(void) ++{ ++	layer7_cleanup_proc(); ++	ipt_unregister_match(&layer7_match); ++} ++ ++module_init(init); ++module_exit(fini); +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.c +--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.c	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.c	2004-06-27 19:07:00.000000000 -0500 +@@ -0,0 +1,1195 @@ ++/* ++ * regcomp and regexec -- regsub and regerror are elsewhere ++ * @(#)regexp.c	1.3 of 18 April 87 ++ * ++ *	Copyright (c) 1986 by University of Toronto. ++ *	Written by Henry Spencer.  Not derived from licensed software. ++ * ++ *	Permission is granted to anyone to use this software for any ++ *	purpose on any computer system, and to redistribute it freely, ++ *	subject to the following restrictions: ++ * ++ *	1. The author is not responsible for the consequences of use of ++ *		this software, no matter how awful, even if they arise ++ *		from defects in it. ++ * ++ *	2. The origin of this software must not be misrepresented, either ++ *		by explicit claim or by omission. ++ * ++ *	3. Altered versions must be plainly marked as such, and must not ++ *		be misrepresented as being the original software. ++ * ++ * Beware that some of this code is subtly aware of the way operator ++ * precedence is structured in regular expressions.  Serious changes in ++ * regular-expression syntax might require a total rethink. ++ * ++ * This code was modified by Ethan Sommer to work within the kernel ++ * (it now uses kmalloc etc..) ++ *  ++ * Modified slightly by Matthew Strait to use more modern C. ++ */ ++ ++#include "regexp.h" ++#include "regmagic.h" ++ ++/* added by ethan and matt.  Lets it work in both kernel and user space. ++(So iptables can use it, for instance.)  Yea, it goes both ways... */ ++#if __KERNEL__ ++  #define malloc(foo) kmalloc(foo,GFP_ATOMIC) ++#else ++  #define printk(format,args...) printf(format,##args) ++#endif ++ ++void regerror(char * s) ++{ ++        printk("<3>Regexp: %s\n", s); ++        /* NOTREACHED */ ++} ++ ++/* ++ * The "internal use only" fields in regexp.h are present to pass info from ++ * compile to execute that permits the execute phase to run lots faster on ++ * simple cases.  They are: ++ * ++ * regstart	char that must begin a match; '\0' if none obvious ++ * reganch	is the match anchored (at beginning-of-line only)? ++ * regmust	string (pointer into program) that match must include, or NULL ++ * regmlen	length of regmust string ++ * ++ * Regstart and reganch permit very fast decisions on suitable starting points ++ * for a match, cutting down the work a lot.  Regmust permits fast rejection ++ * of lines that cannot possibly match.  The regmust tests are costly enough ++ * that regcomp() supplies a regmust only if the r.e. contains something ++ * potentially expensive (at present, the only such thing detected is * or + ++ * at the start of the r.e., which can involve a lot of backup).  Regmlen is ++ * supplied because the test in regexec() needs it and regcomp() is computing ++ * it anyway. ++ */ ++ ++/* ++ * Structure for regexp "program".  This is essentially a linear encoding ++ * of a nondeterministic finite-state machine (aka syntax charts or ++ * "railroad normal form" in parsing technology).  Each node is an opcode ++ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of ++ * all nodes except BRANCH implement concatenation; a "next" pointer with ++ * a BRANCH on both ends of it is connecting two alternatives.  (Here we ++ * have one of the subtle syntax dependencies:  an individual BRANCH (as ++ * opposed to a collection of them) is never concatenated with anything ++ * because of operator precedence.)  The operand of some types of node is ++ * a literal string; for others, it is a node leading into a sub-FSM.  In ++ * particular, the operand of a BRANCH node is the first node of the branch. ++ * (NB this is *not* a tree structure:  the tail of the branch connects ++ * to the thing following the set of BRANCHes.)  The opcodes are: ++ */ ++ ++/* definition	number	opnd?	meaning */ ++#define	END	0	/* no	End of program. */ ++#define	BOL	1	/* no	Match "" at beginning of line. */ ++#define	EOL	2	/* no	Match "" at end of line. */ ++#define	ANY	3	/* no	Match any one character. */ ++#define	ANYOF	4	/* str	Match any character in this string. */ ++#define	ANYBUT	5	/* str	Match any character not in this string. */ ++#define	BRANCH	6	/* node	Match this alternative, or the next... */ ++#define	BACK	7	/* no	Match "", "next" ptr points backward. */ ++#define	EXACTLY	8	/* str	Match this string. */ ++#define	NOTHING	9	/* no	Match empty string. */ ++#define	STAR	10	/* node	Match this (simple) thing 0 or more times. */ ++#define	PLUS	11	/* node	Match this (simple) thing 1 or more times. */ ++#define	OPEN	20	/* no	Mark this point in input as start of #n. */ ++			/*	OPEN+1 is number 1, etc. */ ++#define	CLOSE	30	/* no	Analogous to OPEN. */ ++ ++/* ++ * Opcode notes: ++ * ++ * BRANCH	The set of branches constituting a single choice are hooked ++ *		together with their "next" pointers, since precedence prevents ++ *		anything being concatenated to any individual branch.  The ++ *		"next" pointer of the last BRANCH in a choice points to the ++ *		thing following the whole choice.  This is also where the ++ *		final "next" pointer of each individual branch points; each ++ *		branch starts with the operand node of a BRANCH node. ++ * ++ * BACK		Normal "next" pointers all implicitly point forward; BACK ++ *		exists to make loop structures possible. ++ * ++ * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular ++ *		BRANCH structures using BACK.  Simple cases (one character ++ *		per match) are implemented with STAR and PLUS for speed ++ *		and to minimize recursive plunges. ++ * ++ * OPEN,CLOSE	...are numbered at compile time. ++ */ ++ ++/* ++ * A node is one char of opcode followed by two chars of "next" pointer. ++ * "Next" pointers are stored as two 8-bit pieces, high order first.  The ++ * value is a positive offset from the opcode of the node containing it. ++ * An operand, if any, simply follows the node.  (Note that much of the ++ * code generation knows about this implicit relationship.) ++ * ++ * Using two bytes for the "next" pointer is vast overkill for most things, ++ * but allows patterns to get big without disasters. ++ */ ++#define	OP(p)	(*(p)) ++#define	NEXT(p)	(((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) ++#define	OPERAND(p)	((p) + 3) ++ ++/* ++ * See regmagic.h for one further detail of program structure. ++ */ ++ ++ ++/* ++ * Utility definitions. ++ */ ++#ifndef CHARBITS ++#define	UCHARAT(p)	((int)*(unsigned char *)(p)) ++#else ++#define	UCHARAT(p)	((int)*(p)&CHARBITS) ++#endif ++ ++#define	FAIL(m)	{ regerror(m); return(NULL); } ++#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?') ++#define	META	"^$.[()|?+*\\" ++ ++/* ++ * Flags to be passed up and down. ++ */ ++#define	HASWIDTH	01	/* Known never to match null string. */ ++#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */ ++#define	SPSTART		04	/* Starts with * or +. */ ++#define	WORST		0	/* Worst case. */ ++ ++/* ++ * Global work variables for regcomp(). ++ */ ++static char *regparse;		/* Input-scan pointer. */ ++static int regnpar;		/* () count. */ ++static char regdummy; ++static char *regcode;		/* Code-emit pointer; ®dummy = don't. */ ++static long regsize;		/* Code size. */ ++ ++/* ++ * Forward declarations for regcomp()'s friends. ++ */ ++#ifndef STATIC ++#define	STATIC	static ++#endif ++STATIC char *reg(int paren,int *flagp); ++STATIC char *regbranch(int *flagp); ++STATIC char *regpiece(int *flagp); ++STATIC char *regatom(int *flagp); ++STATIC char *regnode(char op); ++STATIC char *regnext(char *p); ++STATIC void regc(char b); ++STATIC void reginsert(char op, char *opnd); ++STATIC void regtail(char *p, char *val); ++STATIC void regoptail(char *p, char *val); ++ ++ ++__kernel_size_t my_strcspn(const char *s1,const char *s2) ++{ ++        char *scan1; ++        char *scan2; ++        int count; ++ ++        count = 0; ++        for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { ++                for (scan2 = (char *)s2; *scan2 != '\0';)       /* ++ moved down. */ ++                        if (*scan1 == *scan2++) ++                                return(count); ++                count++; ++        } ++        return(count); ++} ++ ++/* ++ - regcomp - compile a regular expression into internal code ++ * ++ * We can't allocate space until we know how big the compiled form will be, ++ * but we can't compile it (and thus know how big it is) until we've got a ++ * place to put the code.  So we cheat:  we compile it twice, once with code ++ * generation turned off and size counting turned on, and once "for real". ++ * This also means that we don't allocate space until we are sure that the ++ * thing really will compile successfully, and we never have to move the ++ * code and thus invalidate pointers into it.  (Note that it has to be in ++ * one piece because free() must be able to free it all.) ++ * ++ * Beware that the optimization-preparation code in here knows about some ++ * of the structure of the compiled regexp. ++ */ ++regexp * ++regcomp(char *exp,int *patternsize) ++{ ++	register regexp *r; ++	register char *scan; ++	register char *longest; ++	register int len; ++	int flags; ++	/* commented out by ethan ++	   extern char *malloc(); ++	*/ ++ ++	if (exp == NULL) ++		FAIL("NULL argument"); ++ ++	/* First pass: determine size, legality. */ ++	regparse = exp; ++	regnpar = 1; ++	regsize = 0L; ++	regcode = ®dummy; ++	regc(MAGIC); ++	if (reg(0, &flags) == NULL) ++		return(NULL); ++ ++	/* Small enough for pointer-storage convention? */ ++	if (regsize >= 32767L)		/* Probably could be 65535L. */ ++		FAIL("regexp too big"); ++ ++	/* Allocate space. */ ++	*patternsize=sizeof(regexp) + (unsigned)regsize; ++	r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); ++	if (r == NULL) ++		FAIL("out of space"); ++ ++	/* Second pass: emit code. */ ++	regparse = exp; ++	regnpar = 1; ++	regcode = r->program; ++	regc(MAGIC); ++	if (reg(0, &flags) == NULL) ++		return(NULL); ++ ++	/* Dig out information for optimizations. */ ++	r->regstart = '\0';	/* Worst-case defaults. */ ++	r->reganch = 0; ++	r->regmust = NULL; ++	r->regmlen = 0; ++	scan = r->program+1;			/* First BRANCH. */ ++	if (OP(regnext(scan)) == END) {		/* Only one top-level choice. */ ++		scan = OPERAND(scan); ++ ++		/* Starting-point info. */ ++		if (OP(scan) == EXACTLY) ++			r->regstart = *OPERAND(scan); ++		else if (OP(scan) == BOL) ++			r->reganch++; ++ ++		/* ++		 * If there's something expensive in the r.e., find the ++		 * longest literal string that must appear and make it the ++		 * regmust.  Resolve ties in favor of later strings, since ++		 * the regstart check works with the beginning of the r.e. ++		 * and avoiding duplication strengthens checking.  Not a ++		 * strong reason, but sufficient in the absence of others. ++		 */ ++		if (flags&SPSTART) { ++			longest = NULL; ++			len = 0; ++			for (; scan != NULL; scan = regnext(scan)) ++				if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { ++					longest = OPERAND(scan); ++					len = strlen(OPERAND(scan)); ++				} ++			r->regmust = longest; ++			r->regmlen = len; ++		} ++	} ++ ++	return(r); ++} ++ ++/* ++ - reg - regular expression, i.e. main body or parenthesized thing ++ * ++ * Caller must absorb opening parenthesis. ++ * ++ * Combining parenthesis handling with the base level of regular expression ++ * is a trifle forced, but the need to tie the tails of the branches to what ++ * follows makes it hard to avoid. ++ */ ++static char * ++reg(int paren, int *flagp /* Parenthesized? */ ) ++{ ++	register char *ret; ++	register char *br; ++	register char *ender; ++	register int parno = 0; /* 0 makes gcc happy */ ++	int flags; ++ ++	*flagp = HASWIDTH;	/* Tentatively. */ ++ ++	/* Make an OPEN node, if parenthesized. */ ++	if (paren) { ++		if (regnpar >= NSUBEXP) ++			FAIL("too many ()"); ++		parno = regnpar; ++		regnpar++; ++		ret = regnode(OPEN+parno); ++	} else ++		ret = NULL; ++ ++	/* Pick up the branches, linking them together. */ ++	br = regbranch(&flags); ++	if (br == NULL) ++		return(NULL); ++	if (ret != NULL) ++		regtail(ret, br);	/* OPEN -> first. */ ++	else ++		ret = br; ++	if (!(flags&HASWIDTH)) ++		*flagp &= ~HASWIDTH; ++	*flagp |= flags&SPSTART; ++	while (*regparse == '|') { ++		regparse++; ++		br = regbranch(&flags); ++		if (br == NULL) ++			return(NULL); ++		regtail(ret, br);	/* BRANCH -> BRANCH. */ ++		if (!(flags&HASWIDTH)) ++			*flagp &= ~HASWIDTH; ++		*flagp |= flags&SPSTART; ++	} ++ ++	/* Make a closing node, and hook it on the end. */ ++	ender = regnode((paren) ? CLOSE+parno : END);	 ++	regtail(ret, ender); ++ ++	/* Hook the tails of the branches to the closing node. */ ++	for (br = ret; br != NULL; br = regnext(br)) ++		regoptail(br, ender); ++ ++	/* Check for proper termination. */ ++	if (paren && *regparse++ != ')') { ++		FAIL("unmatched ()"); ++	} else if (!paren && *regparse != '\0') { ++		if (*regparse == ')') { ++			FAIL("unmatched ()"); ++		} else ++			FAIL("junk on end");	/* "Can't happen". */ ++		/* NOTREACHED */ ++	} ++ ++	return(ret); ++} ++ ++/* ++ - regbranch - one alternative of an | operator ++ * ++ * Implements the concatenation operator. ++ */ ++static char * ++regbranch(int *flagp) ++{ ++	register char *ret; ++	register char *chain; ++	register char *latest; ++	int flags; ++ ++	*flagp = WORST;		/* Tentatively. */ ++ ++	ret = regnode(BRANCH); ++	chain = NULL; ++	while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { ++		latest = regpiece(&flags); ++		if (latest == NULL) ++			return(NULL); ++		*flagp |= flags&HASWIDTH; ++		if (chain == NULL)	/* First piece. */ ++			*flagp |= flags&SPSTART; ++		else ++			regtail(chain, latest); ++		chain = latest; ++	} ++	if (chain == NULL)	/* Loop ran zero times. */ ++		(void) regnode(NOTHING); ++ ++	return(ret); ++} ++ ++/* ++ - regpiece - something followed by possible [*+?] ++ * ++ * Note that the branching code sequences used for ? and the general cases ++ * of * and + are somewhat optimized:  they use the same NOTHING node as ++ * both the endmarker for their branch list and the body of the last branch. ++ * It might seem that this node could be dispensed with entirely, but the ++ * endmarker role is not redundant. ++ */ ++static char * ++regpiece(int *flagp) ++{ ++	register char *ret; ++	register char op; ++	register char *next; ++	int flags; ++ ++	ret = regatom(&flags); ++	if (ret == NULL) ++		return(NULL); ++ ++	op = *regparse; ++	if (!ISMULT(op)) { ++		*flagp = flags; ++		return(ret); ++	} ++ ++	if (!(flags&HASWIDTH) && op != '?') ++		FAIL("*+ operand could be empty"); ++	*flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); ++ ++	if (op == '*' && (flags&SIMPLE)) ++		reginsert(STAR, ret); ++	else if (op == '*') { ++		/* Emit x* as (x&|), where & means "self". */ ++		reginsert(BRANCH, ret);			/* Either x */ ++		regoptail(ret, regnode(BACK));		/* and loop */ ++		regoptail(ret, ret);			/* back */ ++		regtail(ret, regnode(BRANCH));		/* or */ ++		regtail(ret, regnode(NOTHING));		/* null. */ ++	} else if (op == '+' && (flags&SIMPLE)) ++		reginsert(PLUS, ret); ++	else if (op == '+') { ++		/* Emit x+ as x(&|), where & means "self". */ ++		next = regnode(BRANCH);			/* Either */ ++		regtail(ret, next); ++		regtail(regnode(BACK), ret);		/* loop back */ ++		regtail(next, regnode(BRANCH));		/* or */ ++		regtail(ret, regnode(NOTHING));		/* null. */ ++	} else if (op == '?') { ++		/* Emit x? as (x|) */ ++		reginsert(BRANCH, ret);			/* Either x */ ++		regtail(ret, regnode(BRANCH));		/* or */ ++		next = regnode(NOTHING);		/* null. */ ++		regtail(ret, next); ++		regoptail(ret, next); ++	} ++	regparse++; ++	if (ISMULT(*regparse)) ++		FAIL("nested *?+"); ++ ++	return(ret); ++} ++ ++/* ++ - regatom - the lowest level ++ * ++ * Optimization:  gobbles an entire sequence of ordinary characters so that ++ * it can turn them into a single node, which is smaller to store and ++ * faster to run.  Backslashed characters are exceptions, each becoming a ++ * separate node; the code is simpler that way and it's not worth fixing. ++ */ ++static char * ++regatom(int *flagp) ++{ ++	register char *ret; ++	int flags; ++ ++	*flagp = WORST;		/* Tentatively. */ ++ ++	switch (*regparse++) { ++	case '^': ++		ret = regnode(BOL); ++		break; ++	case '$': ++		ret = regnode(EOL); ++		break; ++	case '.': ++		ret = regnode(ANY); ++		*flagp |= HASWIDTH|SIMPLE; ++		break; ++	case '[': { ++			register int class; ++			register int classend; ++ ++			if (*regparse == '^') {	/* Complement of range. */ ++				ret = regnode(ANYBUT); ++				regparse++; ++			} else ++				ret = regnode(ANYOF); ++			if (*regparse == ']' || *regparse == '-') ++				regc(*regparse++); ++			while (*regparse != '\0' && *regparse != ']') { ++				if (*regparse == '-') { ++					regparse++; ++					if (*regparse == ']' || *regparse == '\0') ++						regc('-'); ++					else { ++						class = UCHARAT(regparse-2)+1; ++						classend = UCHARAT(regparse); ++						if (class > classend+1) ++							FAIL("invalid [] range"); ++						for (; class <= classend; class++) ++							regc(class); ++						regparse++; ++					} ++				} else ++					regc(*regparse++); ++			} ++			regc('\0'); ++			if (*regparse != ']') ++				FAIL("unmatched []"); ++			regparse++; ++			*flagp |= HASWIDTH|SIMPLE; ++		} ++		break; ++	case '(': ++		ret = reg(1, &flags); ++		if (ret == NULL) ++			return(NULL); ++		*flagp |= flags&(HASWIDTH|SPSTART); ++		break; ++	case '\0': ++	case '|': ++	case ')': ++		FAIL("internal urp");	/* Supposed to be caught earlier. */ ++		break; ++	case '?': ++	case '+': ++	case '*': ++		FAIL("?+* follows nothing"); ++		break; ++	case '\\': ++		if (*regparse == '\0') ++			FAIL("trailing \\"); ++		ret = regnode(EXACTLY); ++		regc(*regparse++); ++		regc('\0'); ++		*flagp |= HASWIDTH|SIMPLE; ++		break; ++	default: { ++			register int len; ++			register char ender; ++ ++			regparse--; ++			len = my_strcspn((const char *)regparse, (const char *)META); ++			if (len <= 0) ++				FAIL("internal disaster"); ++			ender = *(regparse+len); ++			if (len > 1 && ISMULT(ender)) ++				len--;		/* Back off clear of ?+* operand. */ ++			*flagp |= HASWIDTH; ++			if (len == 1) ++				*flagp |= SIMPLE; ++			ret = regnode(EXACTLY); ++			while (len > 0) { ++				regc(*regparse++); ++				len--; ++			} ++			regc('\0'); ++		} ++		break; ++	} ++ ++	return(ret); ++} ++ ++/* ++ - regnode - emit a node ++ */ ++static char *			/* Location. */ ++regnode(char op) ++{ ++	register char *ret; ++	register char *ptr; ++ ++	ret = regcode; ++	if (ret == ®dummy) { ++		regsize += 3; ++		return(ret); ++	} ++ ++	ptr = ret; ++	*ptr++ = op; ++	*ptr++ = '\0';		/* Null "next" pointer. */ ++	*ptr++ = '\0'; ++	regcode = ptr; ++ ++	return(ret); ++} ++ ++/* ++ - regc - emit (if appropriate) a byte of code ++ */ ++static void ++regc(char b) ++{ ++	if (regcode != ®dummy) ++		*regcode++ = b; ++	else ++		regsize++; ++} ++ ++/* ++ - reginsert - insert an operator in front of already-emitted operand ++ * ++ * Means relocating the operand. ++ */ ++static void ++reginsert(char op, char* opnd) ++{ ++	register char *src; ++	register char *dst; ++	register char *place; ++ ++	if (regcode == ®dummy) { ++		regsize += 3; ++		return; ++	} ++ ++	src = regcode; ++	regcode += 3; ++	dst = regcode; ++	while (src > opnd) ++		*--dst = *--src; ++ ++	place = opnd;		/* Op node, where operand used to be. */ ++	*place++ = op; ++	*place++ = '\0'; ++	*place++ = '\0'; ++} ++ ++/* ++ - regtail - set the next-pointer at the end of a node chain ++ */ ++static void ++regtail(char *p, char *val) ++{ ++	register char *scan; ++	register char *temp; ++	register int offset; ++ ++	if (p == ®dummy) ++		return; ++ ++	/* Find last node. */ ++	scan = p; ++	for (;;) { ++		temp = regnext(scan); ++		if (temp == NULL) ++			break; ++		scan = temp; ++	} ++ ++	if (OP(scan) == BACK) ++		offset = scan - val; ++	else ++		offset = val - scan; ++	*(scan+1) = (offset>>8)&0377; ++	*(scan+2) = offset&0377; ++} ++ ++/* ++ - regoptail - regtail on operand of first argument; nop if operandless ++ */ ++static void ++regoptail(char *p, char *val) ++{ ++	/* "Operandless" and "op != BRANCH" are synonymous in practice. */ ++	if (p == NULL || p == ®dummy || OP(p) != BRANCH) ++		return; ++	regtail(OPERAND(p), val); ++} ++ ++/* ++ * regexec and friends ++ */ ++ ++/* ++ * Global work variables for regexec(). ++ */ ++static char *reginput;		/* String-input pointer. */ ++static char *regbol;		/* Beginning of input, for ^ check. */ ++static char **regstartp;	/* Pointer to startp array. */ ++static char **regendp;		/* Ditto for endp. */ ++ ++/* ++ * Forwards. ++ */ ++STATIC int regtry(regexp *prog, char *string); ++STATIC int regmatch(char *prog); ++STATIC int regrepeat(char *p); ++ ++#ifdef DEBUG ++int regnarrate = 0; ++void regdump(); ++STATIC char *regprop(char *op); ++#endif ++ ++/* ++ - regexec - match a regexp against a string ++ */ ++int ++regexec(regexp *prog, char *string) ++{ ++	register char *s; ++ ++	/* Be paranoid... */ ++	if (prog == NULL || string == NULL) { ++		printk("<3>Regexp: NULL parameter\n"); ++		return(0); ++	} ++ ++	/* Check validity of program. */ ++	if (UCHARAT(prog->program) != MAGIC) { ++		printk("<3>Regexp: corrupted program\n"); ++		return(0); ++	} ++ ++	/* If there is a "must appear" string, look for it. */ ++	if (prog->regmust != NULL) { ++		s = string; ++		while ((s = strchr(s, prog->regmust[0])) != NULL) { ++			if (strncmp(s, prog->regmust, prog->regmlen) == 0) ++				break;	/* Found it. */ ++			s++; ++		} ++		if (s == NULL)	/* Not present. */ ++			return(0); ++	} ++ ++	/* Mark beginning of line for ^ . */ ++	regbol = string; ++ ++	/* Simplest case:  anchored match need be tried only once. */ ++	if (prog->reganch) ++		return(regtry(prog, string)); ++ ++	/* Messy cases:  unanchored match. */ ++	s = string; ++	if (prog->regstart != '\0') ++		/* We know what char it must start with. */ ++		while ((s = strchr(s, prog->regstart)) != NULL) { ++			if (regtry(prog, s)) ++				return(1); ++			s++; ++		} ++	else ++		/* We don't -- general case. */ ++		do { ++			if (regtry(prog, s)) ++				return(1); ++		} while (*s++ != '\0'); ++ ++	/* Failure. */ ++	return(0); ++} ++ ++/* ++ - regtry - try match at specific point ++ */ ++static int			/* 0 failure, 1 success */ ++regtry(regexp *prog, char *string) ++{ ++	register int i; ++	register char **sp; ++	register char **ep; ++ ++	reginput = string; ++	regstartp = prog->startp; ++	regendp = prog->endp; ++ ++	sp = prog->startp; ++	ep = prog->endp; ++	for (i = NSUBEXP; i > 0; i--) { ++		*sp++ = NULL; ++		*ep++ = NULL; ++	} ++	if (regmatch(prog->program + 1)) { ++		prog->startp[0] = string; ++		prog->endp[0] = reginput; ++		return(1); ++	} else ++		return(0); ++} ++ ++/* ++ - regmatch - main matching routine ++ * ++ * Conceptually the strategy is simple:  check to see whether the current ++ * node matches, call self recursively to see whether the rest matches, ++ * and then act accordingly.  In practice we make some effort to avoid ++ * recursion, in particular by going through "ordinary" nodes (that don't ++ * need to know whether the rest of the match failed) by a loop instead of ++ * by recursion. ++ */ ++static int			/* 0 failure, 1 success */ ++regmatch(char *prog) ++{ ++	register char *scan = prog; /* Current node. */ ++	char *next;		    /* Next node. */ ++ ++#ifdef DEBUG ++	if (scan != NULL && regnarrate) ++		fprintf(stderr, "%s(\n", regprop(scan)); ++#endif ++	while (scan != NULL) { ++#ifdef DEBUG ++		if (regnarrate) ++			fprintf(stderr, "%s...\n", regprop(scan)); ++#endif ++		next = regnext(scan); ++ ++		switch (OP(scan)) { ++		case BOL: ++			if (reginput != regbol) ++				return(0); ++			break; ++		case EOL: ++			if (*reginput != '\0') ++				return(0); ++			break; ++		case ANY: ++			if (*reginput == '\0') ++				return(0); ++			reginput++; ++			break; ++		case EXACTLY: { ++				register int len; ++				register char *opnd; ++ ++				opnd = OPERAND(scan); ++				/* Inline the first character, for speed. */ ++				if (*opnd != *reginput) ++					return(0); ++				len = strlen(opnd); ++				if (len > 1 && strncmp(opnd, reginput, len) != 0) ++					return(0); ++				reginput += len; ++			} ++			break; ++		case ANYOF: ++			if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) ++				return(0); ++			reginput++; ++			break; ++		case ANYBUT: ++			if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) ++				return(0); ++			reginput++; ++			break; ++		case NOTHING: ++		case BACK: ++			break; ++		case OPEN+1: ++		case OPEN+2: ++		case OPEN+3: ++		case OPEN+4: ++		case OPEN+5: ++		case OPEN+6: ++		case OPEN+7: ++		case OPEN+8: ++		case OPEN+9: { ++				register int no; ++				register char *save; ++ ++				no = OP(scan) - OPEN; ++				save = reginput; ++ ++				if (regmatch(next)) { ++					/* ++					 * Don't set startp if some later ++					 * invocation of the same parentheses ++					 * already has. ++					 */ ++					if (regstartp[no] == NULL) ++						regstartp[no] = save; ++					return(1); ++				} else ++					return(0); ++			} ++			break; ++		case CLOSE+1: ++		case CLOSE+2: ++		case CLOSE+3: ++		case CLOSE+4: ++		case CLOSE+5: ++		case CLOSE+6: ++		case CLOSE+7: ++		case CLOSE+8: ++		case CLOSE+9: ++			{ ++				register int no; ++				register char *save; ++ ++				no = OP(scan) - CLOSE; ++				save = reginput; ++ ++				if (regmatch(next)) { ++					/* ++					 * Don't set endp if some later ++					 * invocation of the same parentheses ++					 * already has. ++					 */ ++					if (regendp[no] == NULL) ++						regendp[no] = save; ++					return(1); ++				} else ++					return(0); ++			} ++			break; ++		case BRANCH: { ++				register char *save; ++ ++				if (OP(next) != BRANCH)		/* No choice. */ ++					next = OPERAND(scan);	/* Avoid recursion. */ ++				else { ++					do { ++						save = reginput; ++						if (regmatch(OPERAND(scan))) ++							return(1); ++						reginput = save; ++						scan = regnext(scan); ++					} while (scan != NULL && OP(scan) == BRANCH); ++					return(0); ++					/* NOTREACHED */ ++				} ++			} ++			break; ++		case STAR: ++		case PLUS: { ++				register char nextch; ++				register int no; ++				register char *save; ++				register int min; ++ ++				/* ++				 * Lookahead to avoid useless match attempts ++				 * when we know what character comes next. ++				 */ ++				nextch = '\0'; ++				if (OP(next) == EXACTLY) ++					nextch = *OPERAND(next); ++				min = (OP(scan) == STAR) ? 0 : 1; ++				save = reginput; ++				no = regrepeat(OPERAND(scan)); ++				while (no >= min) { ++					/* If it could work, try it. */ ++					if (nextch == '\0' || *reginput == nextch) ++						if (regmatch(next)) ++							return(1); ++					/* Couldn't or didn't -- back up. */ ++					no--; ++					reginput = save + no; ++				} ++				return(0); ++			} ++			break; ++		case END: ++			return(1);	/* Success! */ ++			break; ++		default: ++			printk("<3>Regexp: memory corruption\n"); ++			return(0); ++			break; ++		} ++ ++		scan = next; ++	} ++ ++	/* ++	 * We get here only if there's trouble -- normally "case END" is ++	 * the terminating point. ++	 */ ++	printk("<3>Regexp: corrupted pointers\n"); ++	return(0); ++} ++ ++/* ++ - regrepeat - repeatedly match something simple, report how many ++ */ ++static int ++regrepeat(char *p) ++{ ++	register int count = 0; ++	register char *scan; ++	register char *opnd; ++ ++	scan = reginput; ++	opnd = OPERAND(p); ++	switch (OP(p)) { ++	case ANY: ++		count = strlen(scan); ++		scan += count; ++		break; ++	case EXACTLY: ++		while (*opnd == *scan) { ++			count++; ++			scan++; ++		} ++		break; ++	case ANYOF: ++		while (*scan != '\0' && strchr(opnd, *scan) != NULL) { ++			count++; ++			scan++; ++		} ++		break; ++	case ANYBUT: ++		while (*scan != '\0' && strchr(opnd, *scan) == NULL) { ++			count++; ++			scan++; ++		} ++		break; ++	default:		/* Oh dear.  Called inappropriately. */ ++		printk("<3>Regexp: internal foulup\n"); ++		count = 0;	/* Best compromise. */ ++		break; ++	} ++	reginput = scan; ++ ++	return(count); ++} ++ ++/* ++ - regnext - dig the "next" pointer out of a node ++ */ ++static char*  ++regnext(char *p) ++{ ++	register int offset; ++ ++	if (p == ®dummy) ++		return(NULL); ++ ++	offset = NEXT(p); ++	if (offset == 0) ++		return(NULL); ++ ++	if (OP(p) == BACK) ++		return(p-offset); ++	else ++		return(p+offset); ++} ++ ++#ifdef DEBUG ++ ++STATIC char *regprop(); ++ ++/* ++ - regdump - dump a regexp onto stdout in vaguely comprehensible form ++ */ ++void ++regdump(regexp *r) ++{ ++	register char *s; ++	register char op = EXACTLY;	/* Arbitrary non-END op. */ ++	register char *next; ++	/* extern char *strchr(); */ ++ ++ ++	s = r->program + 1; ++	while (op != END) {	/* While that wasn't END last time... */ ++		op = OP(s); ++		printf("%2d%s", s-r->program, regprop(s));	/* Where, what. */ ++		next = regnext(s); ++		if (next == NULL)		/* Next ptr. */ ++			printf("(0)"); ++		else  ++			printf("(%d)", (s-r->program)+(next-s)); ++		s += 3; ++		if (op == ANYOF || op == ANYBUT || op == EXACTLY) { ++			/* Literal string, where present. */ ++			while (*s != '\0') { ++				putchar(*s); ++				s++; ++			} ++			s++; ++		} ++		putchar('\n'); ++	} ++ ++	/* Header fields of interest. */ ++	if (r->regstart != '\0') ++		printf("start `%c' ", r->regstart); ++	if (r->reganch) ++		printf("anchored "); ++	if (r->regmust != NULL) ++		printf("must have \"%s\"", r->regmust); ++	printf("\n"); ++} ++ ++/* ++ - regprop - printable representation of opcode ++ */ ++static char * ++regprop(char *op) ++{ ++#define BUFLEN 50 ++	register char *p; ++	static char buf[BUFLEN]; ++ ++	strcpy(buf, ":"); ++ ++	switch (OP(op)) { ++	case BOL: ++		p = "BOL"; ++		break; ++	case EOL: ++		p = "EOL"; ++		break; ++	case ANY: ++		p = "ANY"; ++		break; ++	case ANYOF: ++		p = "ANYOF"; ++		break; ++	case ANYBUT: ++		p = "ANYBUT"; ++		break; ++	case BRANCH: ++		p = "BRANCH"; ++		break; ++	case EXACTLY: ++		p = "EXACTLY"; ++		break; ++	case NOTHING: ++		p = "NOTHING"; ++		break; ++	case BACK: ++		p = "BACK"; ++		break; ++	case END: ++		p = "END"; ++		break; ++	case OPEN+1: ++	case OPEN+2: ++	case OPEN+3: ++	case OPEN+4: ++	case OPEN+5: ++	case OPEN+6: ++	case OPEN+7: ++	case OPEN+8: ++	case OPEN+9: ++		snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); ++		p = NULL; ++		break; ++	case CLOSE+1: ++	case CLOSE+2: ++	case CLOSE+3: ++	case CLOSE+4: ++	case CLOSE+5: ++	case CLOSE+6: ++	case CLOSE+7: ++	case CLOSE+8: ++	case CLOSE+9: ++		snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); ++		p = NULL; ++		break; ++	case STAR: ++		p = "STAR"; ++		break; ++	case PLUS: ++		p = "PLUS"; ++		break; ++	default: ++		printk("<3>Regexp: corrupted opcode\n"); ++		break; ++	} ++	if (p != NULL) ++		strncat(buf, p, BUFLEN-strlen(buf)); ++	return(buf); ++} ++#endif ++ ++ +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.h linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.h +--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.h	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.h	2004-06-27 19:07:00.000000000 -0500 +@@ -0,0 +1,27 @@ ++/* ++ * Definitions etc. for regexp(3) routines. ++ * ++ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof], ++ * not the System V one. ++ */ ++ ++#ifndef REGEXP_H ++#define REGEXP_H ++ ++#define NSUBEXP  10 ++typedef struct regexp { ++	char *startp[NSUBEXP]; ++	char *endp[NSUBEXP]; ++	char regstart;		/* Internal use only. */ ++	char reganch;		/* Internal use only. */ ++	char *regmust;		/* Internal use only. */ ++	int regmlen;		/* Internal use only. */ ++	char program[1];	/* Unwarranted chumminess with compiler. */ ++} regexp; ++ ++regexp * regcomp(char *exp, int *patternsize); ++int regexec(regexp *prog, char *string); ++void regsub(regexp *prog, char *source, char *dest); ++void regerror(char *s); ++ ++#endif +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/regexp/regmagic.h linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regmagic.h +--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regmagic.h	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regmagic.h	2004-06-27 19:07:00.000000000 -0500 +@@ -0,0 +1,5 @@ ++/* ++ * The first byte of the regexp internal "program" is actually this magic ++ * number; the start node begins in the second byte. ++ */ ++#define	MAGIC	0234 +diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/regexp/regsub.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regsub.c +--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regsub.c	1969-12-31 18:00:00.000000000 -0600 ++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regsub.c	2004-06-27 19:07:00.000000000 -0500 +@@ -0,0 +1,95 @@ ++/* ++ * regsub ++ * @(#)regsub.c	1.3 of 2 April 86 ++ * ++ *	Copyright (c) 1986 by University of Toronto. ++ *	Written by Henry Spencer.  Not derived from licensed software. ++ * ++ *	Permission is granted to anyone to use this software for any ++ *	purpose on any computer system, and to redistribute it freely, ++ *	subject to the following restrictions: ++ * ++ *	1. The author is not responsible for the consequences of use of ++ *		this software, no matter how awful, even if they arise ++ *		from defects in it. ++ * ++ *	2. The origin of this software must not be misrepresented, either ++ *		by explicit claim or by omission. ++ * ++ *	3. Altered versions must be plainly marked as such, and must not ++ *		be misrepresented as being the original software. ++ * ++ * ++ * This code was modified by Ethan Sommer to work within the kernel ++ * (it now uses kmalloc etc..) ++ * ++ */ ++#include "regexp.h" ++#include "regmagic.h" ++#include <linux/string.h> ++ ++ ++#ifndef CHARBITS ++#define	UCHARAT(p)	((int)*(unsigned char *)(p)) ++#else ++#define	UCHARAT(p)	((int)*(p)&CHARBITS) ++#endif ++ ++#if 0 ++//void regerror(char * s) ++//{ ++//        printk("regexp(3): %s", s); ++//        /* NOTREACHED */ ++//} ++#endif ++ ++/* ++ - regsub - perform substitutions after a regexp match ++ */ ++void ++regsub(regexp * prog, char * source, char * dest) ++{ ++	register char *src; ++	register char *dst; ++	register char c; ++	register int no; ++	register int len; ++	 ++	/* Not necessary and gcc doesn't like it -MLS */ ++	/*extern char *strncpy();*/ ++ ++	if (prog == NULL || source == NULL || dest == NULL) { ++		regerror("NULL parm to regsub"); ++		return; ++	} ++	if (UCHARAT(prog->program) != MAGIC) { ++		regerror("damaged regexp fed to regsub"); ++		return; ++	} ++ ++	src = source; ++	dst = dest; ++	while ((c = *src++) != '\0') { ++		if (c == '&') ++			no = 0; ++		else if (c == '\\' && '0' <= *src && *src <= '9') ++			no = *src++ - '0'; ++		else ++			no = -1; ++ ++		if (no < 0) {	/* Ordinary character. */ ++			if (c == '\\' && (*src == '\\' || *src == '&')) ++				c = *src++; ++			*dst++ = c; ++		} else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { ++			len = prog->endp[no] - prog->startp[no]; ++			(void) strncpy(dst, prog->startp[no], len); ++			dst += len; ++			if (len != 0 && *(dst-1) == '\0') {	/* strncpy hit NUL. */ ++				regerror("damaged match string"); ++				return; ++			} ++		} ++	} ++	*dst++ = '\0'; ++} | 
