diff --git a/target/linux/linux-2.4/config/ar7 b/target/linux/linux-2.4/config/ar7 index 153ba9bf9..833d9d3a2 100644 --- a/target/linux/linux-2.4/config/ar7 +++ b/target/linux/linux-2.4/config/ar7 @@ -343,11 +343,14 @@ CONFIG_IP_NF_FTP=y CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=y +CONFIG_IP_NF_CT_ACCT=m +CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_QUOTA=m CONFIG_IP_NF_SET=m CONFIG_IP_NF_SET_MAX=256 CONFIG_IP_NF_SET_HASHSIZE=1024 @@ -364,6 +367,7 @@ CONFIG_IP_NF_MATCH_PKTTYPE=m CONFIG_IP_NF_MATCH_MARK=y CONFIG_IP_NF_MATCH_MULTIPORT=y CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_CONDITION=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_IPP2P=m @@ -377,6 +381,7 @@ CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_CONNMARK=m CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_STRING=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_MATCH_LAYER7=m # CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set @@ -422,6 +427,7 @@ CONFIG_IPV6=m CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_CONDITION=m CONFIG_IP6_NF_MATCH_MAC=m # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_MATCH_OPTS is not set diff --git a/target/linux/linux-2.4/config/brcm b/target/linux/linux-2.4/config/brcm index adff1f56c..5e7626523 100644 --- a/target/linux/linux-2.4/config/brcm +++ b/target/linux/linux-2.4/config/brcm @@ -354,11 +354,14 @@ CONFIG_IP_NF_FTP=y CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=y +CONFIG_IP_NF_CT_ACCT=m +CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_QUOTA=m CONFIG_IP_NF_SET=m CONFIG_IP_NF_SET_MAX=256 CONFIG_IP_NF_SET_HASHSIZE=1024 @@ -375,6 +378,7 @@ CONFIG_IP_NF_MATCH_PKTTYPE=m CONFIG_IP_NF_MATCH_MARK=y CONFIG_IP_NF_MATCH_MULTIPORT=y CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_CONDITION=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_IPP2P=m @@ -388,6 +392,7 @@ CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_CONNMARK=m CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_STRING=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_MATCH_LAYER7=m # CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set @@ -433,6 +438,7 @@ CONFIG_IPV6=m CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_CONDITION=m CONFIG_IP6_NF_MATCH_MAC=m # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_MATCH_OPTS is not set diff --git a/target/linux/linux-2.4/config/x86 b/target/linux/linux-2.4/config/x86 index 2aef35b28..da27d3c45 100644 --- a/target/linux/linux-2.4/config/x86 +++ b/target/linux/linux-2.4/config/x86 @@ -282,16 +282,31 @@ CONFIG_IP_NF_FTP=y CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=y +CONFIG_IP_NF_CT_ACCT=m +CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_QUOTA=m +CONFIG_IP_NF_SET=m +CONFIG_IP_NF_SET_MAX=256 +CONFIG_IP_NF_SET_HASHSIZE=1024 +CONFIG_IP_NF_MATCH_SET=m +CONFIG_IP_NF_TARGET_SET=m +CONFIG_IP_NF_SET_IPMAP=m +CONFIG_IP_NF_SET_PORTMAP=m +CONFIG_IP_NF_SET_MACIPMAP=m +CONFIG_IP_NF_SET_IPHASH=m +CONFIG_IP_NF_SET_NETHASH=m +CONFIG_IP_NF_SET_IPTREE=m CONFIG_IP_NF_MATCH_MAC=m CONFIG_IP_NF_MATCH_PKTTYPE=m CONFIG_IP_NF_MATCH_MARK=y CONFIG_IP_NF_MATCH_MULTIPORT=y CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_CONDITION=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_IPP2P=m @@ -305,6 +320,7 @@ CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_CONNMARK=m CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_STRING=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_MATCH_LAYER7=m # CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set @@ -337,17 +353,6 @@ CONFIG_IP_NF_TARGET_TCPMSS=y CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP_NF_SET=m -CONFIG_IP_NF_SET_MAX=256 -CONFIG_IP_NF_SET_HASHSIZE=1024 -CONFIG_IP_NF_MATCH_SET=m -CONFIG_IP_NF_TARGET_SET=m -CONFIG_IP_NF_SET_IPMAP=m -CONFIG_IP_NF_SET_PORTMAP=m -CONFIG_IP_NF_SET_MACIPMAP=m -CONFIG_IP_NF_SET_IPHASH=m -CONFIG_IP_NF_SET_NETHASH=m -CONFIG_IP_NF_SET_IPTREE=m # # IP: Virtual Server Configuration @@ -361,6 +366,7 @@ CONFIG_IPV6=m CONFIG_IP6_NF_QUEUE=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_CONDITION=m CONFIG_IP6_NF_MATCH_MAC=m # CONFIG_IP6_NF_MATCH_RT is not set # CONFIG_IP6_NF_MATCH_OPTS is not set 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 ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++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; cstatus); + + WRITE_UNLOCK(&tcp_lock); +- ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]); ++ ip_ct_refresh_acct(conntrack,ctinfo,iph, *tcp_timeouts[newconntrack]); + } + + return NF_ACCEPT; +--- linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c.org 2003-11-28 19:26:21.000000000 +0100 ++++ linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c 2005-11-13 15:47:38.348159896 +0100 +@@ -47,16 +47,16 @@ + /* Returns verdict for packet, and may modify conntracktype */ + static int udp_packet(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len, +- enum ip_conntrack_info conntrackinfo) ++ enum ip_conntrack_info ctinfo) + { + /* If we've seen traffic both ways, this is some kind of UDP + stream. Extend timeout. */ + if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { +- ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream); ++ ip_ct_refresh_acct(conntrack,ctinfo,iph,ip_ct_udp_timeout_stream); + /* Also, more likely to be important, and not a probe */ + set_bit(IPS_ASSURED_BIT, &conntrack->status); + } else +- ip_ct_refresh(conntrack, ip_ct_udp_timeout); ++ ip_ct_refresh_acct(conntrack,ctinfo,iph, ip_ct_udp_timeout); + + return NF_ACCEPT; + } +--- linux/net/ipv4/netfilter/ip_conntrack_standalone.c.org 2005-11-12 16:48:38.000000000 +0100 ++++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-11-13 15:51:07.608347512 +0100 +@@ -79,6 +79,18 @@ + return len; + } + ++#if defined(CONFIG_IP_NF_CT_ACCT) || \ ++ defined(CONFIG_IP_NF_CT_ACCT_MODULE) ++static unsigned int ++print_counters(char *buffer, struct ip_conntrack_counter *counter) ++{ ++ return sprintf(buffer, "packets=%llu bytes=%llu ", ++ counter->packets, counter->bytes); ++} ++#else ++#define print_counters(x, y) 0 ++#endif ++ + static unsigned int + print_conntrack(char *buffer, struct ip_conntrack *conntrack) + { +@@ -98,11 +110,15 @@ + len += print_tuple(buffer + len, + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + proto); ++ len += print_counters(buffer + len, ++ &conntrack->counters[IP_CT_DIR_ORIGINAL]); + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) + len += sprintf(buffer + len, "[UNREPLIED] "); + len += print_tuple(buffer + len, + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, + proto); ++ len += print_counters(buffer + len, ++ &conntrack->counters[IP_CT_DIR_REPLY]); + if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) + len += sprintf(buffer + len, "[ASSURED] "); + len += sprintf(buffer + len, "use=%u ", +@@ -478,7 +494,7 @@ + EXPORT_SYMBOL(ip_conntrack_helper_register); + EXPORT_SYMBOL(ip_conntrack_helper_unregister); + EXPORT_SYMBOL(ip_ct_iterate_cleanup); +-EXPORT_SYMBOL(ip_ct_refresh); ++EXPORT_SYMBOL(ip_ct_refresh_acct); + EXPORT_SYMBOL(ip_ct_find_proto); + EXPORT_SYMBOL(__ip_ct_find_proto); + EXPORT_SYMBOL(ip_ct_find_helper); +--- linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c.org 2003-11-28 19:26:21.000000000 +0100 ++++ linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c 2005-11-13 15:44:20.734201784 +0100 +@@ -41,9 +41,9 @@ + /* Returns verdict for packet, or -1 for invalid. */ + static int established(struct ip_conntrack *conntrack, + struct iphdr *iph, size_t len, +- enum ip_conntrack_info conntrackinfo) ++ enum ip_conntrack_info ctinfo) + { +- ip_ct_refresh(conntrack, ip_ct_generic_timeout); ++ ip_ct_refresh_acct(conntrack, ctinfo,iph,ip_ct_generic_timeout); + return NF_ACCEPT; + } + +--- linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c.org 2003-11-28 19:26:21.000000000 +0100 ++++ linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c 2005-11-13 15:44:50.733641176 +0100 +@@ -82,7 +82,7 @@ + ct->timeout.function((unsigned long)ct); + } else { + atomic_inc(&ct->proto.icmp.count); +- ip_ct_refresh(ct, ip_ct_icmp_timeout); ++ ip_ct_refresh_acct(ct,ctinfo,iph, ip_ct_icmp_timeout); + } + + return NF_ACCEPT; +--- linux/net/ipv4/netfilter/ip_conntrack_core.c.org 2005-11-12 16:48:38.000000000 +0100 ++++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2005-11-13 15:43:23.882844504 +0100 +@@ -1196,22 +1196,40 @@ + + MOD_DEC_USE_COUNT; + } ++static inline void ct_add_counters(struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ const struct iphdr *iph) ++{ ++#if defined(CONFIG_IP_NF_CT_ACCT) || \ ++ defined(CONFIG_IP_NF_CT_ACCT_MODULE) ++ if (iph) { ++ ct->counters[CTINFO2DIR(ctinfo)].packets++; ++ ct->counters[CTINFO2DIR(ctinfo)].bytes += ++ ntohs(iph->tot_len); ++ } ++#endif ++} + + /* Refresh conntrack for this many jiffies. */ +-void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) ++void ip_ct_refresh_acct(struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ const struct iphdr *iph, ++ unsigned long extra_jiffies) + { + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); + + WRITE_LOCK(&ip_conntrack_lock); + /* If not in hash table, timer will not be active yet */ +- if (!is_confirmed(ct)) ++ if (!is_confirmed(ct)) { + ct->timeout.expires = extra_jiffies; +- else { ++ ct_add_counters(ct, ctinfo,iph); ++ } else { + /* Need del_timer for race avoidance (may already be dying). */ + if (del_timer(&ct->timeout)) { + ct->timeout.expires = jiffies + extra_jiffies; + add_timer(&ct->timeout); + } ++ ct_add_counters(ct, ctinfo, iph); + } + WRITE_UNLOCK(&ip_conntrack_lock); + } +--- linux/include/linux/netfilter_ipv4/ip_conntrack.h.org 2005-11-12 16:48:38.000000000 +0100 ++++ linux/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-13 15:39:04.000000000 +0100 +@@ -164,6 +164,12 @@ + union ip_conntrack_expect_help help; + }; + ++struct ip_conntrack_counter ++{ ++ u_int64_t packets; ++ u_int64_t bytes; ++}; ++ + struct ip_conntrack_helper; + + struct ip_conntrack +@@ -181,6 +187,12 @@ + /* Timer function; drops refcnt when it goes off. */ + struct timer_list timeout; + ++#if defined(CONFIG_IP_NF_CT_ACCT) || \ ++ defined(CONFIG_IP_NF_CT_ACCT_MODULE) ++ /* Accounting Information (same cache line as other written members) */ ++ struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; ++#endif ++ + /* If we're expecting another related connection, this will be + in expected linked list */ + struct list_head sibling_list; +@@ -264,8 +276,10 @@ + const struct ip_conntrack_tuple *orig); + + /* Refresh conntrack for this many jiffies */ +-extern void ip_ct_refresh(struct ip_conntrack *ct, +- unsigned long extra_jiffies); ++extern void ip_ct_refresh_acct(struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ const struct iphdr *iph, ++ unsigned long extra_jiffies); + + /* These are for NAT. Icky. */ + /* Call me when a conntrack is destroyed. */ +--- linux/net/ipv4/netfilter/ipt_connbytes.c.org 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/ipv4/netfilter/ipt_connbytes.c 2005-11-13 16:22:02.021433872 +0100 +@@ -0,0 +1,163 @@ ++/* Kernel module to match connection tracking byte counter. ++ * GPL (C) 2002 Martin Devera (devik@cdi.cz). ++ * ++ * 2004-07-20 Harald Welte ++ * - reimplemented to use per-connection accounting counters ++ * - add functionality to match number of packets ++ * - add functionality to match average packet size ++ * - add support to match directions seperately ++ * ++ * 2004-10-24 Piotr Chytla ++ * - Connbytes with per-connection accouting backported to 2.4 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++static u_int64_t mydiv(u_int64_t arg1,u_int32_t arg2) ++{ ++ do_div(arg1,arg2); ++ return arg1; ++} ++ ++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 u_int64_t what; ++ const struct ipt_connbytes_info *sinfo = matchinfo; ++ enum ip_conntrack_info ctinfo; ++ struct ip_conntrack *ct; ++ ++ if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo))) ++ return 0; /* no match */ ++ switch (sinfo->what) { ++ case IPT_CONNBYTES_WHAT_PKTS: ++ switch (sinfo->direction) { ++ case IPT_CONNBYTES_DIR_ORIGINAL: ++ what = ct->counters[IP_CT_DIR_ORIGINAL].packets; ++ break; ++ case IPT_CONNBYTES_DIR_REPLY: ++ what = ct->counters[IP_CT_DIR_REPLY].packets; ++ break; ++ case IPT_CONNBYTES_DIR_BOTH: ++ what = ct->counters[IP_CT_DIR_ORIGINAL].packets; ++ what += ct->counters[IP_CT_DIR_REPLY].packets; ++ break; ++ } ++ break; ++ case IPT_CONNBYTES_WHAT_BYTES: ++ switch (sinfo->direction) { ++ case IPT_CONNBYTES_DIR_ORIGINAL: ++ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; ++ break; ++ case IPT_CONNBYTES_DIR_REPLY: ++ what = ct->counters[IP_CT_DIR_REPLY].bytes; ++ break; ++ case IPT_CONNBYTES_DIR_BOTH: ++ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes; ++ what += ct->counters[IP_CT_DIR_REPLY].bytes; ++ break; ++ } ++ break; ++ case IPT_CONNBYTES_WHAT_AVGPKT: ++ switch (sinfo->direction) { ++ case IPT_CONNBYTES_DIR_ORIGINAL: ++ { ++ u_int32_t pkts32; ++ ++ if (ct->counters[IP_CT_DIR_ORIGINAL].packets > 0xfffffffff) ++ pkts32 = 0xffffffff; ++ else ++ pkts32 = ct->counters[IP_CT_DIR_ORIGINAL].packets; ++ what = mydiv(ct->counters[IP_CT_DIR_ORIGINAL].bytes,pkts32); ++ } ++ break; ++ case IPT_CONNBYTES_DIR_REPLY: ++ { ++ u_int32_t pkts32; ++ ++ if (ct->counters[IP_CT_DIR_REPLY].packets > 0xffffffff) ++ pkts32 = 0xffffffff; ++ else ++ pkts32 = ct->counters[IP_CT_DIR_REPLY].packets; ++ what = mydiv(ct->counters[IP_CT_DIR_REPLY].bytes,pkts32); ++ } ++ break; ++ case IPT_CONNBYTES_DIR_BOTH: ++ { ++ u_int64_t bytes; ++ u_int64_t pkts; ++ u_int32_t pkts32; ++ bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes + ++ ct->counters[IP_CT_DIR_REPLY].bytes; ++ pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets + ++ ct->counters[IP_CT_DIR_REPLY].packets; ++ if (pkts > 0xffffffff) ++ pkts32 = 0xffffffff; ++ else ++ pkts32 = pkts; ++ what = mydiv(bytes,pkts); ++ } ++ break; ++ } ++ break; ++ } ++ if (sinfo->count.to) ++ return (what <= sinfo->count.to && what >= sinfo->count.from); ++ else ++ return (what >= sinfo->count.from); ++} ++ ++static int check(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ const struct ipt_connbytes_info *sinfo = matchinfo; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info))) ++ return 0; ++ if (sinfo->what != IPT_CONNBYTES_WHAT_PKTS && ++ sinfo->what != IPT_CONNBYTES_WHAT_BYTES && ++ sinfo->what != IPT_CONNBYTES_WHAT_AVGPKT) ++ return 0; ++ ++ if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL && ++ sinfo->direction != IPT_CONNBYTES_DIR_REPLY && ++ sinfo->direction != IPT_CONNBYTES_DIR_BOTH) ++ return 0; ++ ++ return 1; ++} ++ ++static struct ipt_match state_match ++= { { NULL, NULL }, "connbytes", &match, &check, NULL, THIS_MODULE }; ++ ++static int __init init(void) ++{ ++ return ipt_register_match(&state_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&state_match); ++} ++ ++module_init(init); ++module_exit(fini); ++MODULE_LICENSE("GPL"); +--- linux/include/linux/netfilter_ipv4/ipt_connbytes.h.org 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/linux/netfilter_ipv4/ipt_connbytes.h 2005-11-13 16:11:24.567341624 +0100 +@@ -0,0 +1,25 @@ ++#ifndef _IPT_CONNBYTES_H ++#define _IPT_CONNBYTES_H ++enum ipt_connbytes_what { ++ IPT_CONNBYTES_WHAT_PKTS, ++ IPT_CONNBYTES_WHAT_BYTES, ++ IPT_CONNBYTES_WHAT_AVGPKT, ++}; ++ ++enum ipt_connbytes_direction { ++ IPT_CONNBYTES_DIR_ORIGINAL, ++ IPT_CONNBYTES_DIR_REPLY, ++ IPT_CONNBYTES_DIR_BOTH, ++}; ++ ++struct ipt_connbytes_info ++{ ++ struct { ++ u_int64_t from; /* count to be matched */ ++ u_int64_t to; /* count to be matched */ ++ } count; ++ u_int8_t what; /* ipt_connbytes_what */ ++ u_int8_t direction; /* ipt_connbytes_direction */ ++}; ++ ++#endif diff --git a/target/linux/linux-2.4/patches/generic/611-netfilter_condition.patch b/target/linux/linux-2.4/patches/generic/611-netfilter_condition.patch new file mode 100644 index 000000000..6c16c29f0 --- /dev/null +++ b/target/linux/linux-2.4/patches/generic/611-netfilter_condition.patch @@ -0,0 +1,625 @@ +diff -ruN linux-2.4.30-old/Documentation/Configure.help linux-2.4.30-new/Documentation/Configure.help +--- linux-2.4.30-old/Documentation/Configure.help 2005-11-13 21:52:27.000000000 +0100 ++++ linux-2.4.30-new/Documentation/Configure.help 2005-11-13 22:20:15.000000000 +0100 +@@ -2979,6 +2979,14 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++Condition variable match support ++CONFIG_IP_NF_MATCH_CONDITION ++ This option allows you to match firewall rules against condition ++ variables stored in the /proc/net/ipt_condition directory. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ + conntrack match support + CONFIG_IP_NF_MATCH_CONNTRACK + This is a general conntrack match module, a superset of the state match. +@@ -3354,6 +3362,14 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++Condition variable match support ++CONFIG_IP6_NF_MATCH_CONDITION ++ This option allows you to match firewall rules against condition ++ variables stored in the /proc/net/ipt_condition directory. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ + Multiple port match support + CONFIG_IP6_NF_MATCH_MULTIPORT + Multiport matching allows you to match TCP or UDP packets based on +diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h +--- linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h 2005-11-13 22:20:14.000000000 +0100 +@@ -0,0 +1,11 @@ ++#ifndef __IPT_CONDITION_MATCH__ ++#define __IPT_CONDITION_MATCH__ ++ ++#define CONDITION_NAME_LEN 32 ++ ++struct condition_info { ++ char name[CONDITION_NAME_LEN]; ++ int invert; ++}; ++ ++#endif +diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h +--- linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h 2005-11-13 22:20:14.000000000 +0100 +@@ -0,0 +1,11 @@ ++#ifndef __IP6T_CONDITION_MATCH__ ++#define __IP6T_CONDITION_MATCH__ ++ ++#define CONDITION6_NAME_LEN 32 ++ ++struct condition6_info { ++ char name[CONDITION6_NAME_LEN]; ++ int invert; ++}; ++ ++#endif +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Config.in linux-2.4.30-new/net/ipv4/netfilter/Config.in +--- linux-2.4.30-old/net/ipv4/netfilter/Config.in 2005-11-13 21:52:27.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100 +@@ -43,6 +43,7 @@ + dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES + dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES + dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES + dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES + dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Makefile linux-2.4.30-new/net/ipv4/netfilter/Makefile +--- linux-2.4.30-old/net/ipv4/netfilter/Makefile 2005-11-13 21:52:27.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100 +@@ -94,6 +94,7 @@ + obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o + obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o + obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o ++obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o + + obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o + +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c +--- linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c 2005-11-13 22:20:14.000000000 +0100 +@@ -0,0 +1,256 @@ ++/*-------------------------------------------*\ ++| Netfilter Condition Module | ++| | ++| Description: This module allows firewall | ++| rules to match using condition variables | ++| stored in /proc files. | ++| | ++| Author: Stephane Ouellette 2002-10-22 | ++| | ++| | ++| History: | ++| 2003-02-10 Second version with improved | ++| locking and simplified code. | ++| | ++| This software is distributed under the | ++| terms of the GNU GPL. | ++\*-------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifndef CONFIG_PROC_FS ++#error "Proc file system support is required for this module" ++#endif ++ ++ ++MODULE_AUTHOR("Stephane Ouellette "); ++MODULE_DESCRIPTION("Allows rules to match against condition variables"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct condition_variable { ++ struct condition_variable *next; ++ struct proc_dir_entry *status_proc; ++ atomic_t refcount; ++ int enabled; /* TRUE == 1, FALSE == 0 */ ++}; ++ ++ ++static rwlock_t list_lock; ++static struct condition_variable *head = NULL; ++static struct proc_dir_entry *proc_net_condition = NULL; ++ ++ ++static int ++ipt_condition_read_info(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (offset == 0) { ++ *start = buffer; ++ buffer[0] = (var->enabled) ? '1' : '0'; ++ buffer[1] = '\n'; ++ return 2; ++ } ++ ++ *eof = 1; ++ return 0; ++} ++ ++ ++static int ++ipt_condition_write_info(struct file *file, const char *buffer, ++ unsigned long length, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (length) { ++ /* Match only on the first character */ ++ switch (buffer[0]) { ++ case '0': ++ var->enabled = 0; ++ break; ++ case '1': ++ var->enabled = 1; ++ } ++ } ++ ++ return (int) length; ++} ++ ++ ++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 condition_info *info = ++ (const struct condition_info *) matchinfo; ++ struct condition_variable *var; ++ int condition_status = 0; ++ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ condition_status = var->enabled; ++ break; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ return condition_status ^ info->invert; ++} ++ ++ ++ ++static int ++checkentry(const char *tablename, const struct ipt_ip *ip, ++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++ struct condition_info *info = (struct condition_info *) matchinfo; ++ struct condition_variable *var, *newvar; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) ++ return 0; ++ ++ /* The first step is to check if the condition variable already exists. */ ++ /* Here, a read lock is sufficient because we won't change the list */ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ /* At this point, we need to allocate a new condition variable */ ++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); ++ ++ if (!newvar) ++ return -ENOMEM; ++ ++ /* Create the condition variable's proc file entry */ ++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); ++ ++ if (!newvar->status_proc) { ++ /* ++ * There are two possibilities: ++ * 1- Another condition variable with the same name has been created, which is valid. ++ * 2- There was a memory allocation error. ++ */ ++ kfree(newvar); ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ return -ENOMEM; ++ } ++ ++ atomic_set(&newvar->refcount, 1); ++ newvar->enabled = 0; ++ newvar->status_proc->owner = THIS_MODULE; ++ newvar->status_proc->data = newvar; ++ wmb(); ++ newvar->status_proc->read_proc = ipt_condition_read_info; ++ newvar->status_proc->write_proc = ipt_condition_write_info; ++ ++ write_lock(&list_lock); ++ ++ newvar->next = head; ++ head = newvar; ++ ++ write_unlock(&list_lock); ++ ++ return 1; ++} ++ ++ ++static void ++destroy(void *matchinfo, unsigned int matchsize) ++{ ++ struct condition_info *info = (struct condition_info *) matchinfo; ++ struct condition_variable *var, *prev = NULL; ++ ++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) ++ return; ++ ++ write_lock(&list_lock); ++ ++ for (var = head; var && strcmp(info->name, var->status_proc->name); ++ prev = var, var = var->next); ++ ++ if (var && atomic_dec_and_test(&var->refcount)) { ++ if (prev) ++ prev->next = var->next; ++ else ++ head = var->next; ++ ++ write_unlock(&list_lock); ++ remove_proc_entry(var->status_proc->name, proc_net_condition); ++ kfree(var); ++ } else ++ write_unlock(&list_lock); ++} ++ ++ ++static struct ipt_match condition_match = { ++ .name = "condition", ++ .match = &match, ++ .checkentry = &checkentry, ++ .destroy = &destroy, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init ++init(void) ++{ ++ int errorcode; ++ ++ rwlock_init(&list_lock); ++ proc_net_condition = proc_mkdir("ipt_condition", proc_net); ++ ++ if (proc_net_condition) { ++ errorcode = ipt_register_match(&condition_match); ++ ++ if (errorcode) ++ remove_proc_entry("ipt_condition", proc_net); ++ } else ++ errorcode = -EACCES; ++ ++ return errorcode; ++} ++ ++ ++static void __exit ++fini(void) ++{ ++ ipt_unregister_match(&condition_match); ++ remove_proc_entry("ipt_condition", proc_net); ++} ++ ++module_init(init); ++module_exit(fini); +diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Config.in linux-2.4.30-new/net/ipv6/netfilter/Config.in +--- linux-2.4.30-old/net/ipv6/netfilter/Config.in 2003-06-13 16:51:39.000000000 +0200 ++++ linux-2.4.30-new/net/ipv6/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100 +@@ -17,6 +17,7 @@ + if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then + # The simple matches. + dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES ++ dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES + dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES +diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Makefile linux-2.4.30-new/net/ipv6/netfilter/Makefile +--- linux-2.4.30-old/net/ipv6/netfilter/Makefile 2003-06-13 16:51:39.000000000 +0200 ++++ linux-2.4.30-new/net/ipv6/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100 +@@ -14,6 +14,7 @@ + # Link order matters here. + obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o + obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o ++obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o + obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o + obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o + obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o +diff -ruN linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c +--- linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c 2005-11-13 22:20:14.000000000 +0100 +@@ -0,0 +1,254 @@ ++/*-------------------------------------------*\ ++| Netfilter Condition Module for IPv6 | ++| | ++| Description: This module allows firewall | ++| rules to match using condition variables | ++| stored in /proc files. | ++| | ++| Author: Stephane Ouellette 2003-02-10 | ++| | ++| | ++| This software is distributed under the | ++| terms of the GNU GPL. | ++\*-------------------------------------------*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifndef CONFIG_PROC_FS ++#error "Proc file system support is required for this module" ++#endif ++ ++ ++MODULE_AUTHOR("Stephane Ouellette "); ++MODULE_DESCRIPTION("Allows rules to match against condition variables"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct condition_variable { ++ struct condition_variable *next; ++ struct proc_dir_entry *status_proc; ++ atomic_t refcount; ++ int enabled; /* TRUE == 1, FALSE == 0 */ ++}; ++ ++ ++static rwlock_t list_lock; ++static struct condition_variable *head = NULL; ++static struct proc_dir_entry *proc_net_condition = NULL; ++ ++ ++static int ++ipt_condition_read_info(char *buffer, char **start, off_t offset, ++ int length, int *eof, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (offset == 0) { ++ *start = buffer; ++ buffer[0] = (var->enabled) ? '1' : '0'; ++ buffer[1] = '\n'; ++ return 2; ++ } ++ ++ *eof = 1; ++ return 0; ++} ++ ++ ++static int ++ipt_condition_write_info(struct file *file, const char *buffer, ++ unsigned long length, void *data) ++{ ++ struct condition_variable *var = ++ (struct condition_variable *) data; ++ ++ if (length) { ++ /* Match only on the first character */ ++ switch (buffer[0]) { ++ case '0': ++ var->enabled = 0; ++ break; ++ case '1': ++ var->enabled = 1; ++ } ++ } ++ ++ return (int) length; ++} ++ ++ ++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 condition6_info *info = ++ (const struct condition6_info *) matchinfo; ++ struct condition_variable *var; ++ int condition_status = 0; ++ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ condition_status = var->enabled; ++ break; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ return condition_status ^ info->invert; ++} ++ ++ ++ ++static int ++checkentry(const char *tablename, const struct ip6t_ip6 *ip, ++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++ struct condition6_info *info = ++ (struct condition6_info *) matchinfo; ++ struct condition_variable *var, *newvar; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) ++ return 0; ++ ++ /* The first step is to check if the condition variable already exists. */ ++ /* Here, a read lock is sufficient because we won't change the list */ ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ ++ /* At this point, we need to allocate a new condition variable */ ++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); ++ ++ if (!newvar) ++ return -ENOMEM; ++ ++ /* Create the condition variable's proc file entry */ ++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); ++ ++ if (!newvar->status_proc) { ++ /* ++ * There are two possibilities: ++ * 1- Another condition variable with the same name has been created, which is valid. ++ * 2- There was a memory allocation error. ++ */ ++ kfree(newvar); ++ read_lock(&list_lock); ++ ++ for (var = head; var; var = var->next) { ++ if (strcmp(info->name, var->status_proc->name) == 0) { ++ atomic_inc(&var->refcount); ++ read_unlock(&list_lock); ++ return 1; ++ } ++ } ++ ++ read_unlock(&list_lock); ++ return -ENOMEM; ++ } ++ ++ atomic_set(&newvar->refcount, 1); ++ newvar->enabled = 0; ++ newvar->status_proc->owner = THIS_MODULE; ++ newvar->status_proc->data = newvar; ++ wmb(); ++ newvar->status_proc->read_proc = ipt_condition_read_info; ++ newvar->status_proc->write_proc = ipt_condition_write_info; ++ ++ write_lock(&list_lock); ++ ++ newvar->next = head; ++ head = newvar; ++ ++ write_unlock(&list_lock); ++ ++ return 1; ++} ++ ++ ++static void ++destroy(void *matchinfo, unsigned int matchsize) ++{ ++ struct condition6_info *info = ++ (struct condition6_info *) matchinfo; ++ struct condition_variable *var, *prev = NULL; ++ ++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) ++ return; ++ ++ write_lock(&list_lock); ++ ++ for (var = head; var && strcmp(info->name, var->status_proc->name); ++ prev = var, var = var->next); ++ ++ if (var && atomic_dec_and_test(&var->refcount)) { ++ if (prev) ++ prev->next = var->next; ++ else ++ head = var->next; ++ ++ write_unlock(&list_lock); ++ remove_proc_entry(var->status_proc->name, proc_net_condition); ++ kfree(var); ++ } else ++ write_unlock(&list_lock); ++} ++ ++ ++static struct ip6t_match condition_match = { ++ .name = "condition", ++ .match = &match, ++ .checkentry = &checkentry, ++ .destroy = &destroy, ++ .me = THIS_MODULE ++}; ++ ++ ++static int __init ++init(void) ++{ ++ int errorcode; ++ ++ rwlock_init(&list_lock); ++ proc_net_condition = proc_mkdir("ip6t_condition", proc_net); ++ ++ if (proc_net_condition) { ++ errorcode = ipt_register_match(&condition_match); ++ ++ if (errorcode) ++ remove_proc_entry("ip6t_condition", proc_net); ++ } else ++ errorcode = -EACCES; ++ ++ return errorcode; ++} ++ ++ ++static void __exit ++fini(void) ++{ ++ ipt_unregister_match(&condition_match); ++ remove_proc_entry("ip6t_condition", proc_net); ++} ++ ++module_init(init); ++module_exit(fini); diff --git a/target/linux/linux-2.4/patches/generic/612-netfilter_quota.patch b/target/linux/linux-2.4/patches/generic/612-netfilter_quota.patch new file mode 100644 index 000000000..a0a019c17 --- /dev/null +++ b/target/linux/linux-2.4/patches/generic/612-netfilter_quota.patch @@ -0,0 +1,147 @@ +diff -ruN linux-2.4.30-old/Documentation/Configure.help linux-2.4.30-new/Documentation/Configure.help +--- linux-2.4.30-old/Documentation/Configure.help 2005-11-13 22:30:42.000000000 +0100 ++++ linux-2.4.30-new/Documentation/Configure.help 2005-11-13 22:31:17.000000000 +0100 +@@ -2888,6 +2888,13 @@ + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + ++quota match support ++CONFIG_IP_NF_MATCH_QUOTA ++ This match implements network quotas. ++ ++ If you want to compile it as a module, say M here and read ++ Documentation/modules.txt. If unsure, say `N'. ++ + skb->pkt_type packet match support + CONFIG_IP_NF_MATCH_PKTTYPE + This patch allows you to match packet in accrodance +diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_quota.h linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_quota.h +--- linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_quota.h 2005-11-13 22:31:17.000000000 +0100 +@@ -0,0 +1,12 @@ ++#ifndef _IPT_QUOTA_H ++#define _IPT_QUOTA_H ++ ++/* print debug info in both kernel/netfilter module & iptable library */ ++//#define DEBUG_IPT_QUOTA ++ ++struct ipt_quota_info { ++ u_int64_t quota; ++ struct ipt_quota_info *master; ++}; ++ ++#endif /*_IPT_QUOTA_H*/ +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Config.in linux-2.4.30-new/net/ipv4/netfilter/Config.in +--- linux-2.4.30-old/net/ipv4/netfilter/Config.in 2005-11-13 22:30:42.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/Config.in 2005-11-13 22:31:17.000000000 +0100 +@@ -24,6 +24,7 @@ + if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then + # The simple matches. + dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES + + dep_tristate ' IP set support' CONFIG_IP_NF_SET $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_SET" != "n" ]; then +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Makefile linux-2.4.30-new/net/ipv4/netfilter/Makefile +--- linux-2.4.30-old/net/ipv4/netfilter/Makefile 2005-11-13 22:30:42.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/Makefile 2005-11-13 22:31:17.000000000 +0100 +@@ -74,6 +74,7 @@ + # matches + obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o + obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o ++obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o + obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o + obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o + obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o +diff -ruN linux-2.4.30-old/net/ipv4/netfilter/ipt_quota.c linux-2.4.30-new/net/ipv4/netfilter/ipt_quota.c +--- linux-2.4.30-old/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30-new/net/ipv4/netfilter/ipt_quota.c 2005-11-13 22:31:17.000000000 +0100 +@@ -0,0 +1,88 @@ ++/* ++ * netfilter module to enforce network quotas ++ * ++ * Sam Johnston ++ * ++ * 30/01/05: Fixed on SMP --Pablo Neira ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; ++ ++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) ++{ ++ struct ipt_quota_info *q = ++ ((struct ipt_quota_info *) matchinfo)->master; ++ ++ spin_lock_bh("a_lock); ++ ++ if (q->quota >= datalen) { ++ /* we can afford this one */ ++ q->quota -= datalen; ++ spin_unlock_bh("a_lock); ++ ++#ifdef DEBUG_IPT_QUOTA ++ printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); ++#endif ++ return 1; ++ } ++ ++ /* so we do not allow even small packets from now on */ ++ q->quota = 0; ++ ++#ifdef DEBUG_IPT_QUOTA ++ printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen); ++#endif ++ ++ spin_unlock_bh("a_lock); ++ return 0; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) ++{ ++ /* TODO: spinlocks? sanity checks? */ ++ struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; ++ ++ if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info))) ++ return 0; ++ ++ /* For SMP, we only want to use one set of counters. */ ++ q->master = q; ++ ++ return 1; ++} ++ ++static struct ipt_match quota_match ++ = { {NULL, NULL}, "quota", &match, &checkentry, NULL, THIS_MODULE }; ++ ++static int __init ++init(void) ++{ ++ return ipt_register_match("a_match); ++} ++ ++static void __exit ++fini(void) ++{ ++ ipt_unregister_match("a_match); ++} ++ ++module_init(init); ++module_exit(fini); ++ diff --git a/target/linux/netfilter.mk b/target/linux/netfilter.mk index 6375a71f2..69f1dd5e7 100644 --- a/target/linux/netfilter.mk +++ b/target/linux/netfilter.mk @@ -12,14 +12,18 @@ IPKG_KMOD_IPT_CONNTRACK-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK IPKG_KMOD_IPT_CONNTRACK-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state IPKG_KMOD_IPT_EXTRA-m := +IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition +IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_MULTIPORT) += multiport IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype +IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT +IPKG_KMOD_IPT_EXTRA-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string IPKG_KMOD_IPT_FILTER-m := IPKG_KMOD_IPT_FILTER-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p @@ -81,14 +85,18 @@ IPKG_IPTABLES_MOD_CONNTRACK-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper IPKG_IPTABLES_MOD_CONNTRACK-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state IPKG_IPTABLES_MOD_EXTRA-m := +IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition +IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype +IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT +IPKG_IPTABLES_MOD_EXTRA-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string IPKG_IPTABLES_MOD_FILTER-m := IPKG_IPTABLES_MOD_FILTER-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p