]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- netfilter pending/base snap 2004 09 07.
authorcieciwa <cieciwa@pld-linux.org>
Tue, 7 Sep 2004 12:26:36 +0000 (12:26 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    2.6.7-pom-ng-20040907.patch -> 1.1

2.6.7-pom-ng-20040907.patch [new file with mode: 0644]

diff --git a/2.6.7-pom-ng-20040907.patch b/2.6.7-pom-ng-20040907.patch
new file mode 100644 (file)
index 0000000..260d258
--- /dev/null
@@ -0,0 +1,7236 @@
+       info about patch: 
+  Already applied: 
+  updates/01_linux-2.6.4.patch 
+  updates/02_iptables-1.2.11-multi.patch 
+  updates/02_linux-2.6.5.patch 
+  updates/03_linux-2.6.6.patch 
+  updates/04_linux-2.6.6-helper_reassign.patch 
+  updates/05_linux-2.6.6-orphaned_expect.patch 
+  updates/06_linux-2.6.6-skb_len_check.patch 
+  updates/07_linux-2.6.7.patch 
+  updates/08_linux-2.6.7-user_attr.patch 
+  updates/09_linux-2.6.7-ipt_LOG_doff_fix.patch 
+  updates/10_linux-2.6.7-tcp_opt.patch 
+  pending/CLASSIFY_more-hooks amanda_offset-fix 
+  pending/conntrack-acct 
+  pending/conntrack-cacheline-opt 
+  pending/conntrack-seqfile 
+  pending/conntrack_error-api 
+  pending/early-drop-norandom 
+  pending/expect-evict-order 
+  pending/expect-slab-cache 
+  pending/init_conntrack-optimize 
+  pending/ip_nat_helper_static 
+  pending/ip_queue_nonlinear_skbs 
+  pending/ipt_helper-invert-fix 
+  pending/mangle-reroute 
+  pending/nf_reset 
+  pending/owner-broken 
+  pending/proc_net_conntrack-permissions 
+  pending/proc-no-internal-targets 
+  pending/sctp 
+  base/HOPLIMIT 
+  base/IPV4OPTSSTRIP  + require fix: s/<linux/ip.h>/<net/ip.h>/ in net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
+  base/NETMAP 
+  base/REJECT 
+  base/SAME 
+  base/TTL 
+  base/connlimit 
+  base/dstlimit 
+  base/fuzzy 
+  base/iprange 
+  base/ipv4options 
+  base/mport 
+  base/nf-log 
+  base/nth 
+  base/osf 
+  base/psd 
+  base/quota 
+  base/raw 
+  base/realm 
+  base/time
+  base/u32
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack.h        2004-09-07 12:07:45.184838544 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack.h    2004-09-07 12:32:45.881697944 +0200
+@@ -156,6 +156,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
+@@ -164,15 +170,17 @@
+            plus 1 for any connection(s) we are `master' for */
+       struct nf_conntrack ct_general;
+-      /* These are my tuples; original and reply */
+-      struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+-
+       /* Have we seen traffic both ways yet? (bitset) */
+       unsigned long status;
+       /* Timer function; drops refcnt when it goes off. */
+       struct timer_list timeout;
++#ifdef CONFIG_IP_NF_CT_ACCT
++      /* 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;
+@@ -207,6 +215,9 @@
+       } nat;
+ #endif /* CONFIG_IP_NF_NAT_NEEDED */
++      /* Traversed often, so hopefully in different cacheline to top */
++      /* These are my tuples; original and reply */
++      struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
+ };
+ /* get master conntrack via master expectation */
+@@ -245,8 +256,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 sk_buff *skb,
++                             unsigned long extra_jiffies);
+ /* These are for NAT.  Icky. */
+ /* Call me when a conntrack is destroyed. */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack_core.h linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack_core.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack_core.h   2004-09-07 12:07:45.184838544 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack_core.h       2004-09-07 12:32:47.916388624 +0200
+@@ -21,15 +21,17 @@
+ extern struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol);
+ extern struct list_head protocol_list;
+-/* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
+-extern struct ip_conntrack *icmp_error_track(struct sk_buff *skb,
+-                                           enum ip_conntrack_info *ctinfo,
+-                                           unsigned int hooknum);
+-extern int get_tuple(const struct iphdr *iph,
+-                   const struct sk_buff *skb,
+-                   unsigned int dataoff,
+-                   struct ip_conntrack_tuple *tuple,
+-                   const struct ip_conntrack_protocol *protocol);
++extern int
++ip_ct_get_tuple(const struct iphdr *iph,
++              const struct sk_buff *skb,
++              unsigned int dataoff,
++              struct ip_conntrack_tuple *tuple,
++              const struct ip_conntrack_protocol *protocol);
++
++extern int
++ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
++                 const struct ip_conntrack_tuple *orig,
++                 const struct ip_conntrack_protocol *protocol);
+ /* Find a connection corresponding to a tuple. */
+ struct ip_conntrack_tuple_hash *
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ip_conntrack_protocol.h       2004-09-07 12:07:45.184838544 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv4/ip_conntrack_protocol.h   2004-09-07 12:32:47.917388472 +0200
+@@ -3,6 +3,11 @@
+ #define _IP_CONNTRACK_PROTOCOL_H
+ #include <linux/netfilter_ipv4/ip_conntrack.h>
++/* length of buffer to which print_tuple/print_conntrack members are
++ * writing */
++
++#define IP_CT_PRINT_BUFLEN 100
++
+ struct ip_conntrack_protocol
+ {
+       /* Next pointer. */
+@@ -50,6 +55,9 @@
+       int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
+                              const struct sk_buff *skb);
++      int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
++                   unsigned int hooknum);
++
+       /* Module (if any) which this is connected to. */
+       struct module *me;
+ };
+@@ -63,4 +71,17 @@
+ extern struct ip_conntrack_protocol ip_conntrack_protocol_udp;
+ extern struct ip_conntrack_protocol ip_conntrack_protocol_icmp;
+ extern int ip_conntrack_protocol_tcp_init(void);
++
++/* Log invalid packets */
++extern unsigned int ip_ct_log_invalid;
++
++#ifdef DEBUG_INVALID_PACKETS
++#define LOG_INVALID(proto) \
++      (ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW)
++#else
++#define LOG_INVALID(proto) \
++      ((ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW) \
++       && net_ratelimit())
++#endif
++
+ #endif /*_IP_CONNTRACK_PROTOCOL_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.6.7/include/linux/netfilter_ipv4/ip_nat_helper.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ip_nat_helper.h       2004-09-07 12:07:45.156842800 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv4/ip_nat_helper.h   2004-09-07 12:32:56.182132040 +0200
+@@ -38,11 +38,12 @@
+                              struct ip_nat_info *info);
+ };
+-extern struct list_head helpers;
+-
+ extern int ip_nat_helper_register(struct ip_nat_helper *me);
+ extern void ip_nat_helper_unregister(struct ip_nat_helper *me);
++extern struct ip_nat_helper *
++ip_nat_find_helper(const struct ip_conntrack_tuple *tuple);
++
+ /* These return true or false. */
+ extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+                               struct ip_conntrack *ct,
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.7/include/linux/netfilter_ipv4/ip_tables.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ip_tables.h   2004-09-07 12:07:45.184838544 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv4/ip_tables.h       2004-09-07 12:32:37.051040408 +0200
+@@ -336,6 +336,7 @@
+  *    Main firewall chains definitions and global var's definitions.
+  */
+ #ifdef __KERNEL__
++extern struct semaphore ipt_mutex;
+ static DECLARE_MUTEX(ipt_mutex);
+ #include <linux/init.h>
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_TTL.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_TTL.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_TTL.h 2004-09-07 12:33:09.040177320 +0200
+@@ -0,0 +1,21 @@
++/* TTL modification module for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
++
++#ifndef _IPT_TTL_H
++#define _IPT_TTL_H
++
++enum {
++      IPT_TTL_SET = 0,
++      IPT_TTL_INC,
++      IPT_TTL_DEC
++};
++
++#define IPT_TTL_MAXMODE       IPT_TTL_DEC
++
++struct ipt_TTL_info {
++      u_int8_t        mode;
++      u_int8_t        ttl;
++};
++
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_connlimit.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_connlimit.h       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_connlimit.h   2004-09-07 12:33:10.090017720 +0200
+@@ -0,0 +1,12 @@
++#ifndef _IPT_CONNLIMIT_H
++#define _IPT_CONNLIMIT_H
++
++struct ipt_connlimit_data;
++
++struct ipt_connlimit_info {
++      int limit;
++      int inverse;
++      u_int32_t mask;
++      struct ipt_connlimit_data *data;
++};
++#endif /* _IPT_CONNLIMIT_H */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_dstlimit.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_dstlimit.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_dstlimit.h    2004-09-07 12:33:11.098864352 +0200
+@@ -0,0 +1,39 @@
++#ifndef _IPT_DSTLIMIT_H
++#define _IPT_DSTLIMIT_H
++
++/* timings are in milliseconds. */
++#define IPT_DSTLIMIT_SCALE 10000
++/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
++   seconds, or one every 59 hours. */
++
++/* details of this structure hidden by the implementation */
++struct ipt_dstlimit_htable;
++
++#define IPT_DSTLIMIT_HASH_DIP 0x0001
++#define IPT_DSTLIMIT_HASH_DPT 0x0002
++#define IPT_DSTLIMIT_HASH_SIP 0x0004
++
++struct dstlimit_cfg {
++      u_int32_t mode;   /* bitmask of IPT_DSTLIMIT_HASH_* */
++      u_int32_t avg;    /* Average secs between packets * scale */
++      u_int32_t burst;  /* Period multiplier for upper limit. */
++
++      /* user specified */
++      u_int32_t size;         /* how many buckets */
++      u_int32_t max;          /* max number of entries */
++      u_int32_t gc_interval;  /* gc interval */
++      u_int32_t expire;       /* when do entries expire? */
++};
++
++struct ipt_dstlimit_info {
++      char name [IFNAMSIZ];           /* name */
++      struct dstlimit_cfg cfg;
++      struct ipt_dstlimit_htable *hinfo;
++
++      /* Used internally by the kernel */
++      union {
++              void *ptr;
++              struct ipt_dstlimit_info *master;
++      } u;
++};
++#endif /*_IPT_DSTLIMIT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_fuzzy.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_fuzzy.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_fuzzy.h       2004-09-07 12:33:12.079715240 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IPT_FUZZY_H
++#define _IPT_FUZZY_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#define MAXFUZZYRATE 10000000
++#define MINFUZZYRATE 3
++
++struct ipt_fuzzy_info {
++      u_int32_t minimum_rate;
++      u_int32_t maximum_rate;
++      u_int32_t packets_total;
++      u_int32_t bytes_total;
++      u_int32_t previous_time;
++      u_int32_t present_time;
++      u_int32_t mean_rate;
++      u_int8_t acceptance_rate;
++};
++
++#endif /*_IPT_FUZZY_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_ipv4options.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_ipv4options.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-09-07 12:33:15.333220632 +0200
+@@ -0,0 +1,21 @@
++#ifndef __ipt_ipv4options_h_included__
++#define __ipt_ipv4options_h_included__
++
++#define IPT_IPV4OPTION_MATCH_SSRR             0x01  /* For strict source routing */
++#define IPT_IPV4OPTION_MATCH_LSRR             0x02  /* For loose source routing */
++#define IPT_IPV4OPTION_DONT_MATCH_SRR         0x04  /* any source routing */
++#define IPT_IPV4OPTION_MATCH_RR                       0x08  /* For Record route */
++#define IPT_IPV4OPTION_DONT_MATCH_RR          0x10
++#define IPT_IPV4OPTION_MATCH_TIMESTAMP                0x20  /* For timestamp request */
++#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP   0x40
++#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT     0x80  /* For router-alert */
++#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT        0x100
++#define IPT_IPV4OPTION_MATCH_ANY_OPT          0x200 /* match packet with any option */
++#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT     0x400 /* match packet with no option */
++
++struct ipt_ipv4options_info {
++      u_int16_t options;
++};
++
++
++#endif /* __ipt_ipv4options_h_included__ */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_mport.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_mport.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_mport.h       2004-09-07 12:33:16.383061032 +0200
+@@ -0,0 +1,24 @@
++#ifndef _IPT_MPORT_H
++#define _IPT_MPORT_H
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#define IPT_MPORT_SOURCE (1<<0)
++#define IPT_MPORT_DESTINATION (1<<1)
++#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
++
++#define IPT_MULTI_PORTS       15
++
++/* Must fit inside union ipt_matchinfo: 32 bytes */
++/* every entry in ports[] except for the last one has one bit in pflags
++ * associated with it. If this bit is set, the port is the first port of
++ * a portrange, with the next entry being the last.
++ * End of list is marked with pflags bit set and port=65535.
++ * If 14 ports are used (last one does not have a pflag), the last port
++ * is repeated to fill the last entry in ports[] */
++struct ipt_mport
++{
++      u_int8_t flags:2;                       /* Type of comparison */
++      u_int16_t pflags:14;                    /* Port flags */
++      u_int16_t ports[IPT_MULTI_PORTS];       /* Ports */
++};
++#endif /*_IPT_MPORT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_nth.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_nth.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_nth.h 2004-09-07 12:33:17.546884104 +0200
+@@ -0,0 +1,19 @@
++#ifndef _IPT_NTH_H
++#define _IPT_NTH_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#ifndef IPT_NTH_NUM_COUNTERS
++#define IPT_NTH_NUM_COUNTERS 16
++#endif
++
++struct ipt_nth_info {
++      u_int8_t every;
++      u_int8_t not;
++      u_int8_t startat;
++      u_int8_t counter;
++      u_int8_t packet;
++};
++
++#endif /*_IPT_NTH_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_osf.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_osf.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_osf.h 2004-09-07 12:33:18.674712648 +0200
+@@ -0,0 +1,149 @@
++/*
++ * ipt_osf.h
++ *
++ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
++ *
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _IPT_OSF_H
++#define _IPT_OSF_H
++
++#define MAXGENRELEN            32
++#define MAXDETLEN              64
++
++#define IPT_OSF_GENRE          1
++#define        IPT_OSF_SMART           2
++#define IPT_OSF_LOG            4
++#define IPT_OSF_NETLINK                8
++
++#define IPT_OSF_LOGLEVEL_ALL   0
++#define IPT_OSF_LOGLEVEL_FIRST 1
++
++#include <linux/list.h>
++#include <net/tcp.h>
++
++#ifndef __KERNEL__
++#include <netinet/ip.h>
++#include <netinet/tcp.h>
++
++struct list_head
++{
++       struct list_head *prev, *next;
++};
++#endif
++
++struct ipt_osf_info
++{
++       char                    genre[MAXGENRELEN];
++       int                     len;
++       unsigned long           flags;
++       int                     loglevel;
++       int                     invert; /* UNSUPPORTED */
++};
++
++struct osf_wc
++{
++       char                    wc;
++       unsigned long           val;
++};
++
++/* This struct represents IANA options
++ * http://www.iana.org/assignments/tcp-parameters
++ */
++struct osf_opt
++{
++       unsigned char           kind;
++       unsigned char           length;
++       struct osf_wc           wc;
++};
++
++struct osf_finger
++{
++       struct list_head        flist;
++       struct osf_wc           wss;
++       unsigned char           ttl;
++       unsigned char           df;
++       unsigned long           ss;
++       unsigned char           genre[MAXGENRELEN];
++       unsigned char           version[MAXGENRELEN], subtype[MAXGENRELEN];
++
++       /* Not needed, but for consistency with original table from Michal Zalewski */
++       unsigned char           details[MAXDETLEN]; 
++
++       int                     opt_num;
++       struct osf_opt          opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
++
++};
++
++struct ipt_osf_nlmsg
++{
++       struct osf_finger       f;
++       struct iphdr            ip;
++       struct tcphdr           tcp;
++};
++
++#ifdef __KERNEL__
++
++/* Defines for IANA option kinds */
++
++#define OSFOPT_EOL             0       /* End of options */
++#define OSFOPT_NOP             1       /* NOP */
++#define OSFOPT_MSS             2       /* Maximum segment size */
++#define OSFOPT_WSO             3       /* Window scale option */
++#define OSFOPT_SACKP           4       /* SACK permitted */
++#define OSFOPT_SACK            5       /* SACK */
++#define OSFOPT_ECHO            6
++#define OSFOPT_ECHOREPLY       7
++#define OSFOPT_TS              8       /* Timestamp option */
++#define OSFOPT_POCP            9       /* Partial Order Connection Permitted */
++#define OSFOPT_POSP            10      /* Partial Order Service Profile */
++/* Others are not used in current OSF */
++
++static struct osf_opt IANA_opts[] = 
++{
++       {0, 1,},
++       {1, 1,},
++       {2, 4,},
++       {3, 3,},
++       {4, 2,},
++       {5, 1 ,}, /* SACK length is not defined */
++       {6, 6,},
++       {7, 6,},
++       {8, 10,},
++       {9, 2,},
++       {10, 3,},
++       {11, 1,}, /* CC: Suppose 1 */
++       {12, 1,}, /* the same */
++       {13, 1,}, /* and here too */
++       {14, 3,},
++       {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
++       {16, 1,},
++       {17, 1,},
++       {18, 3,},
++       {19, 18,},
++       {20, 1,},
++       {21, 1,},
++       {22, 1,},
++       {23, 1,},
++       {24, 1,},
++       {25, 1,},
++       {26, 1,},
++};
++
++#endif /* __KERNEL__ */
++
++#endif /* _IPT_OSF_H */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_psd.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_psd.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_psd.h 2004-09-07 12:33:19.723553200 +0200
+@@ -0,0 +1,40 @@
++#ifndef _IPT_PSD_H
++#define _IPT_PSD_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++/*
++ * High port numbers have a lower weight to reduce the frequency of false
++ * positives, such as from passive mode FTP transfers.
++ */
++#define PORT_WEIGHT_PRIV              3
++#define PORT_WEIGHT_HIGH              1
++
++/*
++ * Port scan detection thresholds: at least COUNT ports need to be scanned
++ * from the same source, with no longer than DELAY ticks between ports.
++ */
++#define SCAN_MIN_COUNT                        7
++#define SCAN_MAX_COUNT                        (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
++#define SCAN_WEIGHT_THRESHOLD         SCAN_MAX_COUNT
++#define SCAN_DELAY_THRESHOLD          (300) /* old usage of HZ here was erroneously and broke under uml */
++
++/*
++ * Keep track of up to LIST_SIZE source addresses, using a hash table of
++ * HASH_SIZE entries for faster lookups, but limiting hash collisions to
++ * HASH_MAX source addresses per the same hash value.
++ */
++#define LIST_SIZE                     0x100
++#define HASH_LOG                      9
++#define HASH_SIZE                     (1 << HASH_LOG)
++#define HASH_MAX                      0x10
++
++struct ipt_psd_info {
++      unsigned int weight_threshold;
++      unsigned int delay_threshold;
++      unsigned short lo_ports_weight;
++      unsigned short hi_ports_weight;
++};
++
++#endif /*_IPT_PSD_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_quota.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_quota.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_quota.h       2004-09-07 12:33:20.689406368 +0200
+@@ -0,0 +1,11 @@
++#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;
++};
++
++#endif /*_IPT_QUOTA_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_sctp.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_sctp.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_sctp.h        2004-09-07 12:33:05.389732272 +0200
+@@ -0,0 +1,107 @@
++#ifndef _IPT_SCTP_H_
++#define _IPT_SCTP_H_
++
++#define IPT_SCTP_SRC_PORTS            0x01
++#define IPT_SCTP_DEST_PORTS           0x02
++#define IPT_SCTP_CHUNK_TYPES          0x04
++
++#define IPT_SCTP_VALID_FLAGS          0x07
++
++#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
++
++
++struct ipt_sctp_flag_info {
++      u_int8_t chunktype;
++      u_int8_t flag;
++      u_int8_t flag_mask;
++};
++
++#define IPT_NUM_SCTP_FLAGS    4
++
++struct ipt_sctp_info {
++      u_int16_t dpts[2];  /* Min, Max */
++      u_int16_t spts[2];  /* Min, Max */
++
++      u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
++
++#define SCTP_CHUNK_MATCH_ANY   0x01  /* Match if any of the chunk types are present */
++#define SCTP_CHUNK_MATCH_ALL   0x02  /* Match if all of the chunk types are present */
++#define SCTP_CHUNK_MATCH_ONLY  0x04  /* Match if these are the only chunk types present */
++
++      u_int32_t chunk_match_type;
++      struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
++      int flag_count;
++
++      u_int32_t flags;
++      u_int32_t invflags;
++};
++
++#define bytes(type) (sizeof(type) * 8)
++
++#define SCTP_CHUNKMAP_SET(chunkmap, type)             \
++      do {                                            \
++              chunkmap[type / bytes(u_int32_t)] |=    \
++                      1 << (type % bytes(u_int32_t)); \
++      } while (0)
++
++#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)                   \
++      do {                                                    \
++              chunkmap[type / bytes(u_int32_t)] &=            \
++                      ~(1 << (type % bytes(u_int32_t)));      \
++      } while (0)
++
++#define SCTP_CHUNKMAP_IS_SET(chunkmap, type)                  \
++({                                                            \
++      (chunkmap[type / bytes (u_int32_t)] &                   \
++              (1 << (type % bytes (u_int32_t)))) ? 1: 0;      \
++})
++
++#define SCTP_CHUNKMAP_RESET(chunkmap)                                 \
++      do {                                                    \
++              int i;                                          \
++              for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
++                      chunkmap[i] = 0;                        \
++      } while (0)
++
++#define SCTP_CHUNKMAP_SET_ALL(chunkmap)                       \
++      do {                                                    \
++              int i;                                          \
++              for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
++                      chunkmap[i] = ~0;                       \
++      } while (0)
++
++#define SCTP_CHUNKMAP_COPY(destmap, srcmap)                   \
++      do {                                                    \
++              int i;                                          \
++              for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
++                      destmap[i] = srcmap[i];                 \
++      } while (0)
++
++#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap)              \
++({                                                    \
++      int i;                                          \
++      int flag = 1;                                   \
++      for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
++              if (chunkmap[i]) {                      \
++                      flag = 0;                       \
++                      break;                          \
++              }                                       \
++      }                                               \
++        flag;                                         \
++})
++
++#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)            \
++({                                                    \
++      int i;                                          \
++      int flag = 1;                                   \
++      for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
++              if (chunkmap[i] != ~0) {                \
++                      flag = 0;                       \
++                              break;                  \
++              }                                       \
++      }                                               \
++        flag;                                         \
++})
++
++#endif /* _IPT_SCTP_H_ */
++
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_time.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_time.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_time.h        2004-09-07 12:33:22.072196152 +0200
+@@ -0,0 +1,15 @@
++#ifndef __ipt_time_h_included__
++#define __ipt_time_h_included__
++
++
++struct ipt_time_info {
++      u_int8_t  days_match;   /* 1 bit per day. -SMTWTFS                      */
++      u_int16_t time_start;   /* 0 < time_start < 23*60+59 = 1439             */
++      u_int16_t time_stop;    /* 0:0 < time_stat < 23:59                      */
++      u_int8_t  kerneltime;   /* ignore skb time (and use kerneltime) or not. */
++      time_t    date_start;
++      time_t    date_stop;
++};
++
++
++#endif /* __ipt_time_h_included__ */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.7/include/linux/netfilter_ipv4/ipt_u32.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv4/ipt_u32.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv4/ipt_u32.h 2004-09-07 12:38:33.376870648 +0200
+@@ -0,0 +1,40 @@
++#ifndef _IPT_U32_H
++#define _IPT_U32_H
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++enum ipt_u32_ops
++{
++      IPT_U32_AND,
++      IPT_U32_LEFTSH,
++      IPT_U32_RIGHTSH,
++      IPT_U32_AT
++};
++
++struct ipt_u32_location_element
++{
++      u_int32_t number;
++      u_int8_t nextop;
++};
++struct ipt_u32_value_element
++{
++      u_int32_t min;
++      u_int32_t max;
++};
++/* *** any way to allow for an arbitrary number of elements?
++   for now I settle for a limit of 10 of each */
++#define U32MAXSIZE 10
++struct ipt_u32_test
++{
++      u_int8_t nnums;
++      struct ipt_u32_location_element location[U32MAXSIZE+1];
++      u_int8_t nvalues;
++      struct ipt_u32_value_element value[U32MAXSIZE+1];
++};
++
++struct ipt_u32
++{
++      u_int8_t ntests;
++      struct ipt_u32_test tests[U32MAXSIZE+1];
++};
++
++#endif /*_IPT_U32_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.7/include/linux/netfilter_ipv6/ip6t_HL.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_HL.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv6/ip6t_HL.h 2004-09-07 12:33:06.516560968 +0200
+@@ -0,0 +1,22 @@
++/* Hop Limit modification module for ip6tables
++ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
++ * Based on HW's TTL module */
++
++#ifndef _IP6T_HL_H
++#define _IP6T_HL_H
++
++enum {
++      IP6T_HL_SET = 0,
++      IP6T_HL_INC,
++      IP6T_HL_DEC
++};
++
++#define IP6T_HL_MAXMODE       IP6T_HL_DEC
++
++struct ip6t_HL_info {
++      u_int8_t        mode;
++      u_int8_t        hop_limit;
++};
++
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.7/include/linux/netfilter_ipv6/ip6t_REJECT.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-09-07 12:07:45.155842952 +0200
++++ linux-2.6.7/include/linux/netfilter_ipv6/ip6t_REJECT.h     2004-09-07 12:33:08.262295576 +0200
+@@ -2,15 +2,17 @@
+ #define _IP6T_REJECT_H
+ enum ip6t_reject_with {
+-      IP6T_ICMP_NET_UNREACHABLE,
+-      IP6T_ICMP_HOST_UNREACHABLE,
+-      IP6T_ICMP_PROT_UNREACHABLE,
+-      IP6T_ICMP_PORT_UNREACHABLE,
+-      IP6T_ICMP_ECHOREPLY
++      IP6T_ICMP6_NO_ROUTE,
++      IP6T_ICMP6_ADM_PROHIBITED,
++      IP6T_ICMP6_NOT_NEIGHBOUR,
++      IP6T_ICMP6_ADDR_UNREACH,
++      IP6T_ICMP6_PORT_UNREACH,
++      IP6T_ICMP6_ECHOREPLY,
++      IP6T_TCP_RESET
+ };
+ struct ip6t_reject_info {
+       enum ip6t_reject_with with;      /* reject type */
+ };
+-#endif /*_IPT_REJECT_H*/
++#endif /*_IP6T_REJECT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.7/include/linux/netfilter_ipv6/ip6t_fuzzy.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv6/ip6t_fuzzy.h      2004-09-07 12:33:12.080715088 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IP6T_FUZZY_H
++#define _IP6T_FUZZY_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#define MAXFUZZYRATE 10000000
++#define MINFUZZYRATE 3
++
++struct ip6t_fuzzy_info {
++      u_int32_t minimum_rate;
++      u_int32_t maximum_rate;
++      u_int32_t packets_total;
++      u_int32_t bytes_total;
++      u_int32_t previous_time;
++      u_int32_t present_time;
++      u_int32_t mean_rate;
++      u_int8_t acceptance_rate;
++};
++
++#endif /*_IP6T_FUZZY_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.7/include/linux/netfilter_ipv6/ip6t_nth.h
+--- linux-2.6.7.org/include/linux/netfilter_ipv6/ip6t_nth.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/include/linux/netfilter_ipv6/ip6t_nth.h        2004-09-07 12:33:17.547883952 +0200
+@@ -0,0 +1,19 @@
++#ifndef _IP6T_NTH_H
++#define _IP6T_NTH_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#ifndef IP6T_NTH_NUM_COUNTERS
++#define IP6T_NTH_NUM_COUNTERS 16
++#endif
++
++struct ip6t_nth_info {
++      u_int8_t every;
++      u_int8_t not;
++      u_int8_t startat;
++      u_int8_t counter;
++      u_int8_t packet;
++};
++
++#endif /*_IP6T_NTH_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7.org/include/linux/sysctl.h linux-2.6.7/include/linux/sysctl.h
+--- linux-2.6.7.org/include/linux/sysctl.h     2004-09-07 12:07:45.225832312 +0200
++++ linux-2.6.7/include/linux/sysctl.h 2004-09-07 12:32:47.918388320 +0200
+@@ -410,6 +410,7 @@
+       NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
+       NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
+       NET_IPV4_NF_CONNTRACK_BUCKETS=14,
++      NET_IPV4_NF_CONNTRACK_LOG_INVALID=15,
+ };
+  
+ /* /proc/sys/net/ipv6 */
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/Kconfig linux-2.6.7/net/ipv4/netfilter/Kconfig
+--- linux-2.6.7.org/net/ipv4/netfilter/Kconfig 2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/Kconfig     2004-09-07 12:38:33.380870040 +0200
+@@ -628,5 +628,174 @@
+         If you want to compile it as a module, say M here and read
+         Documentation/modules.txt.  If unsure, say `N'.
++config IP_NF_CT_ACCT
++      bool "Connection tracking flow accounting"
++      depends on IP_NF_CONNTRACK
++
++config IP_NF_MATCH_SCTP
++      tristate  'SCTP protocol match support'
++      depends on IP_NF_IPTABLES
++
++config IP_NF_TARGET_IPV4OPTSSTRIP
++      tristate  'IPV4OPTSSTRIP target support'
++      depends on IP_NF_MANGLE
++      help
++        This option adds an IPV4OPTSSTRIP target.
++        This target allows you to strip all IP options in a packet.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_TARGET_TTL
++      tristate  'TTL target support'
++      depends on IP_NF_MANGLE
++      help
++        This option adds a `TTL' target, which enables the user to set
++        the TTL value or increment / decrement the TTL value by a given
++        amount.
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_CONNLIMIT
++      tristate  'Connections/IP limit match support'
++      depends on IP_NF_IPTABLES
++      help
++        This match allows you to restrict the number of parallel TCP
++        connections to a server per client IP address (or address block).
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_DSTLIMIT
++      tristate  'dstlimit match support'
++      depends on IP_NF_IPTABLES
++
++config IP_NF_MATCH_FUZZY
++      tristate  'fuzzy match support'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a `fuzzy' match, which allows you to match
++        packets according to a fuzzy logic based law.
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_IPV4OPTIONS
++      tristate  'IPV4OPTIONS match support'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a IPV4OPTIONS match.
++        It allows you to filter options like source routing,
++        record route, timestamp and router-altert.
++      
++        If you say Y here, try iptables -m ipv4options --help for more information.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_MPORT
++      tristate  'Multiple port with ranges match support'
++      depends on IP_NF_IPTABLES
++      help
++        This is an enhanced multiport match which supports port
++        ranges as well as single ports.
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_NTH
++      tristate  'Nth match support'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a `Nth' match, which allow you to make
++        rules that match every Nth packet.  By default there are 
++        16 different counters.
++      
++        [options]
++         --every     Nth              Match every Nth packet
++        [--counter]  num              Use counter 0-15 (default:0)
++        [--start]    num              Initialize the counter at the number 'num'
++                                      instead of 0. Must be between 0 and Nth-1
++        [--packet]   num              Match on 'num' packet. Must be between 0
++                                      and Nth-1.
++      
++                                      If --packet is used for a counter than
++                                      there must be Nth number of --packet
++                                      rules, covering all values between 0 and
++                                      Nth-1 inclusively.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_OSF
++      tristate  'OSF match support'
++      depends on IP_NF_IPTABLES
++      help
++      
++        The idea of passive OS fingerprint matching exists for quite a long time,
++        but was created as extension fo OpenBSD pf only some weeks ago.
++        Original idea was lurked in some OpenBSD mailing list (thanks
++        grange@open...) and than adopted for Linux netfilter in form of this code.
++      
++        Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
++        his excellent p0f and than changed a bit for more convenience.
++      
++        This module compares some data(WS, MSS, options and it's order, ttl,
++        df and others) from first SYN packet (actually from packets with SYN
++        bit set) with hardcoded in fingers[] table ones.
++      
++        If you say Y here, try iptables -m osf --help for more information.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_PSD
++      tristate  'psd match support'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a `psd' match, which allows you to create rules in
++        any iptables table wich will detect TCP and UDP port scans.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_QUOTA
++      tristate  'quota match support'
++      depends on IP_NF_IPTABLES
++      help
++        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'.
++      
++
++config IP_NF_MATCH_TIME
++      tristate  'TIME match support'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a `time' match, which allows you
++        to match based on the packet arrival time/date
++        (arrival time/date at the machine which netfilter is running on) or
++        departure time/date (for locally generated packets).
++      
++        If you say Y here, try iptables -m time --help for more information.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP_NF_MATCH_U32
++      tristate  'U32 match support'
++      depends on IP_NF_IPTABLES
++      help
++        U32 allows you to extract quantities of up to 4 bytes from a packet,
++        AND them with specified masks, shift them by specified amounts and
++        test whether the results are in any of a set of specified ranges.
++        The specification of what to extract is general enough to skip over
++        headers with lengths stored in the packet, as in IP or TCP header
++        lengths.
++      
++        Details and examples are in the kernel module source.
++
+ endmenu
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/Makefile linux-2.6.7/net/ipv4/netfilter/Makefile
+--- linux-2.6.7.org/net/ipv4/netfilter/Makefile        2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/Makefile    2004-09-07 12:38:33.381869888 +0200
+@@ -43,15 +43,36 @@
+ # 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_DSTLIMIT) += ipt_dstlimit.o
++obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
+ obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+ obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
+ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
++
++obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
++
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o
++
++obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
++
++obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
++
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+@@ -60,8 +81,12 @@
+ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
++obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
++
++
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
++obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+ obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
+@@ -82,6 +107,8 @@
+ obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
++obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+ obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_amanda.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_amanda.c   2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_amanda.c       2004-09-07 12:32:44.773866360 +0200
+@@ -58,7 +58,7 @@
+       /* increase the UDP timeout of the master connection as replies from
+        * Amanda clients to the server can be quite delayed */
+-      ip_ct_refresh(ct, master_timeout * HZ);
++      ip_ct_refresh_acct(ct, ctinfo, NULL, master_timeout * HZ);
+       /* No data? */
+       dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_core.c     2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_core.c 2004-09-07 12:32:54.736351832 +0200
+@@ -58,6 +58,7 @@
+ DECLARE_RWLOCK(ip_conntrack_lock);
+ DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
++static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
+ void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
+ LIST_HEAD(ip_conntrack_expect_list);
+@@ -65,9 +66,9 @@
+ static LIST_HEAD(helpers);
+ unsigned int ip_conntrack_htable_size = 0;
+ int ip_conntrack_max;
+-static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
+ struct list_head *ip_conntrack_hash;
+ static kmem_cache_t *ip_conntrack_cachep;
++static kmem_cache_t *ip_conntrack_expect_cachep;
+ struct ip_conntrack ip_conntrack_untracked;
+ extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
+@@ -127,11 +128,11 @@
+ }
+ int
+-get_tuple(const struct iphdr *iph,
+-        const struct sk_buff *skb,
+-        unsigned int dataoff,
+-        struct ip_conntrack_tuple *tuple,
+-        const struct ip_conntrack_protocol *protocol)
++ip_ct_get_tuple(const struct iphdr *iph,
++              const struct sk_buff *skb,
++              unsigned int dataoff,
++              struct ip_conntrack_tuple *tuple,
++              const struct ip_conntrack_protocol *protocol)
+ {
+       /* Never happen */
+       if (iph->frag_off & htons(IP_OFFSET)) {
+@@ -147,10 +148,10 @@
+       return protocol->pkt_to_tuple(skb, dataoff, tuple);
+ }
+-static int
+-invert_tuple(struct ip_conntrack_tuple *inverse,
+-           const struct ip_conntrack_tuple *orig,
+-           const struct ip_conntrack_protocol *protocol)
++int
++ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
++                 const struct ip_conntrack_tuple *orig,
++                 const struct ip_conntrack_protocol *protocol)
+ {
+       inverse->src.ip = orig->dst.ip;
+       inverse->dst.ip = orig->src.ip;
+@@ -177,7 +178,7 @@
+       IP_NF_ASSERT(atomic_read(&exp->use) == 0);
+       IP_NF_ASSERT(!timer_pending(&exp->timeout));
+-      kfree(exp);
++      kmem_cache_free(ip_conntrack_expect_cachep, exp);
+ }
+ inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
+@@ -336,7 +337,7 @@
+                       list_del(&ct->master->expected_list);
+                       master = ct->master->expectant;
+               }
+-              kfree(ct->master);
++              kmem_cache_free(ip_conntrack_expect_cachep, ct->master);
+       }
+       WRITE_UNLOCK(&ip_conntrack_lock);
+@@ -496,83 +497,6 @@
+       return h != NULL;
+ }
+-/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+-struct ip_conntrack *
+-icmp_error_track(struct sk_buff *skb,
+-               enum ip_conntrack_info *ctinfo,
+-               unsigned int hooknum)
+-{
+-      struct ip_conntrack_tuple innertuple, origtuple;
+-      struct {
+-              struct icmphdr icmp;
+-              struct iphdr ip;
+-      } inside;
+-      struct ip_conntrack_protocol *innerproto;
+-      struct ip_conntrack_tuple_hash *h;
+-      int dataoff;
+-
+-      IP_NF_ASSERT(skb->nfct == NULL);
+-
+-      /* Not enough header? */
+-      if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
+-              return NULL;
+-
+-      if (inside.icmp.type != ICMP_DEST_UNREACH
+-          && inside.icmp.type != ICMP_SOURCE_QUENCH
+-          && inside.icmp.type != ICMP_TIME_EXCEEDED
+-          && inside.icmp.type != ICMP_PARAMETERPROB
+-          && inside.icmp.type != ICMP_REDIRECT)
+-              return NULL;
+-
+-      /* Ignore ICMP's containing fragments (shouldn't happen) */
+-      if (inside.ip.frag_off & htons(IP_OFFSET)) {
+-              DEBUGP("icmp_error_track: fragment of proto %u\n",
+-                     inside.ip.protocol);
+-              return NULL;
+-      }
+-
+-      innerproto = ip_ct_find_proto(inside.ip.protocol);
+-      dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
+-      /* Are they talking about one of our connections? */
+-      if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
+-              DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
+-              return NULL;
+-      }
+-
+-      /* Ordinarily, we'd expect the inverted tupleproto, but it's
+-         been preserved inside the ICMP. */
+-      if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
+-              DEBUGP("icmp_error_track: Can't invert tuple\n");
+-              return NULL;
+-      }
+-
+-      *ctinfo = IP_CT_RELATED;
+-
+-      h = ip_conntrack_find_get(&innertuple, NULL);
+-      if (!h) {
+-              /* Locally generated ICMPs will match inverted if they
+-                 haven't been SNAT'ed yet */
+-              /* FIXME: NAT code has to handle half-done double NAT --RR */
+-              if (hooknum == NF_IP_LOCAL_OUT)
+-                      h = ip_conntrack_find_get(&origtuple, NULL);
+-
+-              if (!h) {
+-                      DEBUGP("icmp_error_track: no match\n");
+-                      return NULL;
+-              }
+-              /* Reverse direction from that found */
+-              if (DIRECTION(h) != IP_CT_DIR_REPLY)
+-                      *ctinfo += IP_CT_IS_REPLY;
+-      } else {
+-              if (DIRECTION(h) == IP_CT_DIR_REPLY)
+-                      *ctinfo += IP_CT_IS_REPLY;
+-      }
+-
+-      /* Update skb to refer to this connection */
+-      skb->nfct = &h->ctrack->infos[*ctinfo];
+-      return h->ctrack;
+-}
+-
+ /* There's a small race here where we may free a just-assured
+    connection.  Too bad: we're in trouble anyway. */
+ static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
+@@ -628,7 +552,6 @@
+       size_t hash;
+       struct ip_conntrack_expect *expected;
+       int i;
+-      static unsigned int drop_next;
+       if (!ip_conntrack_hash_rnd_initted) {
+               get_random_bytes(&ip_conntrack_hash_rnd, 4);
+@@ -637,15 +560,10 @@
+       hash = hash_conntrack(tuple);
+-      if (ip_conntrack_max &&
+-          atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
+-              /* Try dropping from random chain, or else from the
+-                   chain about to put into (in case they're trying to
+-                   bomb one hash chain). */
+-              unsigned int next = (drop_next++)%ip_conntrack_htable_size;
+-
+-              if (!early_drop(&ip_conntrack_hash[next])
+-                  && !early_drop(&ip_conntrack_hash[hash])) {
++      if (ip_conntrack_max
++          && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
++              /* Try dropping from this hash chain. */
++              if (!early_drop(&ip_conntrack_hash[hash])) {
+                       if (net_ratelimit())
+                               printk(KERN_WARNING
+                                      "ip_conntrack: table full, dropping"
+@@ -654,7 +572,7 @@
+               }
+       }
+-      if (!invert_tuple(&repl_tuple, tuple, protocol)) {
++      if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
+               DEBUGP("Can't invert tuple.\n");
+               return NULL;
+       }
+@@ -693,41 +611,48 @@
+                            struct ip_conntrack_expect *, tuple);
+       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+-      /* If master is not in hash table yet (ie. packet hasn't left
+-         this machine yet), how can other end know about expected?
+-         Hence these are not the droids you are looking for (if
+-         master ct never got confirmed, we'd hold a reference to it
+-         and weird things would happen to future packets). */
+-      if (expected && !is_confirmed(expected->expectant))
+-              expected = NULL;
+-
+-      /* Look up the conntrack helper for master connections only */
+-      if (!expected)
+-              conntrack->helper = ip_ct_find_helper(&repl_tuple);
++      if (expected) {
++              /* If master is not in hash table yet (ie. packet hasn't left
++                 this machine yet), how can other end know about expected?
++                 Hence these are not the droids you are looking for (if
++                 master ct never got confirmed, we'd hold a reference to it
++                 and weird things would happen to future packets). */
++              if (!is_confirmed(expected->expectant)) {
++                      conntrack->helper = ip_ct_find_helper(&repl_tuple);
++                      goto end;
++              }
+-      /* If the expectation is dying, then this is a loser. */
+-      if (expected
+-          && expected->expectant->helper->timeout
+-          && ! del_timer(&expected->timeout))
+-              expected = NULL;
++              /* Expectation is dying... */
++              if (expected->expectant->helper->timeout
++                  && !del_timer(&expected->timeout))
++                      goto end;       
+-      if (expected) {
+               DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+                       conntrack, expected);
+               /* Welcome, Mr. Bond.  We've been expecting you... */
++              IP_NF_ASSERT(master_ct(conntrack));
+               __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+               conntrack->master = expected;
+               expected->sibling = conntrack;
+               LIST_DELETE(&ip_conntrack_expect_list, expected);
+               expected->expectant->expecting--;
+               nf_conntrack_get(&master_ct(conntrack)->infos[0]);
+-      }
+-      atomic_inc(&ip_conntrack_count);
++
++              /* this is a braindead... --pablo */
++              atomic_inc(&ip_conntrack_count);
++              WRITE_UNLOCK(&ip_conntrack_lock);
++
++              if (expected->expectfn)
++                      expected->expectfn(conntrack);
++
++              goto ret;
++      } else 
++              conntrack->helper = ip_ct_find_helper(&repl_tuple);
++
++end:  atomic_inc(&ip_conntrack_count);
+       WRITE_UNLOCK(&ip_conntrack_lock);
+-      if (expected && expected->expectfn)
+-              expected->expectfn(conntrack);
+-      return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
++ret:  return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
+ }
+ /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+@@ -743,7 +668,8 @@
+       IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+-      if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
++      if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, 
++                              &tuple,proto))
+               return NULL;
+       /* look for tuple match */
+@@ -828,10 +754,12 @@
+       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+-      /* It may be an icmp error... */
+-      if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
+-          && icmp_error_track(*pskb, &ctinfo, hooknum))
+-              return NF_ACCEPT;
++      /* It may be an special packet, error, unclean...
++       * inverse of the return code tells to the netfilter
++       * core what to do with the packet. */
++      if (proto->error != NULL 
++          && (ret = proto->error(*pskb, &ctinfo, hooknum)) <= 0)
++              return -ret;
+       if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
+               /* Not valid part of a connection */
+@@ -869,7 +797,8 @@
+ int invert_tuplepr(struct ip_conntrack_tuple *inverse,
+                  const struct ip_conntrack_tuple *orig)
+ {
+-      return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
++      return ip_ct_invert_tuple(inverse, orig, 
++                                ip_ct_find_proto(orig->dst.protonum));
+ }
+ static inline int resent_expect(const struct ip_conntrack_expect *i,
+@@ -923,9 +852,8 @@
+ ip_conntrack_expect_alloc(void)
+ {
+       struct ip_conntrack_expect *new;
+-      
+-      new = (struct ip_conntrack_expect *)
+-              kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
++
++      new = kmem_cache_alloc(ip_conntrack_expect_cachep, GFP_ATOMIC);
+       if (!new) {
+               DEBUGP("expect_related: OOM allocating expect\n");
+               return NULL;
+@@ -933,6 +861,7 @@
+       /* tuple_cmp compares whole union, we have to initialized cleanly */
+       memset(new, 0, sizeof(struct ip_conntrack_expect));
++      atomic_set(&new->use, 1);
+       return new;
+ }
+@@ -944,7 +873,6 @@
+       DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+       new->expectant = related_to;
+       new->sibling = NULL;
+-      atomic_set(&new->use, 1);
+       /* add to expected list for this connection */
+       list_add_tail(&new->expected_list, &related_to->sibling_list);
+@@ -997,7 +925,8 @@
+               }
+               WRITE_UNLOCK(&ip_conntrack_lock);
+-              kfree(expect);
++              /* This expectation is not inserted so no need to lock */
++              kmem_cache_free(ip_conntrack_expect_cachep, expect);
+               return -EEXIST;
+       } else if (related_to->helper->max_expected && 
+@@ -1015,7 +944,7 @@
+                                      related_to->helper->name,
+                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
+-                      kfree(expect);
++                      kmem_cache_free(ip_conntrack_expect_cachep, expect);
+                       return -EPERM;
+               }
+               DEBUGP("ip_conntrack: max number of expected "
+@@ -1049,7 +978,7 @@
+               WRITE_UNLOCK(&ip_conntrack_lock);
+               DEBUGP("expect_related: busy!\n");
+-              kfree(expect);
++              kmem_cache_free(ip_conntrack_expect_cachep, expect);
+               return -EBUSY;
+       }
+@@ -1164,21 +1093,39 @@
+       synchronize_net();
+ }
+-/* Refresh conntrack for this many jiffies. */
+-void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
++static inline void ct_add_counters(struct ip_conntrack *ct,
++                                 enum ip_conntrack_info ctinfo,
++                                 const struct sk_buff *skb)
++{
++#ifdef CONFIG_IP_NF_CT_ACCT
++      if (skb) {
++              ct->counters[CTINFO2DIR(ctinfo)].packets++;
++              ct->counters[CTINFO2DIR(ctinfo)].bytes += 
++                                      ntohs(skb->nh.iph->tot_len);
++      }
++#endif
++}
++
++/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */
++void ip_ct_refresh_acct(struct ip_conntrack *ct, 
++                      enum ip_conntrack_info ctinfo,
++                      const struct sk_buff *skb,
++                      unsigned long extra_jiffies)
+ {
+       IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+       /* 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, skb);
++      } else {
+               WRITE_LOCK(&ip_conntrack_lock);
+               /* 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, skb);
+               WRITE_UNLOCK(&ip_conntrack_lock);
+       }
+ }
+@@ -1368,6 +1315,7 @@
+       }
+       kmem_cache_destroy(ip_conntrack_cachep);
++      kmem_cache_destroy(ip_conntrack_expect_cachep);
+       vfree(ip_conntrack_hash);
+       nf_unregister_sockopt(&so_getorigdst);
+ }
+@@ -1420,6 +1368,15 @@
+               printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
+               goto err_free_hash;
+       }
++
++      ip_conntrack_expect_cachep = kmem_cache_create("ip_conntrack_expect",
++                                      sizeof(struct ip_conntrack_expect),
++                                      0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++      if (!ip_conntrack_expect_cachep) {
++              printk(KERN_ERR "Unable to create ip_expect slab cache\n");
++              goto err_free_conntrack_slab;
++      }
++
+       /* Don't NEED lock here, but good form anyway. */
+       WRITE_LOCK(&ip_conntrack_lock);
+       /* Sew in builtin protocols. */
+@@ -1447,6 +1404,8 @@
+       return ret;
++err_free_conntrack_slab:
++      kmem_cache_destroy(ip_conntrack_cachep);
+ err_free_hash:
+       vfree(ip_conntrack_hash);
+ err_unreg_sockopt:
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_generic.c    2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_generic.c        2004-09-07 12:32:47.921387864 +0200
+@@ -50,9 +50,9 @@
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int packet(struct ip_conntrack *conntrack,
+                 const struct sk_buff *skb,
+-                enum ip_conntrack_info conntrackinfo)
++                enum ip_conntrack_info ctinfo)
+ {
+-      ip_ct_refresh(conntrack, ip_ct_generic_timeout);
++      ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout);
+       return NF_ACCEPT;
+ }
+@@ -62,8 +62,14 @@
+       return 1;
+ }
+-struct ip_conntrack_protocol ip_conntrack_generic_protocol
+-= { { NULL, NULL }, 0, "unknown",
+-    generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
+-    generic_print_conntrack, packet, new, NULL, NULL, NULL };
+-
++struct ip_conntrack_protocol ip_conntrack_generic_protocol =
++{
++      .proto                  = 0,
++      .name                   = "unknown",
++      .pkt_to_tuple           = generic_pkt_to_tuple,
++      .invert_tuple           = generic_invert_tuple,
++      .print_tuple            = generic_print_tuple,
++      .print_conntrack        = generic_print_conntrack,
++      .packet                 = packet,
++      .new                    = new,
++};
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_icmp.c       2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_icmp.c   2004-09-07 12:32:47.930386496 +0200
+@@ -12,6 +12,11 @@
+ #include <linux/netfilter.h>
+ #include <linux/in.h>
+ #include <linux/icmp.h>
++#include <net/ip.h>
++#include <net/checksum.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ unsigned long ip_ct_icmp_timeout = 30*HZ;
+@@ -94,7 +99,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, skb, ip_ct_icmp_timeout);
+       }
+       return NF_ACCEPT;
+@@ -122,7 +127,147 @@
+       return 1;
+ }
+-struct ip_conntrack_protocol ip_conntrack_protocol_icmp
+-= { { NULL, NULL }, IPPROTO_ICMP, "icmp",
+-    icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
+-    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
++static int
++icmp_error_message(struct sk_buff *skb,
++                 enum ip_conntrack_info *ctinfo,
++                 unsigned int hooknum)
++{
++      struct ip_conntrack_tuple innertuple, origtuple;
++      struct {
++              struct icmphdr icmp;
++              struct iphdr ip;
++      } inside;
++      struct ip_conntrack_protocol *innerproto;
++      struct ip_conntrack_tuple_hash *h;
++      int dataoff;
++
++      IP_NF_ASSERT(skb->nfct == NULL);
++
++      /* Not enough header? */
++      if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
++              return NF_ACCEPT;
++
++      /* Ignore ICMP's containing fragments (shouldn't happen) */
++      if (inside.ip.frag_off & htons(IP_OFFSET)) {
++              DEBUGP("icmp_error_track: fragment of proto %u\n",
++                     inside.ip.protocol);
++              return NF_ACCEPT;
++      }
++
++      innerproto = ip_ct_find_proto(inside.ip.protocol);
++      dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
++      /* Are they talking about one of our connections? */
++      if (!ip_ct_get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
++              DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
++              return NF_ACCEPT;
++      }
++
++      /* Ordinarily, we'd expect the inverted tupleproto, but it's
++         been preserved inside the ICMP. */
++      if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
++              DEBUGP("icmp_error_track: Can't invert tuple\n");
++              return NF_ACCEPT;
++      }
++
++      *ctinfo = IP_CT_RELATED;
++
++      h = ip_conntrack_find_get(&innertuple, NULL);
++      if (!h) {
++              /* Locally generated ICMPs will match inverted if they
++                 haven't been SNAT'ed yet */
++              /* FIXME: NAT code has to handle half-done double NAT --RR */
++              if (hooknum == NF_IP_LOCAL_OUT)
++                      h = ip_conntrack_find_get(&origtuple, NULL);
++
++              if (!h) {
++                      DEBUGP("icmp_error_track: no match\n");
++                      return NF_ACCEPT;
++              }
++              /* Reverse direction from that found */
++              if (DIRECTION(h) != IP_CT_DIR_REPLY)
++                      *ctinfo += IP_CT_IS_REPLY;
++      } else {
++              if (DIRECTION(h) == IP_CT_DIR_REPLY)
++                      *ctinfo += IP_CT_IS_REPLY;
++      }
++
++      /* Update skb to refer to this connection */
++      skb->nfct = &h->ctrack->infos[*ctinfo];
++      return -NF_ACCEPT;
++}
++
++/* Small and modified version of icmp_rcv */
++static int
++icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
++         unsigned int hooknum)
++{
++      struct icmphdr icmph;
++
++      /* Not enough header? */
++      if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &icmph, sizeof(icmph))!=0) {
++              if (LOG_INVALID(IPPROTO_ICMP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL,
++                                    "ip_ct_icmp: short packet ");
++              return -NF_ACCEPT;
++      }
++
++      /* See ip_conntrack_proto_tcp.c */
++      if (hooknum != NF_IP_PRE_ROUTING)
++              goto checksum_skipped;
++
++      switch (skb->ip_summed) {
++      case CHECKSUM_HW:
++              if (!(u16)csum_fold(skb->csum)) 
++                      break;
++              if (LOG_INVALID(IPPROTO_ICMP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
++                                    "ip_ct_icmp: bad HW ICMP checksum ");
++              return -NF_ACCEPT;
++      case CHECKSUM_NONE:
++              if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
++                      if (LOG_INVALID(IPPROTO_ICMP))
++                              nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
++                                            "ip_ct_icmp: bad ICMP checksum ");
++                      return -NF_ACCEPT;
++              }
++      default:
++              break;
++      }
++
++checksum_skipped:
++      /*
++       *      18 is the highest 'known' ICMP type. Anything else is a mystery
++       *
++       *      RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
++       *                discarded.
++       */
++      if (icmph.type > NR_ICMP_TYPES) {
++              if (LOG_INVALID(IPPROTO_ICMP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL,
++                                    "ip_ct_icmp: invalid ICMP type ");
++              return -NF_ACCEPT;
++      }
++
++      /* Need to track icmp error message? */
++      if (icmph.type != ICMP_DEST_UNREACH
++          && icmph.type != ICMP_SOURCE_QUENCH
++          && icmph.type != ICMP_TIME_EXCEEDED
++          && icmph.type != ICMP_PARAMETERPROB
++          && icmph.type != ICMP_REDIRECT)
++              return NF_ACCEPT;
++
++      return icmp_error_message(skb, ctinfo, hooknum);
++}
++
++struct ip_conntrack_protocol ip_conntrack_protocol_icmp =
++{
++      .proto                  = IPPROTO_ICMP,
++      .name                   = "icmp",
++      .pkt_to_tuple           = icmp_pkt_to_tuple,
++      .invert_tuple           = icmp_invert_tuple,
++      .print_tuple            = icmp_print_tuple,
++      .print_conntrack        = icmp_print_conntrack,
++      .packet                 = icmp_packet,
++      .new                    = icmp_new,
++      .error                  = icmp_error,
++};
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_tcp.c        2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c    2004-09-07 12:32:47.922387712 +0200
+@@ -225,7 +225,7 @@
+               set_bit(IPS_ASSURED_BIT, &conntrack->status);
+ out:  WRITE_UNLOCK(&tcp_lock);
+-      ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
++      ip_ct_refresh_acct(conntrack, ctinfo, skb, *tcp_timeouts[newconntrack]);
+       return NF_ACCEPT;
+ }
+@@ -268,7 +268,15 @@
+       return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
+ }
+-struct ip_conntrack_protocol ip_conntrack_protocol_tcp
+-= { { NULL, NULL }, IPPROTO_TCP, "tcp",
+-    tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
+-    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
++struct ip_conntrack_protocol ip_conntrack_protocol_tcp =
++{
++      .proto                  = IPPROTO_TCP,
++      .name                   = "tcp",
++      .pkt_to_tuple           = tcp_pkt_to_tuple,
++      .invert_tuple           = tcp_invert_tuple,
++      .print_tuple            = tcp_print_tuple,
++      .print_conntrack        = tcp_print_conntrack,
++      .packet                 = tcp_packet,
++      .new                    = tcp_new,
++      .exp_matches_pkt        = tcp_exp_matches_pkt,
++};
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_proto_udp.c        2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_proto_udp.c    2004-09-07 12:32:47.931386344 +0200
+@@ -12,6 +12,8 @@
+ #include <linux/netfilter.h>
+ #include <linux/in.h>
+ #include <linux/udp.h>
++#include <net/checksum.h>
++#include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ unsigned long ip_ct_udp_timeout = 30*HZ;
+@@ -60,16 +62,17 @@
+ /* Returns verdict for packet, and may modify conntracktype */
+ static int udp_packet(struct ip_conntrack *conntrack,
+                     const struct sk_buff *skb,
+-                    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, skb, 
++                                 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, skb, ip_ct_udp_timeout);
+       return NF_ACCEPT;
+ }
+@@ -80,7 +83,60 @@
+       return 1;
+ }
+-struct ip_conntrack_protocol ip_conntrack_protocol_udp
+-= { { NULL, NULL }, IPPROTO_UDP, "udp",
+-    udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
+-    udp_packet, udp_new, NULL, NULL, NULL };
++static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
++                   unsigned int hooknum)
++{
++      struct iphdr *iph = skb->nh.iph;
++      unsigned int udplen = skb->len - iph->ihl * 4;
++      struct udphdr hdr;
++
++      /* Header is too small? */
++      if (skb_copy_bits(skb, iph->ihl*4, &hdr, sizeof(hdr)) != 0) {
++              if (LOG_INVALID(IPPROTO_UDP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
++                                "ip_ct_udp: short packet ");
++              return -NF_ACCEPT;
++      }
++      
++      /* Truncated/malformed packets */
++      if (ntohs(hdr.len) > udplen || ntohs(hdr.len) < sizeof(hdr)) {
++              if (LOG_INVALID(IPPROTO_UDP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
++                                "ip_ct_udp: truncated/malformed packet ");
++              return -NF_ACCEPT;
++      }
++      
++      /* Packet with no checksum */
++      if (!hdr.check)
++              return NF_ACCEPT;
++
++      /* Checksum invalid? Ignore.
++       * We skip checking packets on the outgoing path
++       * because the semantic of CHECKSUM_HW is different there 
++       * and moreover root might send raw packets.
++       * FIXME: Source route IP option packets --RR */
++      if (hooknum == NF_IP_PRE_ROUTING
++          && csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
++                               skb->ip_summed == CHECKSUM_HW ? skb->csum
++                               : skb_checksum(skb, iph->ihl*4, udplen, 0))) {
++              if (LOG_INVALID(IPPROTO_UDP))
++                      nf_log_packet(PF_INET, 0, skb, NULL, NULL, 
++                                "ip_ct_udp: bad UDP checksum ");
++              return -NF_ACCEPT;
++      }
++      
++      return NF_ACCEPT;
++}
++
++struct ip_conntrack_protocol ip_conntrack_protocol_udp =
++{
++      .proto                  = IPPROTO_UDP,
++      .name                   = "udp",
++      .pkt_to_tuple           = udp_pkt_to_tuple,
++      .invert_tuple           = udp_invert_tuple,
++      .print_tuple            = udp_print_tuple,
++      .print_conntrack        = udp_print_conntrack,
++      .packet                 = udp_packet,
++      .new                    = udp_new,
++      .error                  = udp_error,
++};
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.7/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_conntrack_standalone.c       2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_conntrack_standalone.c   2004-09-07 12:32:47.924387408 +0200
+@@ -20,6 +20,7 @@
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/proc_fs.h>
++#include <linux/seq_file.h>
+ #ifdef CONFIG_SYSCTL
+ #include <linux/sysctl.h>
+ #endif
+@@ -63,128 +64,225 @@
+       return len;
+ }
+-/* FIXME: Don't print source proto part. --RR */
++#ifdef CONFIG_IP_NF_CT_ACCT
+ static unsigned int
+-print_expect(char *buffer, const struct ip_conntrack_expect *expect)
++seq_print_counters(struct seq_file *s, struct ip_conntrack_counter *counter)
+ {
+-      unsigned int len;
+-
+-      if (expect->expectant->helper->timeout)
+-              len = sprintf(buffer, "EXPECTING: %lu ",
+-                            timer_pending(&expect->timeout)
+-                            ? (expect->timeout.expires - jiffies)/HZ : 0);
+-      else
+-              len = sprintf(buffer, "EXPECTING: - ");
+-      len += sprintf(buffer + len, "use=%u proto=%u ",
+-                    atomic_read(&expect->use), expect->tuple.dst.protonum);
+-      len += print_tuple(buffer + len, &expect->tuple,
+-                         __ip_ct_find_proto(expect->tuple.dst.protonum));
+-      len += sprintf(buffer + len, "\n");
+-      return len;
++      return seq_printf(s, "packets=%llu bytes=%llu ",
++                        counter->packets, counter->bytes);
+ }
++#else
++#define seq_print_counters(x, y)      0
++#endif
+-static unsigned int
+-print_conntrack(char *buffer, struct ip_conntrack *conntrack)
++static void *ct_seq_start(struct seq_file *s, loff_t *pos)
+ {
+-      unsigned int len;
+-      struct ip_conntrack_protocol *proto
+-              = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+-                             .tuple.dst.protonum);
+-
+-      len = sprintf(buffer, "%-8s %u %lu ",
+-                    proto->name,
+-                    conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+-                    .tuple.dst.protonum,
+-                    timer_pending(&conntrack->timeout)
+-                    ? (conntrack->timeout.expires - jiffies)/HZ : 0);
++      unsigned int *bucket;
+-      len += proto->print_conntrack(buffer + len, conntrack);
+-      len += print_tuple(buffer + len,
+-                         &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+-                         proto);
+-      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);
+-      if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
+-              len += sprintf(buffer + len, "[ASSURED] ");
+-      len += sprintf(buffer + len, "use=%u ",
+-                     atomic_read(&conntrack->ct_general.use));
+-      len += sprintf(buffer + len, "\n");
++      /* strange seq_file api calls stop even if we fail,
++       * thus we need to grab lock since stop unlocks */
++      READ_LOCK(&ip_conntrack_lock);
++  
++      if (*pos >= ip_conntrack_htable_size)
++              return NULL;
+-      return len;
++      bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
++      if (!bucket) {
++              return ERR_PTR(-ENOMEM);
++      }
++  
++      *bucket = *pos;
++      return bucket;
+ }
++  
++static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      unsigned int *bucket = (unsigned int *) v;
+-/* Returns true when finished. */
+-static inline int
+-conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
+-                char *buffer, off_t offset, off_t *upto,
+-                unsigned int *len, unsigned int maxlen)
++      *pos = ++(*bucket);
++      if (*pos >= ip_conntrack_htable_size) {
++              kfree(v);
++              return NULL;
++      }
++      return bucket;
++}
++  
++static void ct_seq_stop(struct seq_file *s, void *v)
+ {
+-      unsigned int newlen;
+-      IP_NF_ASSERT(hash->ctrack);
++      READ_UNLOCK(&ip_conntrack_lock);
++}
++
++/* return 0 on success, 1 in case of error */
++static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash,
++                          struct seq_file *s)
++{
++      struct ip_conntrack *conntrack = hash->ctrack;
++      struct ip_conntrack_protocol *proto;
++      char buffer[IP_CT_PRINT_BUFLEN];
+       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+-      /* Only count originals */
++      IP_NF_ASSERT(conntrack);
++
++      /* we only want to print DIR_ORIGINAL */
+       if (DIRECTION(hash))
+               return 0;
+-      if ((*upto)++ < offset)
+-              return 0;
++      proto = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++                             .tuple.dst.protonum);
++      IP_NF_ASSERT(proto);
+-      newlen = print_conntrack(buffer + *len, hash->ctrack);
+-      if (*len + newlen > maxlen)
++      if (seq_printf(s, "%-8s %u %lu ",
++                    proto->name,
++                    conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
++                    timer_pending(&conntrack->timeout)
++                    ? (conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
++              return 1;
++
++      proto->print_conntrack(buffer, conntrack);
++      if (seq_puts(s, buffer))
++              return 1;
++  
++      print_tuple(buffer, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
++                  proto);
++
++      if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
++              return 1;
++
++      if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
++              if (seq_printf(s, "[UNREPLIED] "))
++                      return 1;
++
++      print_tuple(buffer, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
++                  proto);
++      if (seq_puts(s, buffer))
++              return 1;
++
++      if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
++              return 1;
++
++      if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
++              if (seq_printf(s, "[ASSURED] "))
++                      return 1;
++
++      if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+               return 1;
+-      else *len += newlen;
+       return 0;
+ }
+-static int
+-list_conntracks(char *buffer, char **start, off_t offset, int length)
++
++static int ct_seq_show(struct seq_file *s, void *v)
+ {
+-      unsigned int i;
+-      unsigned int len = 0;
+-      off_t upto = 0;
+-      struct list_head *e;
++      unsigned int *bucket = (unsigned int *) v;
+-      READ_LOCK(&ip_conntrack_lock);
+-      /* Traverse hash; print originals then reply. */
+-      for (i = 0; i < ip_conntrack_htable_size; i++) {
+-              if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
+-                            struct ip_conntrack_tuple_hash *,
+-                            buffer, offset, &upto, &len, length))
+-                      goto finished;
++      if (LIST_FIND(&ip_conntrack_hash[*bucket], ct_seq_real_show,
++                    struct ip_conntrack_tuple_hash *, s)) {
++              /* buffer was filled and unable to print that tuple */
++              return 1;
+       }
++      return 0;
++}
++      
++static struct seq_operations ct_seq_ops = {
++      .start = ct_seq_start,
++      .next  = ct_seq_next,
++      .stop  = ct_seq_stop,
++      .show  = ct_seq_show
++};
++  
++static int ct_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &ct_seq_ops);
++}
+-      /* Now iterate through expecteds. */
++static struct file_operations ct_file_ops = {
++      .owner   = THIS_MODULE,
++      .open    = ct_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++  
++/* expects */
++static void *exp_seq_start(struct seq_file *s, loff_t *pos)
++{
++      struct list_head *e = &ip_conntrack_expect_list;
++      loff_t i;
++
++      /* strange seq_file api calls stop even if we fail,
++       * thus we need to grab lock since stop unlocks */
++      READ_LOCK(&ip_conntrack_lock);
+       READ_LOCK(&ip_conntrack_expect_tuple_lock);
+-      list_for_each(e, &ip_conntrack_expect_list) {
+-              unsigned int last_len;
+-              struct ip_conntrack_expect *expect
+-                      = (struct ip_conntrack_expect *)e;
+-              if (upto++ < offset) continue;
+-
+-              last_len = len;
+-              len += print_expect(buffer + len, expect);
+-              if (len > length) {
+-                      len = last_len;
+-                      goto finished_expects;
+-              }
++
++      if (list_empty(e))
++              return NULL;
++
++      for (i = 0; i <= *pos; i++) {
++              e = e->next;
++              if (e == &ip_conntrack_expect_list)
++                      return NULL;
+       }
++      return e;
++}
++
++static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      struct list_head *e = v;
++
++      e = e->next;
++
++      if (e == &ip_conntrack_expect_list)
++              return NULL;
++
++      return e;
++}
+- finished_expects:
++static void exp_seq_stop(struct seq_file *s, void *v)
++{
+       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+- finished:
+       READ_UNLOCK(&ip_conntrack_lock);
++}
+-      /* `start' hack - see fs/proc/generic.c line ~165 */
+-      *start = (char *)((unsigned int)upto - offset);
+-      return len;
++static int exp_seq_show(struct seq_file *s, void *v)
++{
++      struct ip_conntrack_expect *expect = v;
++      char buffer[IP_CT_PRINT_BUFLEN];
++
++      if (expect->expectant->helper->timeout)
++              seq_printf(s, "%lu ", timer_pending(&expect->timeout)
++                         ? (expect->timeout.expires - jiffies)/HZ : 0);
++      else
++              seq_printf(s, "- ");
++
++      seq_printf(s, "use=%u proto=%u ", atomic_read(&expect->use),
++                 expect->tuple.dst.protonum);
++
++      print_tuple(buffer, &expect->tuple,
++                  __ip_ct_find_proto(expect->tuple.dst.protonum));
++      return seq_printf(s, "%s\n", buffer);
+ }
++static struct seq_operations exp_seq_ops = {
++      .start = exp_seq_start,
++      .next = exp_seq_next,
++      .stop = exp_seq_stop,
++      .show = exp_seq_show
++};
++
++static int exp_open(struct inode *inode, struct file *file)
++{
++      return seq_open(file, &exp_seq_ops);
++}
++  
++static struct file_operations exp_file_ops = {
++      .owner   = THIS_MODULE,
++      .open    = exp_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++
+ static unsigned int ip_confirm(unsigned int hooknum,
+                              struct sk_buff **pskb,
+                              const struct net_device *in,
+@@ -334,6 +432,11 @@
+ /* From ip_conntrack_proto_icmp.c */
+ extern unsigned long ip_ct_generic_timeout;
++/* Log invalid packets of a given protocol */
++unsigned int ip_ct_log_invalid = 0;
++static int log_invalid_proto_min = 0;
++static int log_invalid_proto_max = 255;
++
+ static struct ctl_table_header *ip_ct_sysctl_header;
+ static ctl_table ip_ct_sysctl_table[] = {
+@@ -449,6 +552,17 @@
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+       },
++      {
++              .ctl_name       = NET_IPV4_NF_CONNTRACK_LOG_INVALID,
++              .procname       = "ip_conntrack_log_invalid",
++              .data           = &ip_ct_log_invalid,
++              .maxlen         = sizeof(unsigned int),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec_minmax,
++              .strategy       = &sysctl_intvec,
++              .extra1         = &log_invalid_proto_min,
++              .extra2         = &log_invalid_proto_max,
++      },
+       { .ctl_name = 0 }
+ };
+@@ -494,7 +608,7 @@
+ #endif
+ static int init_or_cleanup(int init)
+ {
+-      struct proc_dir_entry *proc;
++      struct proc_dir_entry *proc, *proc_exp;
+       int ret = 0;
+       if (!init) goto cleanup;
+@@ -503,14 +617,18 @@
+       if (ret < 0)
+               goto cleanup_nothing;
+-      proc = proc_net_create("ip_conntrack", 0440, list_conntracks);
++      proc = proc_net_create("ip_conntrack", 0440, NULL);
+       if (!proc) goto cleanup_init;
+-      proc->owner = THIS_MODULE;
++      proc->proc_fops = &ct_file_ops;
++
++      proc_exp = proc_net_create("ip_conntrack_expect", 0440, NULL);
++      if (!proc_exp) goto cleanup_proc;
++      proc_exp->proc_fops = &exp_file_ops;
+       ret = nf_register_hook(&ip_conntrack_defrag_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register pre-routing defrag hook.\n");
+-              goto cleanup_proc;
++              goto cleanup_proc_exp;
+       }
+       ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
+       if (ret < 0) {
+@@ -562,6 +680,8 @@
+       nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
+  cleanup_defragops:
+       nf_unregister_hook(&ip_conntrack_defrag_ops);
++cleanup_proc_exp:
++      proc_net_remove("ip_conntrack_exp");
+  cleanup_proc:
+       proc_net_remove("ip_conntrack");
+  cleanup_init:
+@@ -638,7 +758,7 @@
+ EXPORT_SYMBOL(ip_conntrack_helper_register);
+ EXPORT_SYMBOL(ip_conntrack_helper_unregister);
+ EXPORT_SYMBOL(ip_ct_selective_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);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_fw_compat_masq.c linux-2.6.7/net/ipv4/netfilter/ip_fw_compat_masq.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_fw_compat_masq.c     2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_fw_compat_masq.c 2004-09-07 12:32:47.925387256 +0200
+@@ -31,6 +31,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
+ #include <linux/netfilter_ipv4/ip_nat.h>
+ #include <linux/netfilter_ipv4/ip_nat_core.h>
+ #include <linux/netfilter_ipv4/listhelp.h>
+@@ -144,7 +145,8 @@
+       switch ((*pskb)->nh.iph->protocol) {
+       case IPPROTO_ICMP:
+               /* ICMP errors. */
+-              ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
++              protocol->error(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
++              ct = (struct ip_conntrack *)(*pskb)->nfct->master;
+               if (ct) {
+                       /* We only do SNAT in the compatibility layer.
+                          So we can manipulate ICMP errors from
+@@ -165,7 +167,8 @@
+       case IPPROTO_UDP:
+               IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+-              if (!get_tuple((*pskb)->nh.iph, *pskb, (*pskb)->nh.iph->ihl*4, &tuple, protocol)) {
++              if (!ip_ct_get_tuple((*pskb)->nh.iph, *pskb,
++                                   (*pskb)->nh.iph->ihl*4, &tuple, protocol)) {
+                       if (net_ratelimit())
+                               printk("ip_fw_compat_masq: Can't get tuple\n");
+                       return NF_ACCEPT;
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.7/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_nat_core.c   2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_nat_core.c       2004-09-07 12:32:56.183131888 +0200
+@@ -49,7 +49,6 @@
+ static struct list_head *bysource;
+ static struct list_head *byipsproto;
+ LIST_HEAD(protos);
+-LIST_HEAD(helpers);
+ extern struct ip_nat_protocol unknown_nat_protocol;
+@@ -498,13 +497,6 @@
+       return ret;
+ }
+-static inline int
+-helper_cmp(const struct ip_nat_helper *helper,
+-         const struct ip_conntrack_tuple *tuple)
+-{
+-      return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
+-}
+-
+ /* Where to manip the reply packets (will be reverse manip). */
+ static unsigned int opposite_hook[NF_IP_NUMHOOKS]
+ = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
+@@ -643,8 +635,7 @@
+       /* If there's a helper, assign it; based on new tuple. */
+       if (!conntrack->master)
+-              info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
+-                                       &reply);
++              info->helper = ip_nat_find_helper(&reply);
+       /* It's done. */
+       info->initialized |= (1 << HOOK2MANIP(hooknum));
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.7/net/ipv4/netfilter/ip_nat_helper.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_nat_helper.c 2004-09-07 12:07:46.565628632 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_nat_helper.c     2004-09-07 12:32:56.184131736 +0200
+@@ -47,6 +47,7 @@
+ #define DUMP_OFFSET(x)
+ #endif
++static LIST_HEAD(helpers);
+ DECLARE_LOCK(ip_nat_seqofs_lock);
+ /* Setup TCP sequence correction given this change at this sequence */
+@@ -419,6 +420,18 @@
+       return ret;
+ }
++struct ip_nat_helper *
++ip_nat_find_helper(const struct ip_conntrack_tuple *tuple)
++{
++      struct ip_nat_helper *h;
++
++      READ_LOCK(&ip_nat_lock);
++      h = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, tuple);
++      READ_UNLOCK(&ip_nat_lock);
++
++      return h;
++}
++
+ static int
+ kill_helper(const struct ip_conntrack *i, void *helper)
+ {
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ip_queue.c linux-2.6.7/net/ipv4/netfilter/ip_queue.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ip_queue.c      2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ip_queue.c  2004-09-07 12:33:00.821426760 +0200
+@@ -255,9 +255,10 @@
+                               entry->skb->dev->hard_header_parse(entry->skb,
+                                                                  pmsg->hw_addr);
+       }
+-      
+-      if (data_len)
+-              memcpy(pmsg->payload, entry->skb->data, data_len);
++
++      if (data_len) 
++              if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len) != 0)
++                      goto nlmsg_failure;
+               
+       nlh->nlmsg_len = skb->tail - old_tail;
+       return skb;
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.7/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-09-07 12:33:07.424422952 +0200
+@@ -0,0 +1,89 @@
++/**
++ * Strip all IP options in the IP packet header.
++ *
++ * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <net/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Strip all options in IPv4 packets");
++MODULE_LICENSE("GPL");
++
++static unsigned int
++target(struct sk_buff **pskb,
++       const struct net_device *in,
++       const struct net_device *out,
++       unsigned int hooknum,
++       const void *targinfo,
++       void *userinfo)
++{
++      struct iphdr *iph;
++      struct sk_buff *skb;
++      struct ip_options *opt;
++      unsigned char *optiph;
++      int l;
++      
++      if (!skb_ip_make_writable(pskb, (*pskb)->len))
++              return NF_DROP;
++ 
++      skb = (*pskb);
++      iph = (*pskb)->nh.iph;
++      optiph = skb->nh.raw;
++      l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
++
++      /* if no options in packet then nothing to clear. */
++      if (iph->ihl * 4 == sizeof(struct iphdr))
++              return IPT_CONTINUE;
++
++      /* else clear all options */
++      memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++      memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
++      opt = &(IPCB(skb)->opt);
++      opt->is_data = 0;
++      opt->optlen = l;
++
++      skb->nfcache |= NFC_ALTERED;
++
++        return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_entry *e,
++           void *targinfo,
++           unsigned int targinfosize,
++           unsigned int hook_mask)
++{
++      if (strcmp(tablename, "mangle")) {
++              printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++              return 0;
++      }
++      /* nothing else to check because no parameters */
++      return 1;
++}
++
++static struct ipt_target ipt_ipv4optsstrip_reg = { 
++      .name = "IPV4OPTSSTRIP",
++      .target = target,
++      .checkentry = checkentry,
++      .me = THIS_MODULE };
++
++static int __init init(void)
++{
++      return ipt_register_target(&ipt_ipv4optsstrip_reg);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_ipv4optsstrip_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.7/net/ipv4/netfilter/ipt_LOG.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_LOG.c       2004-09-07 12:07:46.566628480 +0200
++++ linux-2.6.7/net/ipv4/netfilter/ipt_LOG.c   2004-09-07 12:32:38.740783528 +0200
+@@ -76,7 +76,7 @@
+               printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET);
+       if ((info->logflags & IPT_LOG_IPOPT)
+-          && iph.ihl * 4 != sizeof(struct iphdr)) {
++          && iph.ihl * 4 > sizeof(struct iphdr)) {
+               unsigned char opt[4 * 15 - sizeof(struct iphdr)];
+               unsigned int i, optsize;
+@@ -143,7 +143,7 @@
+               printk("URGP=%u ", ntohs(tcph.urg_ptr));
+               if ((info->logflags & IPT_LOG_TCPOPT)
+-                  && tcph.doff * 4 != sizeof(struct tcphdr)) {
++                  && tcph.doff * 4 > sizeof(struct tcphdr)) {
+                       unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
+                       unsigned int i, optsize;
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.7/net/ipv4/netfilter/ipt_TTL.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_TTL.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_TTL.c   2004-09-07 12:33:09.041177168 +0200
+@@ -0,0 +1,120 @@
++/* TTL modification target for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Version: $Revision$
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_TTL.h>
++
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("IP tables TTL modification module");
++MODULE_LICENSE("GPL");
++
++static unsigned int 
++ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
++              const struct net_device *out, unsigned int hooknum, 
++              const void *targinfo, void *userinfo)
++{
++      struct iphdr *iph;
++      const struct ipt_TTL_info *info = targinfo;
++      u_int16_t diffs[2];
++      int new_ttl;
++
++      if (!skb_ip_make_writable(pskb, (*pskb)->len))
++              return NF_DROP;
++
++      iph = (*pskb)->nh.iph;
++                       
++      switch (info->mode) {
++              case IPT_TTL_SET:
++                      new_ttl = info->ttl;
++                      break;
++              case IPT_TTL_INC:
++                      new_ttl = iph->ttl + info->ttl;
++                      if (new_ttl > 255)
++                              new_ttl = 255;
++                      break;
++              case IPT_TTL_DEC:
++                      new_ttl = iph->ttl - info->ttl;
++                      if (new_ttl < 0)
++                              new_ttl = 0;
++                      break;
++              default:
++                      new_ttl = iph->ttl;
++                      break;
++      }
++
++      if (new_ttl != iph->ttl) {
++              diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
++              iph->ttl = new_ttl;
++              diffs[1] = htons(((unsigned)iph->ttl) << 8);
++              iph->check = csum_fold(csum_partial((char *)diffs,
++                                                  sizeof(diffs),
++                                                  iph->check^0xFFFF));
++                                                                                              (*pskb)->nfcache |= NFC_ALTERED;
++      }
++
++      return IPT_CONTINUE;
++}
++
++static int ipt_ttl_checkentry(const char *tablename,
++              const struct ipt_entry *e,
++              void *targinfo,
++              unsigned int targinfosize,
++              unsigned int hook_mask)
++{
++      struct ipt_TTL_info *info = targinfo;
++
++      if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
++              printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
++                              targinfosize,
++                              IPT_ALIGN(sizeof(struct ipt_TTL_info)));
++              return 0;       
++      }       
++
++      if (strcmp(tablename, "mangle")) {
++              printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++              return 0;
++      }
++
++      if (info->mode > IPT_TTL_MAXMODE) {
++              printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", 
++                      info->mode);
++              return 0;
++      }
++
++      if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
++              printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
++              return 0;
++      }
++      
++      return 1;
++}
++
++static struct ipt_target ipt_TTL = { 
++      .name = "TTL",
++      .target = ipt_ttl_target, 
++      .checkentry = ipt_ttl_checkentry, 
++      .me = THIS_MODULE 
++};
++
++static int __init init(void)
++{
++      return ipt_register_target(&ipt_TTL);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_TTL);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.7/net/ipv4/netfilter/ipt_connlimit.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_connlimit.c     2004-09-07 12:33:10.091017568 +0200
+@@ -0,0 +1,230 @@
++/*
++ * netfilter module to limit the number of parallel tcp
++ * connections per IP address.
++ *   (c) 2000 Gerd Knorr <kraxel@bytesex.org>
++ *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
++ *            only ignore TIME_WAIT or gone connections
++ *
++ * based on ...
++ *
++ * Kernel module to match connection tracking information.
++ * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connlimit.h>
++
++#define DEBUG 0
++
++MODULE_LICENSE("GPL");
++
++/* we'll save the tuples of all connections we care about */
++struct ipt_connlimit_conn
++{
++        struct list_head list;
++      struct ip_conntrack_tuple tuple;
++};
++
++struct ipt_connlimit_data {
++      spinlock_t lock;
++      struct list_head iphash[256];
++};
++
++static int ipt_iphash(u_int32_t addr)
++{
++      int hash;
++
++      hash  =  addr        & 0xff;
++      hash ^= (addr >>  8) & 0xff;
++      hash ^= (addr >> 16) & 0xff;
++      hash ^= (addr >> 24) & 0xff;
++      return hash;
++}
++
++static int count_them(struct ipt_connlimit_data *data,
++                    u_int32_t addr, u_int32_t mask,
++                    struct ip_conntrack *ct)
++{
++#if DEBUG
++      const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
++                                   "fin_wait", "time_wait", "close", "close_wait",
++                                   "last_ack", "listen" };
++#endif
++      int addit = 1, matches = 0;
++      struct ip_conntrack_tuple tuple;
++      struct ip_conntrack_tuple_hash *found;
++      struct ipt_connlimit_conn *conn;
++      struct list_head *hash,*lh;
++
++      spin_lock(&data->lock);
++      tuple = ct->tuplehash[0].tuple;
++      hash = &data->iphash[ipt_iphash(addr & mask)];
++
++      /* check the saved connections */
++      for (lh = hash->next; lh != hash; lh = lh->next) {
++              conn = list_entry(lh,struct ipt_connlimit_conn,list);
++              found = ip_conntrack_find_get(&conn->tuple,ct);
++              if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
++                  found != NULL &&
++                  found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
++                      /* Just to be sure we have it only once in the list.
++                         We should'nt see tuples twice unless someone hooks this
++                         into a table without "-p tcp --syn" */
++                      addit = 0;
++              }
++#if DEBUG
++              printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
++                     ipt_iphash(addr & mask),
++                     NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
++                     NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
++                     (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
++#endif
++              if (NULL == found) {
++                      /* this one is gone */
++                      lh = lh->prev;
++                      list_del(lh->next);
++                      kfree(conn);
++                      continue;
++              }
++              if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
++                      /* we don't care about connections which are
++                         closed already -> ditch it */
++                      lh = lh->prev;
++                      list_del(lh->next);
++                      kfree(conn);
++                      nf_conntrack_put(&found->ctrack->infos[0]);
++                      continue;
++              }
++              if ((addr & mask) == (conn->tuple.src.ip & mask)) {
++                      /* same source IP address -> be counted! */
++                      matches++;
++              }
++              nf_conntrack_put(&found->ctrack->infos[0]);
++      }
++      if (addit) {
++              /* save the new connection in our list */
++#if DEBUG
++              printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
++                     ipt_iphash(addr & mask),
++                     NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
++                     NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
++#endif
++              conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
++              if (NULL == conn)
++                      return -1;
++              memset(conn,0,sizeof(*conn));
++              INIT_LIST_HEAD(&conn->list);
++              conn->tuple = tuple;
++              list_add(&conn->list,hash);
++              matches++;
++      }
++      spin_unlock(&data->lock);
++      return matches;
++}
++
++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)
++{
++      const struct ipt_connlimit_info *info = matchinfo;
++      int connections, match;
++      struct ip_conntrack *ct;
++      enum ip_conntrack_info ctinfo;
++
++      ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++      if (NULL == ct) {
++              printk("ipt_connlimit: Oops: invalid ct state ?\n");
++              *hotdrop = 1;
++              return 0;
++      }
++      connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
++      if (-1 == connections) {
++              printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
++              *hotdrop = 1; /* let's free some memory :-) */
++              return 0;
++      }
++        match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
++#if DEBUG
++      printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
++             "connections=%d limit=%d match=%s\n",
++             NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
++             connections, info->limit, match ? "yes" : "no");
++#endif
++
++      return match;
++}
++
++static int check(const char *tablename,
++               const struct ipt_ip *ip,
++               void *matchinfo,
++               unsigned int matchsize,
++               unsigned int hook_mask)
++{
++      struct ipt_connlimit_info *info = matchinfo;
++      int i;
++
++      /* verify size */
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
++              return 0;
++
++      /* refuse anything but tcp */
++      if (ip->proto != IPPROTO_TCP)
++              return 0;
++
++      /* init private data */
++      info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
++      spin_lock_init(&(info->data->lock));
++      for (i = 0; i < 256; i++)
++              INIT_LIST_HEAD(&(info->data->iphash[i]));
++      
++      return 1;
++}
++
++static void destroy(void *matchinfo, unsigned int matchinfosize)
++{
++      struct ipt_connlimit_info *info = matchinfo;
++      struct ipt_connlimit_conn *conn;
++      struct list_head *hash;
++      int i;
++
++      /* cleanup */
++      for (i = 0; i < 256; i++) {
++              hash = &(info->data->iphash[i]);
++              while (hash != hash->next) {
++                      conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
++                      list_del(hash->next);
++                      kfree(conn);
++              }
++      }
++      kfree(info->data);
++}
++
++static struct ipt_match connlimit_match = { 
++      .name = "connlimit",
++      .match = &match,
++      .checkentry = &check,
++      .destroy = &destroy,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&connlimit_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&connlimit_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.7/net/ipv4/netfilter/ipt_dstlimit.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_dstlimit.c  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_dstlimit.c      2004-09-07 12:33:11.098864352 +0200
+@@ -0,0 +1,690 @@
++/* iptables match extension to limit the number of packets per second
++ * seperately for each destination.
++ *
++ * (C) 2003 by Harald Welte <laforge@netfilter.org>
++ *
++ * $Id$
++ *
++ * Development of this code was funded by Astaro AG, http://www.astaro.com/
++ *
++ * based on ipt_limit.c by:
++ * Jérôme de Vivie    <devivie@info.enserb.u-bordeaux.fr>
++ * Hervé Eychenne     <eychenne@info.enserb.u-bordeaux.fr>
++ * Rusty Russell      <rusty@rustcorp.com.au>
++ *
++ * The general idea is to create a hash table for every dstip and have a
++ * seperate limit counter per tuple.  This way you can do something like 'limit
++ * the number of syn packets for each of my internal addresses.
++ *
++ * Ideally this would just be implemented as a general 'hash' match, which would
++ * allow us to attach any iptables target to it's hash buckets.  But this is
++ * not possible in the current iptables architecture.  As always, pkttables for
++ * 2.7.x will help ;)
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/jhash.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++
++#define ASSERT_READ_LOCK(x) 
++#define ASSERT_WRITE_LOCK(x) 
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_dstlimit.h>
++
++/* FIXME: this is just for IP_NF_ASSERRT */
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++#define MS2JIFFIES(x) ((x*HZ)/1000)
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
++MODULE_DESCRIPTION("iptables match for limiting per destination");
++
++/* need to declare this at the top */
++static struct proc_dir_entry *dstlimit_procdir;
++static struct file_operations dl_file_ops;
++
++/* hash table crap */
++
++struct dsthash_dst {
++      u_int32_t src_ip;
++      u_int32_t dst_ip;
++      u_int16_t port;
++};
++
++struct dsthash_ent {
++      /* static / read-only parts in the beginning */
++      struct list_head list;
++      struct dsthash_dst dst;
++
++      /* modified structure members in the end */
++      unsigned long expires;          /* precalculated expiry time */
++      struct {
++              unsigned long prev;     /* last modification */
++              u_int32_t credit;
++              u_int32_t credit_cap, cost;
++      } rateinfo;
++};
++
++struct ipt_dstlimit_htable {
++      struct list_head list;          /* global list of all htables */
++      atomic_t use;
++
++      struct dstlimit_cfg cfg;        /* config */
++
++      /* used internally */
++      spinlock_t lock;                /* lock for list_head */
++      u_int32_t rnd;                  /* random seed for hash */
++      struct timer_list timer;        /* timer for gc */
++      atomic_t count;                 /* number entries in table */
++
++      /* seq_file stuff */
++      struct proc_dir_entry *pde;
++
++      struct list_head hash[0];       /* hashtable itself */
++};
++
++DECLARE_RWLOCK(dstlimit_lock);                /* protects htables list */
++static LIST_HEAD(dstlimit_htables);
++static kmem_cache_t *dstlimit_cachep;
++
++static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
++{
++      return (ent->dst.dst_ip == b->dst_ip 
++              && ent->dst.port == b->port
++              && ent->dst.src_ip == b->src_ip);
++}
++
++static inline u_int32_t
++hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
++{
++      return (jhash_3words(dst->dst_ip, dst->port, 
++                           dst->src_ip, ht->rnd) % ht->cfg.size);
++}
++
++static inline struct dsthash_ent *
++__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
++{
++      struct dsthash_ent *ent;
++      u_int32_t hash = hash_dst(ht, dst);
++      MUST_BE_LOCKED(&ht->lock);
++      ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
++      return ent;
++}
++
++/* allocate dsthash_ent, initialize dst, put in htable and lock it */
++static struct dsthash_ent *
++__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
++{
++      struct dsthash_ent *ent;
++
++      /* initialize hash with random val at the time we allocate
++       * the first hashtable entry */
++      if (!ht->rnd)
++              get_random_bytes(&ht->rnd, 4);
++
++      if (ht->cfg.max &&
++          atomic_read(&ht->count) >= ht->cfg.max) {
++              /* FIXME: do something. question is what.. */
++              if (net_ratelimit())
++                      printk(KERN_WARNING 
++                              "ipt_dstlimit: max count of %u reached\n", 
++                              ht->cfg.max);
++              return NULL;
++      }
++
++      ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
++      if (!ent) {
++              if (net_ratelimit())
++                      printk(KERN_ERR 
++                              "ipt_dstlimit: can't allocate dsthash_ent\n");
++              return NULL;
++      }
++
++      atomic_inc(&ht->count);
++
++      ent->dst.dst_ip = dst->dst_ip;
++      ent->dst.port = dst->port;
++      ent->dst.src_ip = dst->src_ip;
++
++      list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
++
++      return ent;
++}
++
++static inline void 
++__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
++{
++      MUST_BE_LOCKED(&ht->lock);
++
++      list_del(&ent->list);
++      kmem_cache_free(dstlimit_cachep, ent);
++      atomic_dec(&ht->count);
++}
++static void htable_gc(unsigned long htlong);
++
++static int htable_create(struct ipt_dstlimit_info *minfo)
++{
++      int i;
++      unsigned int size;
++      struct ipt_dstlimit_htable *hinfo;
++
++      if (minfo->cfg.size)
++              size = minfo->cfg.size;
++      else {
++              size = (((num_physpages << PAGE_SHIFT) / 16384)
++                       / sizeof(struct list_head));
++              if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
++                      size = 8192;
++              if (size < 16)
++                      size = 16;
++      }
++      /* FIXME: don't use vmalloc() here or anywhere else -HW */
++      hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
++                      + (sizeof(struct list_head) * size));
++      if (!hinfo) {
++              printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
++              return -1;
++      }
++      minfo->hinfo = hinfo;
++
++      /* copy match config into hashtable config */
++      memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
++      hinfo->cfg.size = size;
++      if (!hinfo->cfg.max)
++              hinfo->cfg.max = 8 * hinfo->cfg.size;
++      else if (hinfo->cfg.max < hinfo->cfg.size)
++              hinfo->cfg.max = hinfo->cfg.size;
++
++      for (i = 0; i < hinfo->cfg.size; i++)
++              INIT_LIST_HEAD(&hinfo->hash[i]);
++
++      atomic_set(&hinfo->count, 0);
++      atomic_set(&hinfo->use, 1);
++      hinfo->rnd = 0;
++      hinfo->lock = SPIN_LOCK_UNLOCKED;
++      hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
++      if (!hinfo->pde) {
++              vfree(hinfo);
++              return -1;
++      }
++      hinfo->pde->proc_fops = &dl_file_ops;
++      hinfo->pde->data = hinfo;
++
++      init_timer(&hinfo->timer);
++      hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
++      hinfo->timer.data = (unsigned long )hinfo;
++      hinfo->timer.function = htable_gc;
++      add_timer(&hinfo->timer);
++
++      WRITE_LOCK(&dstlimit_lock);
++      list_add(&hinfo->list, &dstlimit_htables);
++      WRITE_UNLOCK(&dstlimit_lock);
++
++      return 0;
++}
++
++static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
++{
++      return 1;
++}
++
++static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
++{
++      return (jiffies >= he->expires);
++}
++
++static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
++                              int (*select)(struct ipt_dstlimit_htable *ht, 
++                                            struct dsthash_ent *he))
++{
++      int i;
++
++      IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
++
++      /* lock hash table and iterate over it */
++      LOCK_BH(&ht->lock);
++      for (i = 0; i < ht->cfg.size; i++) {
++              struct dsthash_ent *dh, *n;
++              list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
++                      if ((*select)(ht, dh))
++                              __dsthash_free(ht, dh);
++              }
++      }
++      UNLOCK_BH(&ht->lock);
++}
++
++/* hash table garbage collector, run by timer */
++static void htable_gc(unsigned long htlong)
++{
++      struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
++
++      htable_selective_cleanup(ht, select_gc);
++
++      /* re-add the timer accordingly */
++      ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
++      add_timer(&ht->timer);
++}
++
++static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
++{
++      /* remove timer, if it is pending */
++      if (timer_pending(&hinfo->timer))
++              del_timer(&hinfo->timer);
++
++      /* remove proc entry */
++      remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
++
++      htable_selective_cleanup(hinfo, select_all);
++      vfree(hinfo);
++}
++
++static struct ipt_dstlimit_htable *htable_find_get(char *name)
++{
++      struct ipt_dstlimit_htable *hinfo;
++
++      READ_LOCK(&dstlimit_lock);
++      list_for_each_entry(hinfo, &dstlimit_htables, list) {
++              if (!strcmp(name, hinfo->pde->name)) {
++                      atomic_inc(&hinfo->use);
++                      READ_UNLOCK(&dstlimit_lock);
++                      return hinfo;
++              }
++      }
++      READ_UNLOCK(&dstlimit_lock);
++
++      return NULL;
++}
++
++static void htable_put(struct ipt_dstlimit_htable *hinfo)
++{
++      if (atomic_dec_and_test(&hinfo->use)) {
++              WRITE_LOCK(&dstlimit_lock);
++              list_del(&hinfo->list);
++              WRITE_UNLOCK(&dstlimit_lock);
++              htable_destroy(hinfo);
++      }
++}
++
++
++/* The algorithm used is the Simple Token Bucket Filter (TBF)
++ * see net/sched/sch_tbf.c in the linux source tree
++ */
++
++/* Rusty: This is my (non-mathematically-inclined) understanding of
++   this algorithm.  The `average rate' in jiffies becomes your initial
++   amount of credit `credit' and the most credit you can ever have
++   `credit_cap'.  The `peak rate' becomes the cost of passing the
++   test, `cost'.
++
++   `prev' tracks the last packet hit: you gain one credit per jiffy.
++   If you get credit balance more than this, the extra credit is
++   discarded.  Every time the match passes, you lose `cost' credits;
++   if you don't have that many, the test fails.
++
++   See Alexey's formal explanation in net/sched/sch_tbf.c.
++
++   To get the maximum range, we multiply by this factor (ie. you get N
++   credits per jiffy).  We want to allow a rate as low as 1 per day
++   (slowest userspace tool allows), which means
++   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
++*/
++#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
++
++/* Repeated shift and or gives us all 1s, final shift and add 1 gives
++ * us the power of 2 below the theoretical max, so GCC simply does a
++ * shift. */
++#define _POW2_BELOW2(x) ((x)|((x)>>1))
++#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
++#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
++#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
++#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
++#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
++
++#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
++
++/* Precision saver. */
++static inline u_int32_t
++user2credits(u_int32_t user)
++{
++      /* If multiplying would overflow... */
++      if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
++              /* Divide first. */
++              return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
++
++      return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
++}
++
++static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
++{
++      dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) 
++                                      * CREDITS_PER_JIFFY;
++      if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
++              dh->rateinfo.credit = dh->rateinfo.credit_cap;
++}
++
++static int
++dstlimit_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_dstlimit_info *r = 
++              ((struct ipt_dstlimit_info *)matchinfo)->u.master;
++      struct ipt_dstlimit_htable *hinfo = r->hinfo;
++      unsigned long now = jiffies;
++      struct dsthash_ent *dh;
++      struct dsthash_dst dst;
++
++      memset(&dst, 0, sizeof(dst));
++
++      /* dest ip is always in hash */
++      dst.dst_ip = skb->nh.iph->daddr;
++
++      /* source ip only if respective hashmode, otherwise set to
++       * zero */
++      if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
++              dst.src_ip = skb->nh.iph->saddr;
++
++      /* dest port only if respective mode */
++      if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
++              u16 ports[2];
++
++              /* Must not be a fragment. */
++              if (offset)
++                      return 0;
++
++              /* Must be big enough to read ports (both UDP and TCP have
++                 them at the start). */
++              if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
++                      /* We've been asked to examine this packet, and we
++                         can't.  Hence, no choice but to drop. */
++                      *hotdrop = 1;
++                      return 0;
++              }
++
++              switch (skb->nh.iph->protocol) {
++                      struct tcphdr *th;
++                      struct udphdr *uh;
++              case IPPROTO_TCP:
++                      th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
++                      dst.port = th->dest;
++                      break;
++              case IPPROTO_UDP:
++                      uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
++                      dst.port = uh->dest;
++                      break;
++              default:
++                      break;
++              }
++      } 
++
++      LOCK_BH(&hinfo->lock);
++      dh = __dsthash_find(hinfo, &dst);
++      if (!dh) {
++              dh = __dsthash_alloc_init(hinfo, &dst);
++
++              if (!dh) {
++                      /* enomem... don't match == DROP */
++                      if (net_ratelimit())
++                              printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
++                      UNLOCK_BH(&hinfo->lock);
++                      return 0;
++              }
++
++              dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
++
++              dh->rateinfo.prev = jiffies;
++              dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
++                                                      hinfo->cfg.burst);
++              dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * 
++                                                      hinfo->cfg.burst);
++              dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
++
++              UNLOCK_BH(&hinfo->lock);
++              return 1;
++      }
++
++      /* update expiration timeout */
++      dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
++
++      rateinfo_recalc(dh, now);
++      if (dh->rateinfo.credit >= dh->rateinfo.cost) {
++              /* We're underlimit. */
++              dh->rateinfo.credit -= dh->rateinfo.cost;
++              UNLOCK_BH(&hinfo->lock);
++              return 1;
++      }
++
++              UNLOCK_BH(&hinfo->lock);
++
++      /* default case: we're overlimit, thus don't match */
++      return 0;
++}
++
++static int
++dstlimit_checkentry(const char *tablename,
++                   const struct ipt_ip *ip,
++                   void *matchinfo,
++                   unsigned int matchsize,
++                   unsigned int hook_mask)
++{
++      struct ipt_dstlimit_info *r = matchinfo;
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
++              return 0;
++
++      /* Check for overflow. */
++      if (r->cfg.burst == 0
++          || user2credits(r->cfg.avg * r->cfg.burst) < 
++                                      user2credits(r->cfg.avg)) {
++              printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
++                     r->cfg.avg, r->cfg.burst);
++              return 0;
++      }
++
++      if (r->cfg.mode == 0 
++          || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
++                        |IPT_DSTLIMIT_HASH_DIP
++                        |IPT_DSTLIMIT_HASH_SIP))
++              return 0;
++
++      if (!r->cfg.gc_interval)
++              return 0;
++      
++      if (!r->cfg.expire)
++              return 0;
++
++      r->hinfo = htable_find_get(r->name);
++      if (!r->hinfo && (htable_create(r) != 0)) {
++              return 0;
++      }
++
++      /* Ugly hack: For SMP, we only want to use one set */
++      r->u.master = r;
++
++      return 1;
++}
++
++static void
++dstlimit_destroy(void *matchinfo, unsigned int matchsize)
++{
++      struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
++
++      htable_put(r->hinfo);
++}
++
++static struct ipt_match ipt_dstlimit = { 
++      .list = { .prev = NULL, .next = NULL }, 
++      .name = "dstlimit", 
++      .match = dstlimit_match, 
++      .checkentry = dstlimit_checkentry, 
++      .destroy = dstlimit_destroy,
++      .me = THIS_MODULE 
++};
++
++/* PROC stuff */
++
++static void *dl_seq_start(struct seq_file *s, loff_t *pos)
++{
++      struct proc_dir_entry *pde = s->private;
++      struct ipt_dstlimit_htable *htable = pde->data;
++      unsigned int *bucket;
++
++      LOCK_BH(&htable->lock);
++      if (*pos >= htable->cfg.size)
++              return NULL;
++
++      bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
++      if (!bucket)
++              return ERR_PTR(-ENOMEM);
++
++      *bucket = *pos;
++      return bucket;
++}
++
++static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++      struct proc_dir_entry *pde = s->private;
++      struct ipt_dstlimit_htable *htable = pde->data;
++      unsigned int *bucket = (unsigned int *)v;
++
++      *pos = ++(*bucket);
++      if (*pos >= htable->cfg.size) {
++              kfree(v);
++              return NULL;
++      }
++      return bucket;
++}
++
++static void dl_seq_stop(struct seq_file *s, void *v)
++{
++      struct proc_dir_entry *pde = s->private;
++      struct ipt_dstlimit_htable *htable = pde->data;
++      unsigned int *bucket = (unsigned int *)v;
++
++      kfree(bucket);
++
++      UNLOCK_BH(&htable->lock);
++}
++
++static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
++{
++      /* recalculate to show accurate numbers */
++      rateinfo_recalc(ent, jiffies);
++
++      return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
++                      (ent->expires - jiffies)/HZ,
++                      NIPQUAD(ent->dst.src_ip),
++                      NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
++                      ent->rateinfo.credit, ent->rateinfo.credit_cap,
++                      ent->rateinfo.cost);
++}
++
++static int dl_seq_show(struct seq_file *s, void *v)
++{
++      struct proc_dir_entry *pde = s->private;
++      struct ipt_dstlimit_htable *htable = pde->data;
++      unsigned int *bucket = (unsigned int *)v;
++
++      if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
++                    struct dsthash_ent *, s)) {
++              /* buffer was filled and unable to print that tuple */
++              return 1;
++      }
++      return 0;
++}
++
++static struct seq_operations dl_seq_ops = {
++      .start = dl_seq_start,
++      .next  = dl_seq_next,
++      .stop  = dl_seq_stop,
++      .show  = dl_seq_show
++};
++
++static int dl_proc_open(struct inode *inode, struct file *file)
++{
++      int ret = seq_open(file, &dl_seq_ops);
++
++      if (!ret) {
++              struct seq_file *sf = file->private_data;
++              sf->private = PDE(inode);
++      }
++      return ret;
++}
++
++static struct file_operations dl_file_ops = {
++      .owner   = THIS_MODULE,
++      .open    = dl_proc_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++
++static int init_or_fini(int fini)
++{
++      int ret = 0;
++
++      if (fini)
++              goto cleanup;
++
++      if (ipt_register_match(&ipt_dstlimit)) {
++              ret = -EINVAL;
++              goto cleanup_nothing;
++      }
++
++      /* FIXME: do we really want HWCACHE_ALIGN since our objects are
++       * quite small ? */
++      dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
++                                          sizeof(struct dsthash_ent), 0,
++                                          SLAB_HWCACHE_ALIGN, NULL, NULL);
++      if (!dstlimit_cachep) {
++              printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
++              ret = -ENOMEM;
++              goto cleanup_unreg_match;
++      }
++
++      dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
++      if (!dstlimit_procdir) {
++              printk(KERN_ERR "Unable to create proc dir entry\n");
++              ret = -ENOMEM;
++              goto cleanup_free_slab;
++      }
++
++      return ret;
++
++cleanup:
++      remove_proc_entry("ipt_dstlimit", proc_net);
++cleanup_free_slab:
++      kmem_cache_destroy(dstlimit_cachep);
++cleanup_unreg_match:
++      ipt_unregister_match(&ipt_dstlimit);
++cleanup_nothing:
++      return ret;
++      
++}
++
++static int __init init(void)
++{
++      return init_or_fini(0);
++}
++
++static void __exit fini(void)
++{
++      init_or_fini(1);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.7/net/ipv4/netfilter/ipt_fuzzy.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_fuzzy.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_fuzzy.c 2004-09-07 12:33:12.080715088 +0200
+@@ -0,0 +1,185 @@
++/*
++ *  This module implements a simple TSK FLC 
++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
++ * to limit , in an adaptive and flexible way , the packet rate crossing 
++ * a given stream . It serves as an initial and very simple (but effective)
++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
++ *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"  
++ * into our code in a precise , adaptive and efficient manner. 
++ *  The goal is very similar to that of "limit" match , but using techniques of
++ * Fuzzy Control , that allow us to shape the transfer functions precisely ,
++ * avoiding over and undershoots - and stuff like that .
++ *
++ *
++ * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
++ * 2002-08-17  : Changed to eliminate floating point operations .
++ * 2002-08-23  : Coding style changes .
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/random.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_fuzzy.h>
++
++/*
++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
++ Expressed in percentage
++*/
++
++#define PAR_LOW               1/100
++#define PAR_HIGH      1
++
++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
++
++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
++MODULE_LICENSE("GPL");
++
++static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++      if (tx >= maxi)
++              return 100;
++
++      if (tx <= mini)
++              return 0;
++
++      return ( (100*(tx-mini)) / (maxi-mini) );
++}
++
++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++      if (tx <= mini)
++              return 100;
++
++      if (tx >= maxi)
++              return 0;
++
++      return ( (100*( maxi - tx ))  / ( maxi - mini ) );
++}
++
++static int
++ipt_fuzzy_match(const struct sk_buff *pskb,
++             const struct net_device *in,
++             const struct net_device *out,
++             const void *matchinfo,
++             int offset,
++             int *hotdrop)
++{
++      /* From userspace */
++      
++      struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
++
++      u_int8_t random_number;
++      unsigned long amount;
++      u_int8_t howhigh, howlow;
++      
++
++      spin_lock_bh(&fuzzy_lock); /* Rise the lock */
++
++      info->bytes_total += pskb->len;
++      info->packets_total++;
++
++      info->present_time = jiffies;
++      
++      if (info->present_time >= info->previous_time)
++              amount = info->present_time - info->previous_time;
++      else { 
++              /* There was a transition : I choose to re-sample 
++                 and keep the old acceptance rate...
++              */
++
++              amount = 0;
++              info->previous_time = info->present_time;
++              info->bytes_total = info->packets_total = 0;
++      };
++      
++      if (amount > HZ/10) /* More than 100 ms elapsed ... */
++      {
++
++              info->mean_rate = (u_int32_t) ((HZ*info->packets_total)  \
++                                      / amount );
++
++              info->previous_time = info->present_time;
++              info->bytes_total = info->packets_total = 0;
++
++              howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
++              howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
++
++              info->acceptance_rate = (u_int8_t) \
++                         (howhigh*PAR_LOW + PAR_HIGH*howlow);
++
++              /* In fact , the above defuzzification would require a denominator
++                 proportional to (howhigh+howlow) but , in this particular case ,
++                 that expression is constant .
++                 An imediate consequence is that it isn't necessary to call 
++                 both mf_high and mf_low - but to keep things understandable ,
++                 I did so .  */ 
++
++      }
++      
++      spin_unlock_bh(&fuzzy_lock); /* Release the lock */
++
++
++      if ( info->acceptance_rate < 100 )
++      {                
++              get_random_bytes((void *)(&random_number), 1);
++
++              /*  If within the acceptance , it can pass => don't match */
++              if (random_number <= (255 * info->acceptance_rate) / 100)
++                      return 0;
++              else
++                      return 1; /* It can't pass ( It matches ) */
++      } ;
++
++      return 0; /* acceptance_rate == 100 % => Everything passes ... */
++      
++}
++
++static int
++ipt_fuzzy_checkentry(const char *tablename,
++                 const struct ipt_ip *e,
++                 void *matchinfo,
++                 unsigned int matchsize,
++                 unsigned int hook_mask)
++{
++      
++      const struct ipt_fuzzy_info *info = matchinfo;
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
++              printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
++                     IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
++              return 0;
++      }
++
++      if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
++          || (info->minimum_rate >= info->maximum_rate )) {
++              printk("ipt_fuzzy: BAD limits , please verify !!!\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_match ipt_fuzzy_reg = { 
++      .name = "fuzzy",
++      .match = ipt_fuzzy_match,
++      .checkentry = ipt_fuzzy_checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&ipt_fuzzy_reg);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&ipt_fuzzy_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.7/net/ipv4/netfilter/ipt_ipv4options.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_ipv4options.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_ipv4options.c   2004-09-07 12:33:15.334220480 +0200
+@@ -0,0 +1,172 @@
++/*
++  This is a module which is used to match ipv4 options.
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from:
++  ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++  11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++  12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
++  12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
++  18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
++  19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_ipv4options.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
++
++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)
++{
++      const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
++      const struct iphdr *iph = skb->nh.iph;
++      const struct ip_options *opt;
++
++      if (iph->ihl * 4 == sizeof(struct iphdr)) {
++              /* No options, so we match only the "DONTs" and the "IGNOREs" */
++
++              if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
++                  ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++                  ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
++                  ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
++                  ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
++                    ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
++                      return 0;
++              return 1;
++      }
++      else {
++              if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
++                      /* there are options, and we don't need to care which one */
++                      return 1;
++              else {
++                      if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
++                              /* there are options but we don't want any ! */
++                              return 0;
++              }
++      }
++
++      opt = &(IPCB(skb)->opt);
++
++      /* source routing */
++      if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
++              if (!((opt->srr) & (opt->is_strictroute)))
++                      return 0;
++      }
++      else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
++              if (!((opt->srr) & (!opt->is_strictroute)))
++                      return 0;
++      }
++      else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
++              if (opt->srr)
++                      return 0;
++      }
++      /* record route */
++      if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
++              if (!opt->rr)
++                      return 0;
++      }
++      else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
++              if (opt->rr)
++                      return 0;
++      }
++      /* timestamp */
++      if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
++              if (!opt->ts)
++                      return 0;
++      }
++      else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
++              if (opt->ts)
++                      return 0;
++      }
++      /* router-alert option  */
++      if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
++              if (!opt->router_alert)
++                      return 0;
++      }
++      else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
++              if (opt->router_alert)
++                      return 0;
++      }
++
++      /* we match ! */
++      return 1;
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_ip *ip,
++         void *matchinfo,
++         unsigned int matchsize,
++         unsigned int hook_mask)
++{
++      const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
++      /* Check the size */
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
++              return 0;
++      /* Now check the coherence of the data ... */
++      if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
++          (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
++           ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
++           ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
++           ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
++           ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
++              return 0; /* opposites */
++      if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
++          (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
++              return 0; /* opposites */
++      if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
++          ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
++              return 0; /* cannot match in the same time loose and strict source routing */
++      if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++           ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
++          ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
++              return 0; /* opposites */
++      if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
++          ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
++              return 0; /* opposites */
++      if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
++          ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
++              return 0; /* opposites */
++      if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
++          ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
++              return 0; /* opposites */
++
++      /* everything looks ok. */
++      return 1;
++}
++
++static struct ipt_match ipv4options_match = { 
++      .name = "ipv4options",
++      .match = match,
++      .checkentry = checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&ipv4options_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&ipv4options_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.7/net/ipv4/netfilter/ipt_mport.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_mport.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_mport.c 2004-09-07 12:33:16.384060880 +0200
+@@ -0,0 +1,116 @@
++/* Kernel module to match one of a list of TCP/UDP ports: ports are in
++   the same place so we can treat them as equal. */
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/udp.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ipt_mport.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_LICENSE("GPL");
++
++#if 0
++#define duprintf(format, args...) printk(format , ## args)
++#else
++#define duprintf(format, args...)
++#endif
++
++/* Returns 1 if the port is matched by the test, 0 otherwise. */
++static inline int
++ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
++{
++      unsigned int i;
++        unsigned int m;
++        u_int16_t pflags = minfo->pflags;
++      for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
++                u_int16_t s, e;
++
++                if (pflags & m
++                    && minfo->ports[i] == 65535)
++                        return 0;
++
++                s = minfo->ports[i];
++
++                if (pflags & m) {
++                        e = minfo->ports[++i];
++                        m <<= 1;
++                } else
++                        e = s;
++
++                if (minfo->flags & IPT_MPORT_SOURCE
++                    && src >= s && src <= e)
++                        return 1;
++
++              if (minfo->flags & IPT_MPORT_DESTINATION
++                  && dst >= s && dst <= e)
++                      return 1;
++      }
++
++      return 0;
++}
++
++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)
++{
++      u16 ports[2];
++      const struct ipt_mport *minfo = matchinfo;
++
++      if (offset)
++              return 0;
++
++      /* Must be big enough to read ports (both UDP and TCP have
++           them at the start). */
++      if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
++              /* We've been asked to examine this packet, and we
++                 can't.  Hence, no choice but to drop. */
++                      duprintf("ipt_multiport:"
++                               " Dropping evil offset=0 tinygram.\n");
++                      *hotdrop = 1;
++                      return 0;
++      }
++
++      return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
++}
++
++/* Called when user tries to insert an entry of this type. */
++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_mport)))
++              return 0;
++
++      /* Must specify proto == TCP/UDP, no unknown flags or bad count */
++      return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
++              && !(ip->invflags & IPT_INV_PROTO)
++              && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
++}
++
++static struct ipt_match mport_match = { 
++      .name = "mport",
++      .match = &match,
++      .checkentry = &checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&mport_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&mport_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.7/net/ipv4/netfilter/ipt_nth.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_nth.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_nth.c   2004-09-07 12:33:17.547883952 +0200
+@@ -0,0 +1,166 @@
++/*
++  This is a module which is used for match support for every Nth packet
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from:
++     ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
++        * added support for multiple counters
++        * added support for matching on individual packets
++          in the counter cycle
++  2004-02-19 Harald Welte <laforge@netfilter.org>
++      * port to 2.6.x
++
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_nth.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
++
++/*
++ * State information.
++ */
++struct state {
++      spinlock_t lock;
++      u_int16_t number;
++};
++
++static struct state states[IPT_NTH_NUM_COUNTERS];
++
++static int
++ipt_nth_match(const struct sk_buff *pskb,
++            const struct net_device *in,
++            const struct net_device *out,
++            const void *matchinfo,
++            int offset,
++            int *hotdrop)
++{
++      /* Parameters from userspace */
++      const struct ipt_nth_info *info = matchinfo;
++        unsigned counter = info->counter;
++              if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
++              {
++                      printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
++               return 0;
++        };
++
++        spin_lock(&states[counter].lock);
++
++        /* Are we matching every nth packet?*/
++        if (info->packet == 0xFF)
++        {
++              /* We're matching every nth packet and only every nth packet*/
++              /* Do we match or invert match? */
++              if (info->not == 0)
++              {
++                      if (states[counter].number == 0)
++                      {
++                              ++states[counter].number;
++                              goto match;
++                      }
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0; /* reset the counter */
++                      else
++                              ++states[counter].number;
++                      goto dontmatch;
++              }
++              else
++              {
++                      if (states[counter].number == 0)
++                      {
++                              ++states[counter].number;
++                              goto dontmatch;
++                      }
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0;
++                      else
++                              ++states[counter].number;
++                      goto match;
++              }
++        }
++        else
++        {
++              /* We're using the --packet, so there must be a rule for every value */
++              if (states[counter].number == info->packet)
++              {
++                      /* only increment the counter when a match happens */
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0; /* reset the counter */
++                      else
++                              ++states[counter].number;
++                      goto match;
++              }
++              else
++                      goto dontmatch;
++      }
++
++ dontmatch:
++      /* don't match */
++      spin_unlock(&states[counter].lock);
++      return 0;
++
++ match:
++      spin_unlock(&states[counter].lock);
++      return 1;
++}
++
++static int
++ipt_nth_checkentry(const char *tablename,
++                 const struct ipt_ip *e,
++                 void *matchinfo,
++                 unsigned int matchsize,
++                 unsigned int hook_mask)
++{
++      /* Parameters from userspace */
++      const struct ipt_nth_info *info = matchinfo;
++        unsigned counter = info->counter;
++        if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
++      {
++              printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
++                      return 0;
++              };
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
++              printk("nth: matchsize %u != %u\n", matchsize,
++                     IPT_ALIGN(sizeof(struct ipt_nth_info)));
++              return 0;
++      }
++
++      states[counter].number = info->startat;
++
++      return 1;
++}
++
++static struct ipt_match ipt_nth_reg = { 
++      .name = "nth",
++      .match = ipt_nth_match,
++      .checkentry = ipt_nth_checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      unsigned counter;
++
++      memset(&states, 0, sizeof(states));
++        for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) 
++              spin_lock_init(&(states[counter].lock));
++
++      return ipt_register_match(&ipt_nth_reg);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&ipt_nth_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.7/net/ipv4/netfilter/ipt_osf.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_osf.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_osf.c   2004-09-07 12:33:18.674712648 +0200
+@@ -0,0 +1,873 @@
++/*
++ * ipt_osf.c
++ *
++ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
++ *
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ * OS fingerprint matching module.
++ * It simply compares various parameters from SYN packet with
++ * some hardcoded ones.
++ *
++ * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
++ * for his p0f.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <linux/ip.h>
++#include <linux/proc_fs.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/ctype.h>
++#include <linux/list.h>
++#include <linux/if.h>
++
++#include <net/sock.h>
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#include <linux/netfilter_ipv4/ipt_osf.h>
++
++#define OSF_DEBUG
++
++#ifdef OSF_DEBUG
++#define log(x...)             printk(KERN_INFO "ipt_osf: " x)
++#define loga(x...)            printk(x)
++#else
++#define log(x...)             do {} while(0)
++#define loga(x...)            do {} while(0)
++#endif
++
++#define FMATCH_WRONG          0
++#define FMATCH_OK             1
++#define FMATCH_OPT_WRONG      2
++
++#define OPTDEL                        ','
++#define OSFPDEL               ':'
++#define MAXOPTSTRLEN          128
++#define OSFFLUSH              "FLUSH"
++
++static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
++static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head       finger_list;    
++static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
++                    const void *, int, 
++                    int *);
++static int checkentry(const char *, const struct ipt_ip *, void *,
++                         unsigned int, unsigned int);
++
++static unsigned long seq, ipt_osf_groups = 1;
++static struct sock *nts;
++
++static struct ipt_match osf_match = 
++{ 
++      { NULL, NULL }, 
++      "osf", 
++      &match, 
++      &checkentry, 
++      NULL, 
++      THIS_MODULE 
++};
++
++static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
++{
++      unsigned int size;
++      struct sk_buff *skb;
++      struct ipt_osf_nlmsg *data;
++      struct nlmsghdr *nlh;
++
++      size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
++
++      skb = alloc_skb(size, GFP_ATOMIC);
++      if (!skb)
++      {
++              log("skb_alloc() failed.\n");
++              return;
++      }
++      
++      nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
++      
++      data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
++
++      memcpy(&data->f, f, sizeof(struct osf_finger));
++      memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
++      memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
++
++      NETLINK_CB(skb).dst_groups = ipt_osf_groups;
++      netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
++
++nlmsg_failure:
++      return;
++}
++
++static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
++{
++      struct iphdr *ip = skb->nh.iph;
++
++      if (flags & IPT_OSF_SMART)
++      {
++              struct in_device *in_dev = in_dev_get(skb->dev);
++
++              for_ifa(in_dev)
++              {
++                      if (inet_ifa_match(ip->saddr, ifa))
++                      {
++                              in_dev_put(in_dev);
++                              return (ip->ttl == f_ttl);
++                      }
++              }
++              endfor_ifa(in_dev);
++              
++              in_dev_put(in_dev);
++              return (ip->ttl <= f_ttl);
++      }
++      else
++              return (ip->ttl == f_ttl);
++}
++
++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_osf_info *info = (struct ipt_osf_info *)matchinfo;
++      struct iphdr *ip = skb->nh.iph;
++      struct tcphdr *tcp;
++      int fmatch = FMATCH_WRONG, fcount = 0;
++      unsigned long totlen, optsize = 0, window;
++      unsigned char df, *optp = NULL, *_optp = NULL;
++      char check_WSS = 0;
++      struct list_head *ent;
++      struct osf_finger *f;
++
++      if (!ip || !info)
++              return 0;
++                              
++      tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
++
++      if (!tcp->syn)
++              return 0;
++      
++      totlen = ntohs(ip->tot_len);
++      df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
++      window = ntohs(tcp->window);
++      
++      if (tcp->doff*4 > sizeof(struct tcphdr))
++      {
++              _optp = optp = (char *)(tcp+1);
++              optsize = tcp->doff*4 - sizeof(struct tcphdr);
++      }
++
++      /* Actually we can create hash/table of all genres and search
++       * only in appropriate part, but here is initial variant,
++       * so will use slow path.
++       */
++      read_lock(&osf_lock);
++      list_for_each(ent, &finger_list)
++      {
++              f = list_entry(ent, struct osf_finger, flist);
++      
++              if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
++                      continue;
++
++              optp = _optp;
++              fmatch = FMATCH_WRONG;
++
++              if (totlen == f->ss && df == f->df && 
++                      smart_dec(skb, info->flags, f->ttl))
++              {
++                      unsigned long foptsize;
++                      int optnum;
++                      unsigned short mss = 0;
++
++                      check_WSS = 0;
++
++                      switch (f->wss.wc)
++                      {
++                              case 0:   check_WSS = 0; break;
++                              case 'S': check_WSS = 1; break;
++                              case 'T': check_WSS = 2; break;
++                              case '%': check_WSS = 3; break;
++                              default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
++                                                       f->wss.wc, f->genre, f->details);
++                                       check_WSS = 4;
++                                       break;
++                      }
++                      if (check_WSS == 4)
++                              continue;
++
++                      /* Check options */
++
++                      foptsize = 0;
++                      for (optnum=0; optnum<f->opt_num; ++optnum)
++                              foptsize += f->opt[optnum].length;
++
++                              
++                      if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
++                              continue;
++
++                      if (!optp)
++                      {
++                              fmatch = FMATCH_OK;
++                              loga("\tYEP : matching without options.\n");
++                              if ((info->flags & IPT_OSF_LOG) && 
++                                      info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
++                                      break;
++                              else
++                                      continue;
++                      }
++                      
++
++                      for (optnum=0; optnum<f->opt_num; ++optnum)
++                      {
++                              if (f->opt[optnum].kind == (*optp)) 
++                              {
++                                      unsigned char len = f->opt[optnum].length;
++                                      unsigned char *optend = optp + len;
++                                      int loop_cont = 0;
++
++                                      fmatch = FMATCH_OK;
++
++
++                                      switch (*optp)
++                                      {
++                                              case OSFOPT_MSS:
++                                                      mss = ntohs(*(unsigned short *)(optp+2));
++                                                      break;
++                                              case OSFOPT_TS:
++                                                      loop_cont = 1;
++                                                      break;
++                                      }
++                                      
++                                      if (loop_cont)
++                                      {
++                                              optp = optend;
++                                              continue;
++                                      }
++                                      
++                                      if (len != 1)
++                                      {
++                                              /* Skip kind and length fields*/
++                                              optp += 2; 
++
++                                              if (f->opt[optnum].wc.val != 0)
++                                              {
++                                                      unsigned long tmp = 0;
++                                                      
++                                                      /* Hmmm... It looks a bit ugly. :) */
++                                                      memcpy(&tmp, optp, 
++                                                              (len > sizeof(unsigned long)?
++                                                                      sizeof(unsigned long):len));
++                                                      /* 2 + 2: optlen(2 bytes) + 
++                                                       *      kind(1 byte) + length(1 byte) */
++                                                      if (len == 4) 
++                                                              tmp = ntohs(tmp);
++                                                      else
++                                                              tmp = ntohl(tmp);
++
++                                                      if (f->opt[optnum].wc.wc == '%')
++                                                      {
++                                                              if ((tmp % f->opt[optnum].wc.val) != 0)
++                                                                      fmatch = FMATCH_OPT_WRONG;
++                                                      }
++                                                      else if (tmp != f->opt[optnum].wc.val)
++                                                              fmatch = FMATCH_OPT_WRONG;
++                                              }
++                                      }
++
++                                      optp = optend;
++                              }
++                              else
++                                      fmatch = FMATCH_OPT_WRONG;
++
++                              if (fmatch != FMATCH_OK)
++                                      break;
++                      }
++
++                      if (fmatch != FMATCH_OPT_WRONG)
++                      {
++                              fmatch = FMATCH_WRONG;
++
++                              switch (check_WSS)
++                              {
++                                      case 0:
++                                              if (f->wss.val == 0 || window == f->wss.val)
++                                                      fmatch = FMATCH_OK;
++                                              break;
++                                      case 1: /* MSS */
++/* Lurked in OpenBSD */
++#define SMART_MSS     1460
++                                              if (window == f->wss.val*mss || 
++                                                      window == f->wss.val*SMART_MSS)
++                                                      fmatch = FMATCH_OK;
++                                              break;
++                                      case 2: /* MTU */
++                                              if (window == f->wss.val*(mss+40) ||
++                                                      window == f->wss.val*(SMART_MSS+40))
++                                                      fmatch = FMATCH_OK;
++                                              break;
++                                      case 3: /* MOD */
++                                              if ((window % f->wss.val) == 0)
++                                                      fmatch = FMATCH_OK;
++                                              break;
++                              }
++                      }
++                                      
++
++                      if (fmatch == FMATCH_OK)
++                      {
++                              fcount++;
++                              log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
++                                      f->genre, f->version,
++                                      f->subtype, f->details,
++                                      NIPQUAD(ip->saddr), ntohs(tcp->source),
++                                      NIPQUAD(ip->daddr), ntohs(tcp->dest),
++                                      f->ttl - ip->ttl);
++                              if (info->flags & IPT_OSF_NETLINK)
++                              {
++                                      spin_lock_bh(&ipt_osf_netlink_lock);
++                                      ipt_osf_nlsend(f, skb);
++                                      spin_unlock_bh(&ipt_osf_netlink_lock);
++                              }
++                              if ((info->flags & IPT_OSF_LOG) && 
++                                      info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
++                                      break;
++                      }
++              }
++      }
++      if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
++      {
++              unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
++              unsigned int i, optsize;
++              struct osf_finger fg;
++
++              memset(&fg, 0, sizeof(fg));
++
++              if ((info->flags & IPT_OSF_LOG))
++                      log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
++              if (optp)
++              {
++                      optsize = tcp->doff * 4 - sizeof(struct tcphdr);
++                      if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
++                                        opt, optsize) < 0)
++                      {
++                              if (info->flags & IPT_OSF_LOG)
++                                      loga("TRUNCATED");
++                              if (info->flags & IPT_OSF_NETLINK)
++                                      strcpy(fg.details, "TRUNCATED");
++                      }
++                      else
++                      {
++                              for (i = 0; i < optsize; i++)
++                              {
++                                      if (info->flags & IPT_OSF_LOG)
++                                              loga("%02X", opt[i]);
++                              }
++                              if (info->flags & IPT_OSF_NETLINK)
++                                      memcpy(fg.details, opt, MAXDETLEN);
++                      }
++              }
++              if ((info->flags & IPT_OSF_LOG))
++                      loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
++                              NIPQUAD(ip->saddr), ntohs(tcp->source),
++                              NIPQUAD(ip->daddr), ntohs(tcp->dest));
++              
++              if (info->flags & IPT_OSF_NETLINK)
++              {
++                      fg.wss.val      = window;
++                      fg.ttl          = ip->ttl;
++                      fg.df           = df;
++                      fg.ss           = totlen;
++                      strncpy(fg.genre, "Unknown", MAXGENRELEN);
++
++                      spin_lock_bh(&ipt_osf_netlink_lock);
++                      ipt_osf_nlsend(&fg, skb);
++                      spin_unlock_bh(&ipt_osf_netlink_lock);
++              }
++      }
++
++      read_unlock(&osf_lock);
++      
++      if (fcount)
++              fmatch = FMATCH_OK;
++
++      return (fmatch == FMATCH_OK)?1:0;
++}
++
++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_osf_info)))
++               return 0;
++       if (ip->proto != IPPROTO_TCP)
++             return 0;
++
++       return 1;
++}
++
++static char * osf_strchr(char *ptr, char c)
++{
++      char *tmp;
++
++      tmp = strchr(ptr, c);
++
++      while (tmp && tmp+1 && isspace(*(tmp+1)))
++              tmp++;
++
++      return tmp;
++}
++
++static struct osf_finger * finger_alloc(void)
++{
++      struct osf_finger *f;
++
++      f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
++      if (f)
++              memset(f, 0, sizeof(struct osf_finger));
++      
++      return f;
++}
++
++static void finger_free(struct osf_finger *f)
++{
++      memset(f, 0, sizeof(struct osf_finger));
++      kfree(f);
++}
++
++
++static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
++{
++      int i, op;
++      char *ptr, wc;
++      unsigned long val;
++
++      ptr = &obuf[0];
++      i = 0;
++      while (ptr != NULL && i < olen)
++      {
++              val = 0;
++              op = 0;
++              wc = 0;
++              switch (obuf[i])
++              {
++                      case 'N': 
++                              op = OSFOPT_NOP;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      *ptr = '\0';
++                                      ptr++;
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      case 'S': 
++                              op = OSFOPT_SACKP;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      *ptr = '\0';
++                                      ptr++;
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      case 'T': 
++                              op = OSFOPT_TS;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      *ptr = '\0';
++                                      ptr++;
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      case 'W': 
++                              op = OSFOPT_WSO;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      switch (obuf[i+1])
++                                      {
++                                              case '%':       wc = '%'; break;
++                                              case 'S':       wc = 'S'; break;
++                                              case 'T':       wc = 'T'; break;
++                                              default:        wc = 0; break;
++                                      }
++                                      
++                                      *ptr = '\0';
++                                      ptr++;
++                                      if (wc)
++                                              val = simple_strtoul(&obuf[i+2], NULL, 10);
++                                      else
++                                              val = simple_strtoul(&obuf[i+1], NULL, 10);
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      case 'M': 
++                              op = OSFOPT_MSS;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      if (obuf[i+1] == '%')
++                                              wc = '%';
++                                      *ptr = '\0';
++                                      ptr++;
++                                      if (wc)
++                                              val = simple_strtoul(&obuf[i+2], NULL, 10);
++                                      else
++                                              val = simple_strtoul(&obuf[i+1], NULL, 10);
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      case 'E': 
++                              op = OSFOPT_EOL;
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      *ptr = '\0';
++                                      ptr++;
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++                      default:
++                              ptr = osf_strchr(&obuf[i], OPTDEL);
++                              if (ptr)
++                              {
++                                      ptr++;
++                                      i += (int)(ptr-&obuf[i]);
++
++                              }
++                              else
++                                      i++;
++                              break;
++              }
++
++              opt[*optnum].kind       = IANA_opts[op].kind;
++              opt[*optnum].length     = IANA_opts[op].length;
++              opt[*optnum].wc.wc      = wc;
++              opt[*optnum].wc.val     = val;
++
++              (*optnum)++;
++      }
++}
++
++static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
++{
++      struct list_head *ent;
++      struct osf_finger *f = NULL;
++      int i, __count, err;
++      
++      *eof = 1;
++      __count = count;
++      count = 0;
++
++      read_lock_bh(&osf_lock);
++      list_for_each(ent, &finger_list)
++      {
++              f = list_entry(ent, struct osf_finger, flist);
++
++              log("%s [%s]", f->genre, f->details);
++              
++              err = snprintf(buf+count, __count-count, "%s - %s[%s] : %s", 
++                                      f->genre, f->version,
++                                      f->subtype, f->details);
++              if (err == 0 || __count <= count + err)
++                      break;
++              else
++                      count += err;
++              if (f->opt_num)
++              {
++                      loga(" OPT: ");
++                      //count += sprintf(buf+count, " OPT: ");
++                      for (i=0; i<f->opt_num; ++i)
++                      {
++                              //count += sprintf(buf+count, "%d.%c%lu; ", 
++                              //      f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
++                              loga("%d.%c%lu; ", 
++                                      f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
++                      }
++              }
++              loga("\n");
++              err = snprintf(buf+count, __count-count, "\n");
++              if (err == 0 || __count <= count + err)
++                      break;
++              else
++                      count += err;
++      }
++      read_unlock_bh(&osf_lock);
++
++      return count;
++}
++
++static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++      int cnt;
++      unsigned long i;
++      char obuf[MAXOPTSTRLEN];
++      struct osf_finger *finger;
++      struct list_head *ent, *n;
++
++      char *pbeg, *pend;
++
++      if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
++      {
++              int i = 0;
++              write_lock_bh(&osf_lock);
++              list_for_each_safe(ent, n, &finger_list)
++              {
++                      i++;
++                      finger = list_entry(ent, struct osf_finger, flist);
++                      list_del(&finger->flist);
++                      finger_free(finger);
++              }
++              write_unlock_bh(&osf_lock);
++      
++              log("Flushed %d entries.\n", i);
++              
++              return count;
++      }
++
++      
++      cnt = 0;
++      for (i=0; i<count && buffer[i] != '\0'; ++i)
++              if (buffer[i] == ':')
++                      cnt++;
++
++      if (cnt != 8 || i != count)
++      {
++              log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
++                      cnt, i, count);
++              return count;
++      }
++
++      memset(obuf, 0, sizeof(obuf));
++      
++      finger = finger_alloc();
++      if (!finger)
++      {
++              log("Failed to allocate new fingerprint entry.\n");
++              return -ENOMEM;
++      }
++
++      pbeg = (char *)buffer;
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              if (pbeg[0] == 'S')
++              {
++                      finger->wss.wc = 'S';
++                      if (pbeg[1] == '%')
++                              finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
++                      else if (pbeg[1] == '*')
++                              finger->wss.val = 0;
++                      else 
++                              finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++              }
++              else if (pbeg[0] == 'T')
++              {
++                      finger->wss.wc = 'T';
++                      if (pbeg[1] == '%')
++                              finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
++                      else if (pbeg[1] == '*')
++                              finger->wss.val = 0;
++                      else 
++                              finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++              }
++              else if (pbeg[0] == '%')
++              {
++                      finger->wss.wc = '%';
++                      finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++              }
++              else if (isdigit(pbeg[0]))
++              {
++                      finger->wss.wc = 0;
++                      finger->wss.val = simple_strtoul(pbeg, NULL, 10);
++              }
++
++              pbeg = pend+1;
++      }
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              finger->ttl = simple_strtoul(pbeg, NULL, 10);
++              pbeg = pend+1;
++      }
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              finger->df = simple_strtoul(pbeg, NULL, 10);
++              pbeg = pend+1;
++      }
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              finger->ss = simple_strtoul(pbeg, NULL, 10);
++              pbeg = pend+1;
++      }
++
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
++              pbeg = pend+1;
++      }
++
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              if (pbeg[0] == '@' || pbeg[0] == '*')
++                      cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
++              else
++                      cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
++              pbeg = pend+1;
++      }
++      
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
++              pbeg = pend+1;
++      }
++      
++      pend = osf_strchr(pbeg, OSFPDEL);
++      if (pend)
++      {
++              *pend = '\0';
++              cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
++              pbeg = pend+1;
++      }
++
++      cnt = snprintf(finger->details, 
++                      ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
++                      "%s", pbeg);
++      
++      log("%s - %s[%s] : %s\n", 
++              finger->genre, finger->version,
++              finger->subtype, finger->details);
++      
++      osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
++      
++
++      write_lock_bh(&osf_lock);
++      list_add_tail(&finger->flist, &finger_list);
++      write_unlock_bh(&osf_lock);
++
++      return count;
++}
++
++static int __init osf_init(void)
++{
++      int err;
++      struct proc_dir_entry *p;
++
++      log("Startng OS fingerprint matching module.\n");
++
++      INIT_LIST_HEAD(&finger_list);
++      
++      err = ipt_register_match(&osf_match);
++      if (err)
++      {
++              log("Failed to register OS fingerprint matching module.\n");
++              return -ENXIO;
++      }
++
++      p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
++      if (!p)
++      {
++              ipt_unregister_match(&osf_match);
++              return -ENXIO;
++      }
++
++      p->write_proc = osf_proc_write;
++      p->read_proc  = osf_proc_read;
++      
++      nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
++      if (!nts)
++      {
++              log("netlink_kernel_create() failed\n");
++              remove_proc_entry("sys/net/ipv4/osf", NULL);
++              ipt_unregister_match(&osf_match);
++              return -ENOMEM;
++      }
++
++      return 0;
++}
++
++static void __exit osf_fini(void)
++{
++      struct list_head *ent, *n;
++      struct osf_finger *f;
++      
++      remove_proc_entry("sys/net/ipv4/osf", NULL);
++      ipt_unregister_match(&osf_match);
++      if (nts && nts->sk_socket)
++              sock_release(nts->sk_socket);
++
++      list_for_each_safe(ent, n, &finger_list)
++      {
++              f = list_entry(ent, struct osf_finger, flist);
++              list_del(&f->flist);
++              finger_free(f);
++      }
++      
++      log("OS fingerprint matching module finished.\n");
++}
++
++module_init(osf_init);
++module_exit(osf_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
++MODULE_DESCRIPTION("Passive OS fingerprint matching.");
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.7/net/ipv4/netfilter/ipt_psd.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_psd.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_psd.c   2004-09-07 12:33:19.724553048 +0200
+@@ -0,0 +1,358 @@
++/*
++  This is a module which is used for PSD (portscan detection)
++  Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
++  and LOG target module.
++
++  Copyright (C) 2000,2001 astaro AG
++
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from:
++     ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++  2000-05-04 Markus Hennig <hennig@astaro.de> : initial
++  2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
++  2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
++  2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
++  2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
++  2004-05-05 Martijn Lievaart <m@rtij.nl> : ported to 2.6
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_psd.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
++
++#define HF_DADDR_CHANGING   0x01
++#define HF_SPORT_CHANGING   0x02
++#define HF_TOS_CHANGING           0x04
++#define HF_TTL_CHANGING           0x08
++
++/*
++ * Information we keep per each target port
++ */
++struct port {
++      u_int16_t number;      /* port number */
++      u_int8_t proto;        /* protocol number */
++      u_int8_t and_flags;    /* tcp ANDed flags */
++      u_int8_t or_flags;     /* tcp ORed flags */
++};
++
++/*
++ * Information we keep per each source address.
++ */
++struct host {
++      struct host *next;              /* Next entry with the same hash */
++      clock_t timestamp;              /* Last update time */
++      struct in_addr src_addr;        /* Source address */
++      struct in_addr dest_addr;       /* Destination address */
++      unsigned short src_port;        /* Source port */
++      int count;                      /* Number of ports in the list */
++      int weight;                     /* Total weight of ports in the list */
++      struct port ports[SCAN_MAX_COUNT - 1];  /* List of ports */
++      unsigned char tos;              /* TOS */
++      unsigned char ttl;              /* TTL */
++      unsigned char flags;            /* HF_ flags bitmask */
++};
++
++/*
++ * State information.
++ */
++static struct {
++      spinlock_t lock;
++      struct host list[LIST_SIZE];    /* List of source addresses */
++      struct host *hash[HASH_SIZE];   /* Hash: pointers into the list */
++      int index;                      /* Oldest entry to be replaced */
++} state;
++
++/*
++ * Convert an IP address into a hash table index.
++ */
++static inline int hashfunc(struct in_addr addr)
++{
++      unsigned int value;
++      int hash;
++
++      value = addr.s_addr;
++      hash = 0;
++      do {
++              hash ^= value;
++      } while ((value >>= HASH_LOG));
++
++      return hash & (HASH_SIZE - 1);
++}
++
++static int
++ipt_psd_match(const struct sk_buff *pskb,
++            const struct net_device *in,
++            const struct net_device *out,
++            const void *matchinfo,
++            int offset,
++            int *hotdrop)
++{
++      struct iphdr *ip_hdr;
++      struct tcphdr *tcp_hdr;
++      struct in_addr addr;
++      u_int16_t src_port,dest_port;
++      u_int8_t tcp_flags, proto;
++      clock_t now;
++      struct host *curr, *last, **head;
++      int hash, index, count;
++
++      /* Parameters from userspace */
++      const struct ipt_psd_info *psdinfo = matchinfo;
++
++      /* IP header */
++      ip_hdr = pskb->nh.iph;
++
++      /* Sanity check */
++      if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
++              DEBUGP("PSD: sanity check failed\n");
++              return 0;
++      }
++
++      /* TCP or UDP ? */
++      proto = ip_hdr->protocol;
++
++      if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
++              DEBUGP("PSD: protocol not supported\n");
++              return 0;
++      }
++
++      /* Get the source address, source & destination ports, and TCP flags */
++
++      addr.s_addr = ip_hdr->saddr;
++
++      tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
++
++      /* Yep, it´s dirty */
++      src_port = tcp_hdr->source;
++      dest_port = tcp_hdr->dest;
++
++      if (proto == IPPROTO_TCP) {
++              tcp_flags = *((u_int8_t*)tcp_hdr + 13);
++      }
++      else {
++              tcp_flags = 0x00;
++      }
++
++      /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
++       * them spoof us. [DHCP needs this feature - HW] */
++      if (!addr.s_addr) {
++              DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
++              return 0;
++      }
++
++      /* Use jiffies here not to depend on someone setting the time while we're
++       * running; we need to be careful with possible return value overflows. */
++      now = jiffies;
++
++      spin_lock(&state.lock);
++
++      /* Do we know this source address already? */
++      count = 0;
++      last = NULL;
++      if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
++              do {
++                      if (curr->src_addr.s_addr == addr.s_addr) break;
++                      count++;
++                      if (curr->next) last = curr;
++              } while ((curr = curr->next));
++
++      if (curr) {
++
++              /* We know this address, and the entry isn't too old. Update it. */
++              if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
++                  time_after_eq(now, curr->timestamp)) {
++
++                      /* Just update the appropriate list entry if we've seen this port already */
++                      for (index = 0; index < curr->count; index++) {
++                              if (curr->ports[index].number == dest_port) {
++                                      curr->ports[index].proto = proto;
++                                      curr->ports[index].and_flags &= tcp_flags;
++                                      curr->ports[index].or_flags |= tcp_flags;
++                                      goto out_no_match;
++                              }
++                      }
++
++                      /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
++                      if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
++                              goto out_no_match;
++
++                      /* Packet to a new port, and not TCP/ACK: update the timestamp */
++                      curr->timestamp = now;
++
++                      /* Logged this scan already? Then drop the packet. */
++                      if (curr->weight >= psdinfo->weight_threshold)
++                              goto out_match;
++
++                      /* Specify if destination address, source port, TOS or TTL are not fixed */
++                      if (curr->dest_addr.s_addr != ip_hdr->daddr)
++                              curr->flags |= HF_DADDR_CHANGING;
++                      if (curr->src_port != src_port)
++                              curr->flags |= HF_SPORT_CHANGING;
++                      if (curr->tos != ip_hdr->tos)
++                              curr->flags |= HF_TOS_CHANGING;
++                      if (curr->ttl != ip_hdr->ttl)
++                              curr->flags |= HF_TTL_CHANGING;
++
++                      /* Update the total weight */
++                      curr->weight += (ntohs(dest_port) < 1024) ?
++                              psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++
++                      /* Got enough destination ports to decide that this is a scan? */
++                      /* Then log it and drop the packet. */
++                      if (curr->weight >= psdinfo->weight_threshold)
++                              goto out_match;
++
++                      /* Remember the new port */
++                      if (curr->count < SCAN_MAX_COUNT) {
++                              curr->ports[curr->count].number = dest_port;
++                              curr->ports[curr->count].proto = proto;
++                              curr->ports[curr->count].and_flags = tcp_flags;
++                              curr->ports[curr->count].or_flags = tcp_flags;
++                              curr->count++;
++                      }
++
++                      goto out_no_match;
++              }
++
++              /* We know this address, but the entry is outdated. Mark it unused, and
++               * remove from the hash table. We'll allocate a new entry instead since
++               * this one might get re-used too soon. */
++              curr->src_addr.s_addr = 0;
++              if (last)
++                      last->next = last->next->next;
++              else if (*head)
++                      *head = (*head)->next;
++              last = NULL;
++      }
++
++      /* We don't need an ACK from a new source address */
++      if (proto == IPPROTO_TCP && tcp_hdr->ack)
++              goto out_no_match;
++
++      /* Got too many source addresses with the same hash value? Then remove the
++       * oldest one from the hash table, so that they can't take too much of our
++       * CPU time even with carefully chosen spoofed IP addresses. */
++      if (count >= HASH_MAX && last) last->next = NULL;
++
++      /* We're going to re-use the oldest list entry, so remove it from the hash
++       * table first (if it is really already in use, and isn't removed from the
++       * hash table already because of the HASH_MAX check above). */
++
++      /* First, find it */
++      if (state.list[state.index].src_addr.s_addr)
++              head = &state.hash[hashfunc(state.list[state.index].src_addr)];
++      else
++              head = &last;
++      last = NULL;
++      if ((curr = *head))
++      do {
++              if (curr == &state.list[state.index]) break;
++              last = curr;
++      } while ((curr = curr->next));
++
++      /* Then, remove it */
++      if (curr) {
++              if (last)
++                      last->next = last->next->next;
++              else if (*head)
++                      *head = (*head)->next;
++      }
++
++      /* Get our list entry */
++      curr = &state.list[state.index++];
++      if (state.index >= LIST_SIZE) state.index = 0;
++
++      /* Link it into the hash table */
++      head = &state.hash[hash];
++      curr->next = *head;
++      *head = curr;
++
++      /* And fill in the fields */
++      curr->timestamp = now;
++      curr->src_addr = addr;
++      curr->dest_addr.s_addr = ip_hdr->daddr;
++      curr->src_port = src_port;
++      curr->count = 1;
++      curr->weight = (ntohs(dest_port) < 1024) ?
++              psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++      curr->ports[0].number = dest_port;
++      curr->ports[0].proto = proto;
++      curr->ports[0].and_flags = tcp_flags;
++      curr->ports[0].or_flags = tcp_flags;
++      curr->tos = ip_hdr->tos;
++      curr->ttl = ip_hdr->ttl;
++
++out_no_match:
++      spin_unlock(&state.lock);
++      return 0;
++
++out_match:
++      spin_unlock(&state.lock);
++      return 1;
++}
++
++static int ipt_psd_checkentry(const char *tablename,
++                            const struct ipt_ip *e,
++                            void *matchinfo,
++                            unsigned int matchsize,
++                            unsigned int hook_mask)
++{
++/*    const struct ipt_psd_info *psdinfo = targinfo;*/
++
++      /* we accept TCP only */
++/*    if (e->ip.proto != IPPROTO_TCP) { */
++/*            DEBUGP("PSD: specified protocol may be TCP only\n"); */
++/*            return 0; */
++/*    } */
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
++              DEBUGP("PSD: matchsize %u != %u\n",
++                     matchsize,
++                     IPT_ALIGN(sizeof(struct ipt_psd_info)));
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_match ipt_psd_reg = {
++      .name = "psd",
++      .match = ipt_psd_match,
++      .checkentry = ipt_psd_checkentry,
++      .me = THIS_MODULE };
++
++static int __init init(void)
++{
++      if (ipt_register_match(&ipt_psd_reg))
++              return -EINVAL;
++
++      memset(&state, 0, sizeof(state));
++
++      spin_lock_init(&(state.lock));
++
++      printk("netfilter PSD loaded - (c) astaro AG\n");
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&ipt_psd_reg);
++      printk("netfilter PSD unloaded - (c) astaro AG\n");
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.7/net/ipv4/netfilter/ipt_quota.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_quota.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_quota.c 2004-09-07 12:33:20.690406216 +0200
+@@ -0,0 +1,91 @@
++/* 
++ * netfilter module to enforce network quotas
++ *
++ * Sam Johnston <samj@samj.net>
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_quota.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
++
++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, int *hotdrop)
++{
++        struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
++      unsigned int datalen;
++
++      if (skb->len < sizeof(struct iphdr))
++              return NF_ACCEPT;
++      
++      datalen = skb->len - skb->nh.iph->ihl*4;
++
++        spin_lock_bh(&quota_lock);
++
++        if (q->quota >= datalen) {
++                /* we can afford this one */
++                q->quota -= datalen;
++                spin_unlock_bh(&quota_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(&quota_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? */
++        if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
++                return 0;
++
++        return 1;
++}
++
++static struct ipt_match quota_match = {
++      .name = "quota",
++      .match = match,
++      .checkentry = checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init
++init(void)
++{
++        return ipt_register_match(&quota_match);
++}
++
++static void __exit
++fini(void)
++{
++        ipt_unregister_match(&quota_match);
++}
++
++module_init(init);
++module_exit(fini);
++
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.7/net/ipv4/netfilter/ipt_sctp.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_sctp.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_sctp.c  2004-09-07 12:33:05.390732120 +0200
+@@ -0,0 +1,201 @@
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <net/ip.h>
++#include <linux/sctp.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_sctp.h>
++
++#ifdef DEBUG_SCTP
++#define duprintf(format, args...) printk(format , ## args)
++#else
++#define duprintf(format, args...)
++#endif
++
++#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
++                                            || (!!((invflag) & (option)) ^ (cond)))
++
++static int
++match_flags(const struct ipt_sctp_flag_info *flag_info,
++          const int flag_count,
++          u_int8_t chunktype,
++          u_int8_t chunkflags)
++{
++      int i;
++
++      for (i = 0; i < flag_count; i++) {
++              if (flag_info[i].chunktype == chunktype) {
++                      return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
++              }
++      }
++
++      return 1;
++}
++
++static int
++match_packet(const struct sk_buff *skb,
++           const u_int32_t *chunkmap,
++           int chunk_match_type,
++           const struct ipt_sctp_flag_info *flag_info,
++           const int flag_count,
++           int *hotdrop)
++{
++      int offset;
++      u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
++      sctp_chunkhdr_t sch;
++
++#ifdef DEBUG_SCTP
++      int i = 0;
++#endif
++
++      if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
++              SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
++      }
++
++      offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
++      do {
++              if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
++                      duprintf("Dropping invalid SCTP packet.\n");
++                      *hotdrop = 1;
++                      return 0;
++              }
++
++              duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
++                              ++i, offset, sch.type, htons(sch.length), sch.flags);
++
++              offset += (htons(sch.length) + 3) & ~3;
++
++              duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
++
++              if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
++                      switch (chunk_match_type) {
++                      case SCTP_CHUNK_MATCH_ANY:
++                              if (match_flags(flag_info, flag_count, 
++                                      sch.type, sch.flags)) {
++                                      return 1;
++                              }
++                              break;
++
++                      case SCTP_CHUNK_MATCH_ALL:
++                              if (match_flags(flag_info, flag_count, 
++                                      sch.type, sch.flags)) {
++                                      SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
++                              }
++                              break;
++
++                      case SCTP_CHUNK_MATCH_ONLY:
++                              if (!match_flags(flag_info, flag_count, 
++                                      sch.type, sch.flags)) {
++                                      return 0;
++                              }
++                              break;
++                      }
++              } else {
++                      switch (chunk_match_type) {
++                      case SCTP_CHUNK_MATCH_ONLY:
++                              return 0;
++                      }
++              }
++      } while (offset < skb->len);
++
++      switch (chunk_match_type) {
++      case SCTP_CHUNK_MATCH_ALL:
++              return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
++      case SCTP_CHUNK_MATCH_ANY:
++              return 0;
++      case SCTP_CHUNK_MATCH_ONLY:
++              return 1;
++      }
++
++      /* This will never be reached, but required to stop compiler whine */
++      return 0;
++}
++
++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)
++{
++      const struct ipt_sctp_info *info;
++      sctp_sctphdr_t sh;
++
++      info = (const struct ipt_sctp_info *)matchinfo;
++
++      if (offset) {
++              duprintf("Dropping non-first fragment.. FIXME\n");
++              return 0;
++      }
++      
++      if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
++              duprintf("Dropping evil TCP offset=0 tinygram.\n");
++              *hotdrop = 1;
++              return 0;
++              }
++      duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
++
++      return  SCCHECK(((ntohs(sh.source) >= info->spts[0]) 
++                      && (ntohs(sh.source) <= info->spts[1])), 
++                      IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
++              && SCCHECK(((ntohs(sh.dest) >= info->dpts[0]) 
++                      && (ntohs(sh.dest) <= info->dpts[1])), 
++                      IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
++              && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
++                                      info->flag_info, info->flag_count, 
++                                      hotdrop),
++                         IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_ip *ip,
++         void *matchinfo,
++         unsigned int matchsize,
++         unsigned int hook_mask)
++{
++      const struct ipt_sctp_info *info;
++
++      info = (const struct ipt_sctp_info *)matchinfo;
++
++      return ip->proto == IPPROTO_SCTP
++              && !(ip->invflags & IPT_INV_PROTO)
++              && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
++              && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
++              && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
++              && !(info->invflags & ~info->flags)
++              && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
++                      (info->chunk_match_type &
++                              (SCTP_CHUNK_MATCH_ALL 
++                              | SCTP_CHUNK_MATCH_ANY
++                              | SCTP_CHUNK_MATCH_ONLY)));
++}
++
++static struct ipt_match sctp_match = 
++{ 
++      .list = { NULL, NULL},
++      .name = "sctp",
++      .match = &match,
++      .checkentry = &checkentry,
++      .destroy = NULL,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&sctp_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&sctp_match);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Kiran Kumar Immidi");
++MODULE_DESCRIPTION("Match for SCTP protocol packets");
++
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_time.c linux-2.6.7/net/ipv4/netfilter/ipt_time.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_time.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_time.c  2004-09-07 12:33:22.072196152 +0200
+@@ -0,0 +1,189 @@
++/*
++  This is a module which is used for time matching
++  It is using some modified code from dietlibc (localtime() function)
++  that you can find at http://www.fefe.de/dietlibc/
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
++  2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++  2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
++     thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
++  2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
++  2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
++     added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
++  2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO.
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_time.h>
++#include <linux/time.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Match arrival timestamp/date");
++MODULE_LICENSE("GPL");
++
++struct tm
++{
++      int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
++      int tm_min;                   /* Minutes.     [0-59] */
++      int tm_hour;                  /* Hours.       [0-23] */
++      int tm_mday;                  /* Day.         [1-31] */
++      int tm_mon;                   /* Month.       [0-11] */
++      int tm_year;                  /* Year - 1900.  */
++      int tm_wday;                  /* Day of week. [0-6] */
++      int tm_yday;                  /* Days in year.[0-365] */
++      int tm_isdst;                 /* DST.         [-1/0/1]*/
++
++      long int tm_gmtoff;           /* we don't care, we count from GMT */
++      const char *tm_zone;          /* we don't care, we count from GMT */
++};
++
++void
++localtime(const time_t *timepr, struct tm *r);
++
++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_time_info *info = matchinfo;   /* match info for rule */
++      struct tm currenttime;                          /* time human readable */
++      u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
++      u_int16_t packet_time;
++      struct timeval kerneltimeval;
++      time_t packet_local_time;
++
++      /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
++      if (info->kerneltime)
++      {
++              do_gettimeofday(&kerneltimeval);
++              packet_local_time = kerneltimeval.tv_sec;
++      }
++      else
++              packet_local_time = skb->stamp.tv_sec;
++
++      /* First we make sure we are in the date start-stop boundaries */
++      if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop))
++              return 0; /* We are outside the date boundaries */
++
++      /* Transform the timestamp of the packet, in a human readable form */
++      localtime(&packet_local_time, &currenttime);
++
++      /* check if we match this timestamp, we start by the days... */
++      if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
++              return 0; /* the day doesn't match */
++
++      /* ... check the time now */
++      packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
++      if ((packet_time < info->time_start) || (packet_time > info->time_stop))
++              return 0;
++
++      /* here we match ! */
++      return 1;
++}
++
++static int
++checkentry(const char *tablename,
++           const struct ipt_ip *ip,
++           void *matchinfo,
++           unsigned int matchsize,
++           unsigned int hook_mask)
++{
++      struct ipt_time_info *info = matchinfo;   /* match info for rule */
++
++      /* First, check that we are in the correct hooks */
++      if (hook_mask
++            & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++      {
++              printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
++              return 0;
++      }
++      /* we use the kerneltime if we are in forward or output */
++      info->kerneltime = 1;
++      if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) 
++              /* we use the skb time */
++              info->kerneltime = 0;
++
++      /* Check the size */
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
++              return 0;
++      /* Now check the coherence of the data ... */
++      if ((info->time_start > 1439) ||        /* 23*60+59 = 1439*/
++          (info->time_stop  > 1439))
++      {
++              printk(KERN_WARNING "ipt_time: invalid argument\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_match time_match
++= { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++      printk("ipt_time loading\n");
++      return ipt_register_match(&time_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&time_match);
++      printk("ipt_time unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
++
++
++/* The part below is borowed and modified from dietlibc */
++
++/* seconds per day */
++#define SPD 24*60*60
++
++void
++localtime(const time_t *timepr, struct tm *r) {
++      time_t i;
++      time_t timep;
++      extern struct timezone sys_tz;
++      const unsigned int __spm[12] =
++              { 0,
++                (31),
++                (31+28),
++                (31+28+31),
++                (31+28+31+30),
++                (31+28+31+30+31),
++                (31+28+31+30+31+30),
++                (31+28+31+30+31+30+31),
++                (31+28+31+30+31+30+31+31),
++                (31+28+31+30+31+30+31+31+30),
++                (31+28+31+30+31+30+31+31+30+31),
++                (31+28+31+30+31+30+31+31+30+31+30),
++              };
++      register time_t work;
++
++      timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
++      work=timep%(SPD);
++      r->tm_sec=work%60; work/=60;
++      r->tm_min=work%60; r->tm_hour=work/60;
++      work=timep/(SPD);
++      r->tm_wday=(4+work)%7;
++      for (i=1970; ; ++i) {
++              register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
++              if (work>k)
++                      work-=k;
++              else
++                      break;
++      }
++      r->tm_year=i-1900;
++      for (i=11; i && __spm[i]>work; --i) ;
++      r->tm_mon=i;
++      r->tm_mday=work-__spm[i]+1;
++}
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.7/net/ipv4/netfilter/ipt_u32.c
+--- linux-2.6.7.org/net/ipv4/netfilter/ipt_u32.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv4/netfilter/ipt_u32.c   2004-09-07 12:38:33.377870496 +0200
+@@ -0,0 +1,211 @@
++/* Kernel module to match u32 packet content. */
++
++/* 
++U32 tests whether quantities of up to 4 bytes extracted from a packet 
++have specified values.  The specification of what to extract is general 
++enough to find data at given offsets from tcp headers or payloads.
++
++ --u32 tests
++ The argument amounts to a program in a small language described below.
++ tests := location = value |  tests && location = value
++ value := range | value , range
++ range := number | number : number
++  a single number, n, is interpreted the same as n:n
++  n:m is interpreted as the range of numbers >=n and <=m
++ location := number | location operator number
++ operator := & | << | >> | @
++
++ The operators &, <<, >>, && mean the same as in c.  The = is really a set
++ membership operator and the value syntax describes a set.  The @ operator
++ is what allows moving to the next header and is described further below.
++
++ *** Until I can find out how to avoid it, there are some artificial limits
++ on the size of the tests:
++ - no more than 10 ='s (and 9 &&'s) in the u32 argument
++ - no more than 10 ranges (and 9 commas) per value
++ - no more than 10 numbers (and 9 operators) per location
++
++ To describe the meaning of location, imagine the following machine that
++ interprets it.  There are three registers:
++  A is of type char*, initially the address of the IP header
++  B and C are unsigned 32 bit integers, initially zero
++
++  The instructions are:
++   number     B = number;
++              C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
++   &number    C = C&number
++   <<number   C = C<<number
++   >>number   C = C>>number
++   @number    A = A+C; then do the instruction number
++  Any access of memory outside [skb->head,skb->end] causes the match to fail.
++  Otherwise the result of the computation is the final value of C.
++
++ Whitespace is allowed but not required in the tests.
++ However the characters that do occur there are likely to require
++ shell quoting, so it's a good idea to enclose the arguments in quotes.
++
++Example:
++ match IP packets with total length >= 256
++ The IP header contains a total length field in bytes 2-3.
++ --u32 "0&0xFFFF=0x100:0xFFFF" 
++ read bytes 0-3
++ AND that with FFFF (giving bytes 2-3),
++ and test whether that's in the range [0x100:0xFFFF]
++
++Example: (more realistic, hence more complicated)
++ match icmp packets with icmp type 0
++ First test that it's an icmp packet, true iff byte 9 (protocol) = 1
++ --u32 "6&0xFF=1 && ...
++ read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
++ Next test that it's not a fragment.
++  (If so it might be part of such a packet but we can't always tell.)
++  n.b. This test is generally needed if you want to match anything
++  beyond the IP header.
++ The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
++ packet (not a fragment).  Alternatively, you can allow first fragments
++ by only testing the last 5 bits of byte 6.
++ ... 4&0x3FFF=0 && ...
++ Last test: the first byte past the IP header (the type) is 0
++ This is where we have to use the @syntax.  The length of the IP header
++ (IHL) in 32 bit words is stored in the right half of byte 0 of the
++ IP header itself.
++ ... 0>>22&0x3C@0>>24=0"
++ The first 0 means read bytes 0-3,
++ >>22 means shift that 22 bits to the right.  Shifting 24 bits would give
++   the first byte, so only 22 bits is four times that plus a few more bits.
++ &3C then eliminates the two extra bits on the right and the first four 
++ bits of the first byte.
++ For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
++ In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, 
++ >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
++ @ means to use this number as a new offset into the packet, and read
++ four bytes starting from there.  This is the first 4 bytes of the icmp
++ payload, of which byte 0 is the icmp type.  Therefore we simply shift
++ the value 24 to the right to throw out all but the first byte and compare
++ the result with 0.
++
++Example: 
++ tcp payload bytes 8-12 is any of 1, 2, 5 or 8
++ First we test that the packet is a tcp packet (similar to icmp).
++ --u32 "6&0xFF=6 && ...
++ Next, test that it's not a fragment (same as above).
++ ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
++ 0>>22&3C as above computes the number of bytes in the IP header.
++ @ makes this the new offset into the packet, which is the start of the
++ tcp header.  The length of the tcp header (again in 32 bit words) is
++ the left half of byte 12 of the tcp header.  The 12>>26&3C
++ computes this length in bytes (similar to the IP header before).
++ @ makes this the new offset, which is the start of the tcp payload.
++ Finally 8 reads bytes 8-12 of the payload and = checks whether the
++ result is any of 1, 2, 5 or 8
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ipt_u32.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++/* #include <asm-i386/timex.h> for timing */
++
++MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
++MODULE_DESCRIPTION("IP tables u32 matching module");
++MODULE_LICENSE("GPL");
++
++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_u32 *data = matchinfo;
++      int testind, i;
++      unsigned char* origbase = (char*)skb->nh.iph;
++      unsigned char* base = origbase;
++      unsigned char* head = skb->head;
++      unsigned char* end = skb->end;
++      int nnums, nvals;
++      u_int32_t pos, val;
++      /* unsigned long long cycles1, cycles2, cycles3, cycles4;
++         cycles1 = get_cycles(); */
++
++      for (testind=0; testind < data->ntests; testind++) {
++              base = origbase; /* reset for each test */
++              pos = data->tests[testind].location[0].number;
++              if (base+pos+3 > end || base+pos < head) 
++                      return 0;
++              val = (base[pos]<<24) + (base[pos+1]<<16) +
++                      (base[pos+2]<<8) + base[pos+3];
++              nnums = data->tests[testind].nnums;
++              for (i=1; i < nnums; i++) {
++                      u_int32_t number = data->tests[testind].location[i].number;
++                      switch (data->tests[testind].location[i].nextop) {
++                      case IPT_U32_AND: 
++                              val = val & number; 
++                              break;
++                      case IPT_U32_LEFTSH: 
++                              val = val << number;
++                              break;
++                      case IPT_U32_RIGHTSH: 
++                              val = val >> number; 
++                              break;
++                      case IPT_U32_AT:
++                              base = base + val;
++                              pos = number;
++                              if (base+pos+3 > end || base+pos < head) 
++                                      return 0;
++                              val = (base[pos]<<24) + (base[pos+1]<<16) +
++                                      (base[pos+2]<<8) + base[pos+3];
++                              break;
++                      }
++              }
++              nvals = data->tests[testind].nvalues;
++              for (i=0; i < nvals; i++) {
++                      if ((data->tests[testind].value[i].min <= val) &&
++                          (val <= data->tests[testind].value[i].max)) {
++                              break;
++                      }
++              }
++              if (i >= data->tests[testind].nvalues) {
++                      /* cycles2 = get_cycles(); 
++                         printk("failed %d in %d cycles\n", testind, 
++                                cycles2-cycles1); */
++                      return 0;
++              }
++      }
++      /* cycles2 = get_cycles();
++         printk("succeeded in %d cycles\n", cycles2-cycles1); */
++      return 1;
++}
++
++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_u32)))
++              return 0;
++      return 1;
++}
++
++static struct ipt_match u32_match
++= { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++      return ipt_register_match(&u32_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&u32_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/Kconfig linux-2.6.7/net/ipv6/netfilter/Kconfig
+--- linux-2.6.7.org/net/ipv6/netfilter/Kconfig 2004-09-07 12:07:46.626619360 +0200
++++ linux-2.6.7/net/ipv6/netfilter/Kconfig     2004-09-07 12:33:17.553883040 +0200
+@@ -230,5 +230,60 @@
+         <file:Documentation/modules.txt>.  If unsure, say `N'.
+         help
++config IP6_NF_TARGET_HL
++      tristate  'HL target support'
++      depends on IP6_NF_MANGLE
++      help
++        This option adds a `HL' target, which allows you to modify the value of
++        IPv6 Hop Limit field.
++      
++        If you want to compile it as a module, say M here and read
++        <file:Documentation/modules.txt>.  If unsure, say `N'.
++
++config IP6_NF_TARGET_REJECT
++      tristate  'REJECT target support'
++      depends on IP6_NF_FILTER
++      help
++        The REJECT target allows a filtering rule to specify that an ICMPv6
++        error should be issued in response to an incoming packet, rather
++        than silently being dropped.
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP6_NF_MATCH_FUZZY
++      tristate  'Fuzzy match support'
++      depends on IP6_NF_FILTER
++      help
++        This option adds a `fuzzy' match, which allows you to match
++        packets according to a fuzzy logic based law.
++      
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
++config IP6_NF_MATCH_NTH
++      tristate  'Nth match support'
++      depends on IP6_NF_IPTABLES
++      help
++        This option adds a `Nth' match, which allow you to make
++        rules that match every Nth packet.  By default there are 
++        16 different counters.
++      
++        [options]
++         --every     Nth              Match every Nth packet
++        [--counter]  num              Use counter 0-15 (default:0)
++        [--start]    num              Initialize the counter at the number 'num'
++                                      instead of 0. Must be between 0 and Nth-1
++        [--packet]   num              Match on 'num' packet. Must be between 0
++                                      and Nth-1.
++      
++                                      If --packet is used for a counter than
++                                      there must be Nth number of --packet
++                                      rules, covering all values between 0 and
++                                      Nth-1 inclusively.
++       
++        If you want to compile it as a module, say M here and read
++        Documentation/modules.txt.  If unsure, say `N'.
++
+ endmenu
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/Makefile linux-2.6.7/net/ipv6/netfilter/Makefile
+--- linux-2.6.7.org/net/ipv6/netfilter/Makefile        2004-09-07 12:07:46.626619360 +0200
++++ linux-2.6.7/net/ipv6/netfilter/Makefile    2004-09-07 12:33:17.554882888 +0200
+@@ -8,6 +8,7 @@
+ 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
++obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
+ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
+ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+@@ -21,5 +22,8 @@
+ obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
+ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
++
++obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
++obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
+ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.7/net/ipv6/netfilter/ip6t_HL.c
+--- linux-2.6.7.org/net/ipv6/netfilter/ip6t_HL.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv6/netfilter/ip6t_HL.c   2004-09-07 12:33:06.517560816 +0200
+@@ -0,0 +1,105 @@
++/* 
++ * Hop Limit modification target for ip6tables
++ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
++ * Based on HW's TTL module
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_HL.h>
++
++MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
++MODULE_DESCRIPTION("IP tables Hop Limit modification module");
++MODULE_LICENSE("GPL");
++
++static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
++              const struct net_device *in, const struct net_device *out,
++              const void *targinfo, void *userinfo)
++{
++      struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
++      const struct ip6t_HL_info *info = targinfo;
++      u_int16_t diffs[2];
++      int new_hl;
++                       
++      switch (info->mode) {
++              case IP6T_HL_SET:
++                      new_hl = info->hop_limit;
++                      break;
++              case IP6T_HL_INC:
++                      new_hl = ip6h->hop_limit + info->hop_limit;
++                      if (new_hl > 255)
++                              new_hl = 255;
++                      break;
++              case IP6T_HL_DEC:
++                      new_hl = ip6h->hop_limit - info->hop_limit;
++                      if (new_hl < 0)
++                              new_hl = 0;
++                      break;
++              default:
++                      new_hl = ip6h->hop_limit;
++                      break;
++      }
++
++      if (new_hl != ip6h->hop_limit) {
++              diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
++              ip6h->hop_limit = new_hl;
++              diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
++      }
++
++      return IP6T_CONTINUE;
++}
++
++static int ip6t_hl_checkentry(const char *tablename,
++              const struct ip6t_entry *e,
++              void *targinfo,
++              unsigned int targinfosize,
++              unsigned int hook_mask)
++{
++      struct ip6t_HL_info *info = targinfo;
++
++      if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
++              printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
++                              targinfosize,
++                              IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
++              return 0;       
++      }       
++
++      if (strcmp(tablename, "mangle")) {
++              printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++              return 0;
++      }
++
++      if (info->mode > IP6T_HL_MAXMODE) {
++              printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", 
++                      info->mode);
++              return 0;
++      }
++
++      if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
++              printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
++              return 0;
++      }
++      
++      return 1;
++}
++
++static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", 
++      ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++      return ip6t_register_target(&ip6t_HL);
++}
++
++static void __exit fini(void)
++{
++      ip6t_unregister_target(&ip6t_HL);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.7/net/ipv6/netfilter/ip6t_REJECT.c
+--- linux-2.6.7.org/net/ipv6/netfilter/ip6t_REJECT.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv6/netfilter/ip6t_REJECT.c       2004-09-07 12:33:08.255296640 +0200
+@@ -0,0 +1,458 @@
++/*
++ * IP6 tables REJECT target module
++ * Linux INET6 implementation
++ *
++ * Copyright (C)2003 USAGI/WIDE Project
++ *
++ * Authors:
++ *    Yasuyuki Kozakai        <yasuyuki.kozakai@toshiba.co.jp>
++ *
++ * Based on net/ipv4/netfilter/ipt_REJECT.c
++ *
++ * 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.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/icmpv6.h>
++#include <net/ipv6.h>
++#include <net/tcp.h>
++#include <net/icmp.h>
++#include <net/ip6_fib.h>
++#include <net/ip6_route.h>
++#include <net/flow.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_REJECT.h>
++
++MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
++MODULE_DESCRIPTION("IP6 tables REJECT target module");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#if 0
++static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
++{
++      void (*attach)(struct sk_buff *, struct nf_ct_info *);
++      if (nfct && (attach = ip6_ct_attach) != NULL) {
++              mb();
++              attach(new_skb, nfct);
++      }
++}
++#endif
++
++static int maybe_reroute(struct sk_buff *skb)
++{
++      if (skb->nfcache & NFC_ALTERED){
++              if (ip6_route_me_harder(skb) != 0){
++                      kfree_skb(skb);
++                      return -EINVAL;
++              }
++      }
++
++      return dst_output(skb);
++}
++
++/* Send RST reply */
++static void send_reset(struct sk_buff *oldskb)
++{
++      struct sk_buff *nskb;
++      struct tcphdr otcph, *tcph;
++      unsigned int otcplen, tcphoff, hh_len;
++      int needs_ack;
++      struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
++      struct dst_entry *dst = NULL;
++      u8 proto;
++      struct flowi fl;
++      proto = oip6h->nexthdr;
++      int err;
++
++      if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
++          (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
++              DEBUGP("ip6t_REJECT: addr is not unicast.\n");
++              return;
++      }
++
++      tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
++                                 &proto, oldskb->len - ((u8*)(oip6h+1)
++                                                        - oldskb->data));
++
++      if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
++              DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
++              return;
++      }
++
++      otcplen = oldskb->len - tcphoff;
++
++      /* IP header checks: fragment, too short. */
++      if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
++              DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
++                      proto, otcplen);
++              return;
++      }
++
++      if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
++              if (net_ratelimit())
++                      printk("ip6t_REJECT: Can't copy tcp header\n");
++              return;
++      }
++
++      /* No RST for RST. */
++      if (otcph.rst) {
++              DEBUGP("ip6t_REJECT: RST is set\n");
++              return;
++      }
++
++      /* Check checksum. */
++      if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
++                          skb_checksum(oldskb, tcphoff, otcplen, 0))) {
++              DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
++              return;
++      }
++
++      memset(&fl, 0, sizeof(fl));
++      fl.proto = IPPROTO_TCP;
++      ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
++      ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
++      fl.fl_ip_sport = otcph.dest;
++      fl.fl_ip_dport = otcph.source;
++      err = ip6_dst_lookup(NULL, &dst, &fl);
++      if (err) {
++              if (net_ratelimit())
++                      printk("ip6t_REJECT: can't find dst. err = %d\n", err);
++              return;
++      }
++
++      hh_len = (dst->dev->hard_header_len + 15)&~15;
++      nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
++                       + sizeof(struct tcphdr) + dst->trailer_len,
++                       GFP_ATOMIC);
++
++      if (!nskb) {
++              if (net_ratelimit())
++                      printk("ip6t_REJECT: Can't alloc skb\n");
++              dst_release(dst);
++              return;
++      }
++
++      nskb->dst = dst;
++      dst_hold(dst);
++
++      skb_reserve(nskb, hh_len + dst->header_len);
++
++      ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
++                                      skb_put(nskb, sizeof(struct ipv6hdr));
++      ip6h->version = 6;
++      ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
++      ip6h->nexthdr = IPPROTO_TCP;
++      ip6h->payload_len = htons(sizeof(struct tcphdr));
++      ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
++      ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
++
++      tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
++      /* Truncate to length (no data) */
++      tcph->doff = sizeof(struct tcphdr)/4;
++      tcph->source = otcph.dest;
++      tcph->dest = otcph.source;
++
++      if (otcph.ack) {
++              needs_ack = 0;
++              tcph->seq = otcph.ack_seq;
++              tcph->ack_seq = 0;
++      } else {
++              needs_ack = 1;
++              tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
++                                    + otcplen - (otcph.doff<<2));
++              tcph->seq = 0;
++      }
++
++      /* Reset flags */
++      ((u_int8_t *)tcph)[13] = 0;
++      tcph->rst = 1;
++      tcph->ack = needs_ack;
++      tcph->window = 0;
++      tcph->urg_ptr = 0;
++      tcph->check = 0;
++
++      /* Adjust TCP checksum */
++      tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
++                                    &nskb->nh.ipv6h->daddr,
++                                    sizeof(struct tcphdr), IPPROTO_TCP,
++                                    csum_partial((char *)tcph,
++                                                 sizeof(struct tcphdr), 0));
++
++#if 0
++      connection_attach(nskb, oldskb->nfct);
++#endif
++
++      NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++              maybe_reroute);
++
++      dst_release(dst);
++}
++
++static void send_unreach(struct sk_buff *skb_in, unsigned char code)
++{
++      struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
++      struct icmp6hdr *icmp6h;
++      struct dst_entry *dst = NULL;
++      struct rt6_info *rt;
++      int tmo;
++      __u32 csum;
++      unsigned int len, datalen, hh_len;
++      int saddr_type, daddr_type;
++      unsigned int ptr, ip6off;
++      u8 proto;
++      struct flowi fl;
++      struct sk_buff *nskb;
++      char *data;
++
++      saddr_type = ipv6_addr_type(&hdr->saddr);
++      daddr_type = ipv6_addr_type(&hdr->daddr);
++
++      if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
++          (!(daddr_type & IPV6_ADDR_UNICAST))) {
++              DEBUGP("ip6t_REJECT: addr is not unicast.\n");
++              return;
++      }
++
++      ip6off = skb_in->nh.raw - skb_in->data;
++      proto = hdr->nexthdr;
++      ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
++                             skb_in->len - ip6off);
++
++      if ((ptr < 0) || (ptr > skb_in->len)) {
++              ptr = ip6off + sizeof(struct ipv6hdr);
++              proto = hdr->nexthdr;
++      } else if (proto == IPPROTO_ICMPV6) {
++                u8 type;
++
++                if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
++                                                    icmp6_type), &type, 1)) {
++                      DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
++                      return;
++              }
++
++              if (!(type & ICMPV6_INFOMSG_MASK)) {
++                      DEBUGP("ip6t_REJECT: no reply to icmp error\n");
++                      return;
++              }
++        } else if (proto == IPPROTO_UDP) {
++              int plen = skb_in->len - (ptr - ip6off);
++              uint16_t check;
++
++              if (plen < sizeof(struct udphdr)) {
++                      DEBUGP("ip6t_REJECT: too short\n");
++                      return;
++              }
++
++              if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
++                                &check, 2)) {
++                      if (net_ratelimit())
++                              printk("ip6t_REJECT: can't get copy from skb");
++                      return;
++              }
++
++              if (check &&
++                  csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
++                                  IPPROTO_UDP,
++                                  skb_checksum(skb_in, ptr, plen, 0))) {
++                      DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
++                      return;
++              }
++      }
++
++      memset(&fl, 0, sizeof(fl));
++      fl.proto = IPPROTO_ICMPV6;
++      ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
++      ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
++      fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
++      fl.fl_icmp_code = code;
++
++      if (ip6_dst_lookup(NULL, &dst, &fl)) {
++              return;
++      }
++
++      rt = (struct rt6_info *)dst;
++      tmo = 1*HZ;
++
++      if (rt->rt6i_dst.plen < 128)
++              tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
++
++      if (!xrlim_allow(dst, tmo)) {
++              if (net_ratelimit())
++                      printk("ip6t_REJECT: rate limitted\n");
++              goto dst_release_out;
++      }
++
++      len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
++
++      if (len > dst_pmtu(dst))
++              len = dst_pmtu(dst);
++      if (len > IPV6_MIN_MTU)
++              len = IPV6_MIN_MTU;
++
++      datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
++      hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
++
++      nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
++                       GFP_ATOMIC);
++
++      if (!nskb) {
++              if (net_ratelimit())
++                      printk("ip6t_REJECT: can't alloc skb\n");
++              goto dst_release_out;
++      }
++
++      nskb->priority = 0;
++      nskb->dst = dst;
++      dst_hold(dst);
++
++      skb_reserve(nskb, hh_len + dst->header_len);
++
++      ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
++                                      skb_put(nskb, sizeof(struct ipv6hdr));
++      ip6h->version = 6;
++      ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
++      ip6h->nexthdr = IPPROTO_ICMPV6;
++      ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
++      ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
++      ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
++
++      icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
++      icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
++      icmp6h->icmp6_code = code;
++      icmp6h->icmp6_cksum = 0;
++
++      data = skb_put(nskb, datalen);
++
++      csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
++      csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
++      icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
++                                           datalen + sizeof(struct icmp6hdr),
++                                           IPPROTO_ICMPV6, csum);
++
++#if 0
++      connection_attach(nskb, skb_in->nfct);
++#endif
++      NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++              maybe_reroute);
++
++dst_release_out:
++      dst_release(dst);
++}
++
++static unsigned int reject6_target(struct sk_buff **pskb,
++                         unsigned int hooknum,
++                         const struct net_device *in,
++                         const struct net_device *out,
++                         const void *targinfo,
++                         void *userinfo)
++{
++      const struct ip6t_reject_info *reject = targinfo;
++
++      DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
++      /* WARNING: This code causes reentry within ip6tables.
++         This means that the ip6tables jump stack is now crap.  We
++         must return an absolute verdict. --RR */
++      switch (reject->with) {
++      case IP6T_ICMP6_NO_ROUTE:
++              send_unreach(*pskb, ICMPV6_NOROUTE);
++              break;
++      case IP6T_ICMP6_ADM_PROHIBITED:
++              send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
++              break;
++      case IP6T_ICMP6_NOT_NEIGHBOUR:
++              send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
++              break;
++      case IP6T_ICMP6_ADDR_UNREACH:
++              send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
++              break;
++      case IP6T_ICMP6_PORT_UNREACH:
++              send_unreach(*pskb, ICMPV6_PORT_UNREACH);
++              break;
++      case IP6T_ICMP6_ECHOREPLY:
++              /* Do nothing */
++              break;
++      case IP6T_TCP_RESET:
++              send_reset(*pskb);
++              break;
++      default:
++              if (net_ratelimit())
++                      printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
++              break;
++      }
++
++      return NF_DROP;
++}
++
++static int check(const char *tablename,
++               const struct ip6t_entry *e,
++               void *targinfo,
++               unsigned int targinfosize,
++               unsigned int hook_mask)
++{
++      const struct ip6t_reject_info *rejinfo = targinfo;
++
++      if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
++              DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
++              return 0;
++      }
++
++      /* Only allow these for packet filtering. */
++      if (strcmp(tablename, "filter") != 0) {
++              DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
++              return 0;
++      }
++
++      if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
++                         | (1 << NF_IP6_FORWARD)
++                         | (1 << NF_IP6_LOCAL_OUT))) != 0) {
++              DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
++              return 0;
++      }
++
++      if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
++              printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
++              return 0;
++      } else if (rejinfo->with == IP6T_TCP_RESET) {
++              /* Must specify that it's a TCP packet */
++              if (e->ipv6.proto != IPPROTO_TCP
++                  || (e->ipv6.invflags & IP6T_INV_PROTO)) {
++                      DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
++                      return 0;
++              }
++      }
++
++      return 1;
++}
++
++static struct ip6t_target ip6t_reject_reg = {
++      .name           = "REJECT",
++      .target         = reject6_target,
++      .checkentry     = check,
++      .me             = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      if (ip6t_register_target(&ip6t_reject_reg))
++              return -EINVAL;
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ip6t_unregister_target(&ip6t_reject_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.7/net/ipv6/netfilter/ip6t_fuzzy.c
+--- linux-2.6.7.org/net/ipv6/netfilter/ip6t_fuzzy.c    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv6/netfilter/ip6t_fuzzy.c        2004-09-07 12:33:12.081714936 +0200
+@@ -0,0 +1,189 @@
++/*
++ * This module implements a simple TSK FLC
++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
++ * to limit , in an adaptive and flexible way , the packet rate crossing
++ * a given stream . It serves as an initial and very simple (but effective)
++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
++ *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
++ * into our code in a precise , adaptive and efficient manner.
++ *  The goal is very similar to that of "limit" match , but using techniques of
++ * Fuzzy Control , that allow us to shape the transfer functions precisely ,
++ * avoiding over and undershoots - and stuff like that .
++ *
++ *
++ * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
++ * 2002-08-17  : Changed to eliminate floating point operations .
++ * 2002-08-23  : Coding style changes .
++ * 2003-04-08  Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ipv6.h>
++#include <linux/random.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
++
++/*
++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
++ Expressed in percentage
++*/
++
++#define PAR_LOW               1/100
++#define PAR_HIGH      1
++
++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
++
++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
++MODULE_LICENSE("GPL");
++
++static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++      if (tx >= maxi) return 100;
++
++      if (tx <= mini) return 0;
++
++      return ((100 * (tx-mini)) / (maxi-mini));
++}
++
++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++      if (tx <= mini) return 100;
++
++      if (tx >= maxi) return 0;
++
++      return ((100 * (maxi - tx)) / (maxi - mini));
++
++}
++
++static int
++ip6t_fuzzy_match(const struct sk_buff *pskb,
++             const struct net_device *in,
++             const struct net_device *out,
++             const void *matchinfo,
++             int offset,
++             const void *hdr,
++             u_int16_t datalen,
++             int *hotdrop)
++{
++      /* From userspace */
++
++      struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
++
++      u_int8_t random_number;
++      unsigned long amount;
++      u_int8_t howhigh, howlow;
++
++
++      spin_lock_bh(&fuzzy_lock); /* Rise the lock */
++
++      info->bytes_total += pskb->len;
++      info->packets_total++;
++
++      info->present_time = jiffies;
++
++      if (info->present_time >= info->previous_time)
++              amount = info->present_time - info->previous_time;
++      else {
++              /* There was a transition : I choose to re-sample
++                 and keep the old acceptance rate...
++              */
++
++              amount = 0;
++              info->previous_time = info->present_time;
++              info->bytes_total = info->packets_total = 0;
++           };
++
++      if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
++
++              info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
++                                      / amount);
++
++              info->previous_time = info->present_time;
++              info->bytes_total = info->packets_total = 0;
++
++              howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
++              howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
++
++              info->acceptance_rate = (u_int8_t) \
++                              (howhigh * PAR_LOW + PAR_HIGH * howlow);
++
++      /* In fact, the above defuzzification would require a denominator
++       * proportional to (howhigh+howlow) but, in this particular case,
++       * that expression is constant.
++       * An imediate consequence is that it is not necessary to call
++       * both mf_high and mf_low - but to keep things understandable,
++       * I did so.
++       */
++
++      }
++
++      spin_unlock_bh(&fuzzy_lock); /* Release the lock */
++
++
++      if (info->acceptance_rate < 100)
++      {
++              get_random_bytes((void *)(&random_number), 1);
++
++              /*  If within the acceptance , it can pass => don't match */
++              if (random_number <= (255 * info->acceptance_rate) / 100)
++                      return 0;
++              else
++                      return 1; /* It can't pass (It matches) */
++      };
++
++      return 0; /* acceptance_rate == 100 % => Everything passes ... */
++
++}
++
++static int
++ip6t_fuzzy_checkentry(const char *tablename,
++                 const struct ip6t_ip6 *ip,
++                 void *matchinfo,
++                 unsigned int matchsize,
++                 unsigned int hook_mask)
++{
++
++      const struct ip6t_fuzzy_info *info = matchinfo;
++
++      if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
++              printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
++                     IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
++              return 0;
++      }
++
++      if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
++       || (info->minimum_rate >= info->maximum_rate)) {
++              printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ip6t_match ip6t_fuzzy_reg = {
++      {NULL, NULL},
++      "fuzzy",
++      ip6t_fuzzy_match,
++      ip6t_fuzzy_checkentry,
++      NULL,
++      THIS_MODULE };
++
++static int __init init(void)
++{
++      if (ip6t_register_match(&ip6t_fuzzy_reg))
++              return -EINVAL;
++
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ip6t_unregister_match(&ip6t_fuzzy_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.7/net/ipv6/netfilter/ip6t_nth.c
+--- linux-2.6.7.org/net/ipv6/netfilter/ip6t_nth.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7/net/ipv6/netfilter/ip6t_nth.c  2004-09-07 12:33:17.548883800 +0200
+@@ -0,0 +1,173 @@
++/*
++  This is a module which is used for match support for every Nth packet
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from:
++     ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
++        * added support for multiple counters
++        * added support for matching on individual packets
++          in the counter cycle
++  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
++
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_nth.h>
++
++MODULE_LICENSE("GPL");
++
++/*
++ * State information.
++ */
++struct state {
++      spinlock_t lock;
++      u_int16_t number;
++};
++
++static struct state states[IP6T_NTH_NUM_COUNTERS];
++
++static int
++ip6t_nth_match(const struct sk_buff *pskb,
++            const struct net_device *in,
++            const struct net_device *out,
++            const void *matchinfo,
++            int offset,
++            const void *hdr,
++            u_int16_t datalen,
++            int *hotdrop)
++{
++      /* Parameters from userspace */
++      const struct ip6t_nth_info *info = matchinfo;
++        unsigned counter = info->counter;
++              if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
++              {
++                      printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
++               return 0;
++        };
++
++        spin_lock(&states[counter].lock);
++
++        /* Are we matching every nth packet?*/
++        if (info->packet == 0xFF)
++        {
++              /* We're matching every nth packet and only every nth packet*/
++              /* Do we match or invert match? */
++              if (info->not == 0)
++              {
++                      if (states[counter].number == 0)
++                      {
++                              ++states[counter].number;
++                              goto match;
++                      }
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0; /* reset the counter */
++                      else
++                              ++states[counter].number;
++                      goto dontmatch;
++              }
++              else
++              {
++                      if (states[counter].number == 0)
++                      {
++                              ++states[counter].number;
++                              goto dontmatch;
++                      }
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0;
++                      else
++                              ++states[counter].number;
++                      goto match;
++              }
++        }
++        else
++        {
++              /* We're using the --packet, so there must be a rule for every value */
++              if (states[counter].number == info->packet)
++              {
++                      /* only increment the counter when a match happens */
++                      if (states[counter].number >= info->every)
++                              states[counter].number = 0; /* reset the counter */
++                      else
++                              ++states[counter].number;
++                      goto match;
++              }
++              else
++                      goto dontmatch;
++      }
++
++ dontmatch:
++      /* don't match */
++      spin_unlock(&states[counter].lock);
++      return 0;
++
++ match:
++      spin_unlock(&states[counter].lock);
++      return 1;
++}
++
++static int
++ip6t_nth_checkentry(const char *tablename,
++                 const struct ip6t_ip6 *e,
++                 void *matchinfo,
++                 unsigned int matchsize,
++                 unsigned int hook_mask)
++{
++      /* Parameters from userspace */
++      const struct ip6t_nth_info *info = matchinfo;
++        unsigned counter = info->counter;
++        if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
++      {
++              printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
++                      return 0;
++              };
++
++      if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
++              printk("nth: matchsize %u != %u\n", matchsize,
++                     IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
++              return 0;
++      }
++
++      states[counter].number = info->startat;
++
++      return 1;
++}
++
++static struct ip6t_match ip6t_nth_reg = { 
++      {NULL, NULL},
++      "nth",
++      ip6t_nth_match,
++      ip6t_nth_checkentry,
++      NULL,
++      THIS_MODULE };
++
++static int __init init(void)
++{
++      unsigned counter;
++        memset(&states, 0, sizeof(states));
++      if (ip6t_register_match(&ip6t_nth_reg))
++              return -EINVAL;
++
++        for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) 
++      {
++              spin_lock_init(&(states[counter].lock));
++        };
++
++      printk("ip6t_nth match loaded\n");
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ip6t_unregister_match(&ip6t_nth_reg);
++      printk("ip6t_nth match unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
This page took 0.350694 seconds and 4 git commands to generate.