summaryrefslogtreecommitdiffstats
path: root/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/linux-2.4/patches/generic/609-netfilter_string.patch')
-rw-r--r--target/linux/linux-2.4/patches/generic/609-netfilter_string.patch265
1 files changed, 265 insertions, 0 deletions
diff --git a/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch b/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch
new file mode 100644
index 000000000..18f9f97be
--- /dev/null
+++ b/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch
@@ -0,0 +1,265 @@
+--- linux/net/ipv4/netfilter/Config.in.org 2005-11-08 23:11:47.011929664 +0100
++++ linux/net/ipv4/netfilter/Config.in 2005-11-08 23:10:33.329131152 +0100
+@@ -50,6 +50,7 @@
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' String match support (EXPERIMENTAL) ' CONFIG_IP_NF_MATCH_STRING $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
+--- linux/net/ipv4/netfilter/Makefile.org 2005-11-08 23:11:57.214378656 +0100
++++ linux/net/ipv4/netfilter/Makefile 2005-11-08 23:11:20.980886984 +0100
+@@ -97,6 +97,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
++obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+
+ obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o
+--- linux/net/ipv4/netfilter/ipt_string.c 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ipt_string.c 2005-11-08 23:08:51.531606728 +0100
+@@ -0,0 +1,218 @@
++/* Kernel module to match a string into a packet.
++ *
++ * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
++ *
++ * ChangeLog
++ * 19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Fixed SMP re-entrancy problem using per-cpu data areas
++ * for the skip/shift tables.
++ * 02.05.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Fixed kernel panic, due to overrunning boyer moore string
++ * tables. Also slightly tweaked heuristic for deciding what
++ * search algo to use.
++ * 27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Implemented Boyer Moore Sublinear search algorithm
++ * alongside the existing linear search based on memcmp().
++ * Also a quick check to decide which method to use on a per
++ * packet basis.
++ */
++
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_string.h>
++
++MODULE_LICENSE("GPL");
++
++struct string_per_cpu {
++ int *skip;
++ int *shift;
++ int *len;
++};
++
++struct string_per_cpu *bm_string_data=NULL;
++
++/* Boyer Moore Sublinear string search - VERY FAST */
++char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len)
++{
++ int M1, right_end, sk, sh;
++ int ended, j, i;
++
++ int *skip, *shift, *len;
++
++ /* use data suitable for this CPU */
++ shift=bm_string_data[smp_processor_id()].shift;
++ skip=bm_string_data[smp_processor_id()].skip;
++ len=bm_string_data[smp_processor_id()].len;
++
++ /* Setup skip/shift tables */
++ M1 = right_end = needle_len-1;
++ for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len;
++ for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i;
++
++ for (i = 1; i < needle_len; i++) {
++ for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++);
++ len[i] = j;
++ }
++
++ shift[0] = 1;
++ for (i = 1; i < needle_len; i++) shift[i] = needle_len;
++ for (i = M1; i > 0; i--) shift[len[i]] = i;
++ ended = 0;
++
++ for (i = 0; i < needle_len; i++) {
++ if (len[i] == M1 - i) ended = i;
++ if (ended) shift[i] = ended;
++ }
++
++ /* Do the search*/
++ while (right_end < haystack_len)
++ {
++ for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++);
++ if (i == needle_len) {
++ return haystack+(right_end - M1);
++ }
++
++ sk = skip[haystack[right_end - i]];
++ sh = shift[i];
++ right_end = max(right_end - i + sk, right_end + sh);
++ }
++
++ return NULL;
++}
++
++/* Linear string search based on memcmp() */
++char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len)
++{
++ char *k = haystack + (haystack_len-needle_len);
++ char *t = haystack;
++
++ while ( t <= k ) {
++ if (memcmp(t, needle, needle_len) == 0)
++ return t;
++ t++;
++ }
++
++ return NULL;
++}
++
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_string_info *info = matchinfo;
++ struct iphdr *ip = skb->nh.iph;
++ int hlen, nlen;
++ char *needle, *haystack;
++ proc_ipt_search search=search_linear;
++
++ if ( !ip ) return 0;
++
++ /* get lenghts, and validate them */
++ nlen=info->len;
++ hlen=ntohs(ip->tot_len)-(ip->ihl*4);
++ if ( nlen > hlen ) return 0;
++
++ needle=(char *)&info->string;
++ haystack=(char *)ip+(ip->ihl*4);
++
++ /* The sublinear search comes in to its own
++ * on the larger packets */
++ if ( (hlen>IPT_STRING_HAYSTACK_THRESH) &&
++ (nlen>IPT_STRING_NEEDLE_THRESH) ) {
++ if ( hlen < BM_MAX_HLEN ) {
++ search=search_sublinear;
++ }else{
++ if (net_ratelimit())
++ printk(KERN_INFO "ipt_string: Packet too big "
++ "to attempt sublinear string search "
++ "(%d bytes)\n", hlen );
++ }
++ }
++
++ return ((search(needle, haystack, nlen, hlen)!=NULL) ^ 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_string_info)))
++ return 0;
++
++ return 1;
++}
++
++void string_freeup_data(void)
++{
++ int c;
++
++ if ( bm_string_data ) {
++ for(c=0; c<smp_num_cpus; c++) {
++ if ( bm_string_data[c].shift ) kfree(bm_string_data[c].shift);
++ if ( bm_string_data[c].skip ) kfree(bm_string_data[c].skip);
++ if ( bm_string_data[c].len ) kfree(bm_string_data[c].len);
++ }
++ kfree(bm_string_data);
++ }
++}
++
++static struct ipt_match string_match
++= { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ int c;
++ size_t tlen;
++ size_t alen;
++
++ tlen=sizeof(struct string_per_cpu)*smp_num_cpus;
++ alen=sizeof(int)*BM_MAX_HLEN;
++
++ /* allocate array of structures */
++ if ( !(bm_string_data=kmalloc(tlen,GFP_KERNEL)) ) {
++ return 0;
++ }
++
++ memset(bm_string_data, 0, tlen);
++
++ /* allocate our skip/shift tables */
++ for(c=0; c<smp_num_cpus; c++) {
++ if ( !(bm_string_data[c].shift=kmalloc(alen, GFP_KERNEL)) )
++ goto alloc_fail;
++ if ( !(bm_string_data[c].skip=kmalloc(alen, GFP_KERNEL)) )
++ goto alloc_fail;
++ if ( !(bm_string_data[c].len=kmalloc(alen, GFP_KERNEL)) )
++ goto alloc_fail;
++ }
++
++ return ipt_register_match(&string_match);
++
++alloc_fail:
++ string_freeup_data();
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&string_match);
++ string_freeup_data();
++}
++
++module_init(init);
++module_exit(fini);
+--- linux/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ipt_string.h 2005-11-08 23:09:45.219444936 +0100
+@@ -0,0 +1,21 @@
++#ifndef _IPT_STRING_H
++#define _IPT_STRING_H
++
++/* *** PERFORMANCE TWEAK ***
++ * Packet size and search string threshold,
++ * above which sublinear searches is used. */
++#define IPT_STRING_HAYSTACK_THRESH 100
++#define IPT_STRING_NEEDLE_THRESH 20
++
++#define BM_MAX_NLEN 256
++#define BM_MAX_HLEN 1024
++
++typedef char *(*proc_ipt_search) (char *, char *, int, int);
++
++struct ipt_string_info {
++ char string[BM_MAX_NLEN];
++ u_int16_t invert;
++ u_int16_t len;
++};
++
++#endif /* _IPT_STRING_H */