From f3a6de83877ebc03e0bf7a2bab35ef497518c772 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Fri, 16 Dec 2005 13:38:40 +0000 Subject: [PATCH] fix one of the iptables 1.3.4 compile errors on 2.4, backport of ipt_string from 2.6, need runtime testing SVN-Revision: 2699 --- .../generic/609-netfilter_string.patch | 529 ++++++++++-------- 1 file changed, 306 insertions(+), 223 deletions(-) diff --git a/openwrt/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch b/openwrt/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch index 18f9f97bee..c8e1a2d2de 100644 --- a/openwrt/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch +++ b/openwrt/target/linux/linux-2.4/patches/generic/609-netfilter_string.patch @@ -1,265 +1,348 @@ ---- 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 @@ +diff -Nur linux-2.4.32/include/linux/netfilter_ipv4/ipt_string.h linux-2.4.32.patch/include/linux/netfilter_ipv4/ipt_string.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.patch/include/linux/netfilter_ipv4/ipt_string.h 2005-12-16 00:40:19.082509250 +0100 +@@ -0,0 +1,18 @@ ++#ifndef _IPT_STRING_H ++#define _IPT_STRING_H ++ ++#define IPT_STRING_MAX_PATTERN_SIZE 128 ++#define IPT_STRING_MAX_ALGO_NAME_SIZE 16 ++ ++struct ipt_string_info ++{ ++ u_int16_t from_offset; ++ u_int16_t to_offset; ++ char algo[IPT_STRING_MAX_ALGO_NAME_SIZE]; ++ char pattern[IPT_STRING_MAX_PATTERN_SIZE]; ++ u_int8_t patlen; ++ u_int8_t invert; ++ struct ts_config __attribute__((aligned(8))) *config; ++}; ++ ++#endif /*_IPT_STRING_H*/ +diff -Nur linux-2.4.32/include/linux/textsearch.h linux-2.4.32.patch/include/linux/textsearch.h +--- linux-2.4.32/include/linux/textsearch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.patch/include/linux/textsearch.h 2005-12-16 11:15:34.838073000 +0100 +@@ -0,0 +1,205 @@ ++#ifndef __LINUX_TEXTSEARCH_H ++#define __LINUX_TEXTSEARCH_H ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __CHECKER__ ++#define __bitwise__ __attribute__((bitwise)) ++#else ++#define __bitwise__ ++#endif ++#ifdef __CHECK_ENDIAN__ ++#define __bitwise __bitwise__ ++#else ++#define __bitwise ++#endif ++ ++typedef __u16 __bitwise __le16; ++typedef __u16 __bitwise __be16; ++typedef __u32 __bitwise __le32; ++typedef __u32 __bitwise __be32; ++#if defined(__GNUC__) && !defined(__STRICT_ANSI__) ++typedef __u64 __bitwise __le64; ++typedef __u64 __bitwise __be64; ++#endif ++ ++#ifdef __KERNEL__ ++typedef unsigned __bitwise__ gfp_t; ++#endif ++ ++struct ts_config; ++ ++/** ++ * TS_AUTOLOAD - Automatically load textsearch modules when needed ++ */ ++#define TS_AUTOLOAD 1 ++ ++/** ++ * struct ts_state - search state ++ * @offset: offset for next match ++ * @cb: control buffer, for persistant variables of get_next_block() ++ */ ++struct ts_state ++{ ++ unsigned int offset; ++ char cb[40]; ++}; ++ ++/** ++ * struct ts_ops - search module operations ++ * @name: name of search algorithm ++ * @init: initialization function to prepare a search ++ * @find: find the next occurrence of the pattern ++ * @destroy: destroy algorithm specific parts of a search configuration ++ * @get_pattern: return head of pattern ++ * @get_pattern_len: return length of pattern ++ * @owner: module reference to algorithm ++ */ ++struct ts_ops ++{ ++ const char *name; ++ struct ts_config * (*init)(const void *, unsigned int, gfp_t); ++ unsigned int (*find)(struct ts_config *, ++ struct ts_state *); ++ void (*destroy)(struct ts_config *); ++ void * (*get_pattern)(struct ts_config *); ++ unsigned int (*get_pattern_len)(struct ts_config *); ++ struct module *owner; ++ struct list_head list; ++}; ++ ++/** ++ * struct ts_config - search configuration ++ * @ops: operations of chosen algorithm ++ * @get_next_block: callback to fetch the next block to search in ++ * @finish: callback to finalize a search ++ */ ++struct ts_config ++{ ++ struct ts_ops *ops; ++ ++ /** ++ * get_next_block - fetch next block of data ++ * @consumed: number of bytes consumed by the caller ++ * @dst: destination buffer ++ * @conf: search configuration ++ * @state: search state ++ * ++ * Called repeatedly until 0 is returned. Must assign the ++ * head of the next block of data to &*dst and return the length ++ * of the block or 0 if at the end. consumed == 0 indicates ++ * a new search. May store/read persistant values in state->cb. ++ */ ++ unsigned int (*get_next_block)(unsigned int consumed, ++ const u8 **dst, ++ struct ts_config *conf, ++ struct ts_state *state); ++ ++ /** ++ * finish - finalize/clean a series of get_next_block() calls ++ * @conf: search configuration ++ * @state: search state ++ * ++ * Called after the last use of get_next_block(), may be used ++ * to cleanup any leftovers. ++ */ ++ void (*finish)(struct ts_config *conf, ++ struct ts_state *state); ++}; ++ ++/** ++ * textsearch_next - continue searching for a pattern ++ * @conf: search configuration ++ * @state: search state ++ * ++ * Continues a search looking for more occurrences of the pattern. ++ * textsearch_find() must be called to find the first occurrence ++ * in order to reset the state. ++ * ++ * Returns the position of the next occurrence of the pattern or ++ * UINT_MAX if not match was found. ++ */ ++static inline unsigned int textsearch_next(struct ts_config *conf, ++ struct ts_state *state) ++{ ++ unsigned int ret = conf->ops->find(conf, state); ++ ++ if (conf->finish) ++ conf->finish(conf, state); ++ ++ return ret; ++} ++ ++/** ++ * textsearch_find - start searching for a pattern ++ * @conf: search configuration ++ * @state: search state ++ * ++ * Returns the position of first occurrence of the pattern or ++ * UINT_MAX if no match was found. ++ */ ++static inline unsigned int textsearch_find(struct ts_config *conf, ++ struct ts_state *state) ++{ ++ state->offset = 0; ++ return textsearch_next(conf, state); ++} ++ ++/** ++ * textsearch_get_pattern - return head of the pattern ++ * @conf: search configuration ++ */ ++static inline void *textsearch_get_pattern(struct ts_config *conf) ++{ ++ return conf->ops->get_pattern(conf); ++} ++ ++/** ++ * textsearch_get_pattern_len - return length of the pattern ++ * @conf: search configuration ++ */ ++static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf) ++{ ++ return conf->ops->get_pattern_len(conf); ++} ++ ++extern int textsearch_register(struct ts_ops *); ++extern int textsearch_unregister(struct ts_ops *); ++extern struct ts_config *textsearch_prepare(const char *, const void *, ++ unsigned int, gfp_t, int); ++extern void textsearch_destroy(struct ts_config *conf); ++extern unsigned int textsearch_find_continuous(struct ts_config *, ++ struct ts_state *, ++ const void *, unsigned int); ++ ++ ++#define TS_PRIV_ALIGNTO 8 ++#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1)) ++ ++static inline struct ts_config *alloc_ts_config(size_t payload, ++ gfp_t gfp_mask) ++{ ++ struct ts_config *conf; ++ ++ conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask); ++ if (conf == NULL) ++ return -ENOMEM; ++ ++ memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload); ++ return conf; ++} ++ ++static inline void *ts_config_priv(struct ts_config *conf) ++{ ++ return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config))); ++} ++ ++#endif /* __KERNEL__ */ ++ ++#endif +diff -Nur linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.patch/net/ipv4/netfilter/Config.in +--- linux-2.4.32/net/ipv4/netfilter/Config.in 2005-01-19 15:10:13.000000000 +0100 ++++ linux-2.4.32.patch/net/ipv4/netfilter/Config.in 2005-12-16 00:41:43.023755250 +0100 +@@ -42,6 +42,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 + fi + # The targets +diff -Nur linux-2.4.32/net/ipv4/netfilter/ipt_string.c linux-2.4.32.patch/net/ipv4/netfilter/ipt_string.c +--- linux-2.4.32/net/ipv4/netfilter/ipt_string.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.patch/net/ipv4/netfilter/ipt_string.c 2005-12-16 00:40:48.436343750 +0100 +@@ -0,0 +1,91 @@ ++/* String matching match for iptables + * -+ * ChangeLog -+ * 19.02.2002: Gianni Tedesco -+ * Fixed SMP re-entrancy problem using per-cpu data areas -+ * for the skip/shift tables. -+ * 02.05.2001: Gianni Tedesco -+ * 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 -+ * 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. ++ * (C) 2005 Pablo Neira Ayuso ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. + */ + -+#include ++#include +#include ++#include +#include -+#include -+#include -+ +#include +#include ++#include + ++MODULE_AUTHOR("Pablo Neira Ayuso "); ++MODULE_DESCRIPTION("IP tables string match module"); +MODULE_LICENSE("GPL"); + -+struct string_per_cpu { -+ int *skip; -+ int *shift; -+ int *len; -+}; ++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 ts_state state; ++ struct ipt_string_info *conf = (struct ipt_string_info *) matchinfo; + -+struct string_per_cpu *bm_string_data=NULL; ++ memset(&state, 0, sizeof(struct ts_state)); + -+/* 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; ++ return (skb_find_text((struct sk_buff *)skb, conf->from_offset, ++ conf->to_offset, conf->config, &state) ++ != UINT_MAX) && !conf->invert; +} + ++#define STRING_TEXT_PRIV(m) ((struct ipt_string_info *) m) + -+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) ++static int checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) +{ -+ 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); -+} ++ struct ipt_string_info *conf = matchinfo; ++ struct ts_config *ts_conf; + -+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; ++ ++ /* Damn, can't handle this case properly with iptables... */ ++ if (conf->from_offset > conf->to_offset) ++ return 0; ++ ++ ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, ++ GFP_KERNEL, TS_AUTOLOAD); ++ if (IS_ERR(ts_conf)) ++ return 0; + -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info))) -+ return 0; ++ conf->config = ts_conf; + -+ return 1; ++ return 1; +} + -+void string_freeup_data(void) ++static void destroy(void *matchinfo, unsigned int matchsize) +{ -+ int c; -+ -+ if ( bm_string_data ) { -+ for(c=0; cconfig); +} + -+static struct ipt_match string_match -+= { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE }; ++static struct ipt_match string_match = { ++ .name = "string", ++ .match = match, ++ .checkentry = checkentry, ++ .destroy = destroy, ++ .me = 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