]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- netfilter snap 20040316
authorcieciwa <cieciwa@pld-linux.org>
Tue, 16 Mar 2004 12:25:29 +0000 (12:25 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    2.6.5-rc1-patch-o-matic-ng-base-20040316.patch -> 1.1
    2.6.5-rc1-patch-o-matic-ng-extra-20040316.patch -> 1.1

2.6.5-rc1-patch-o-matic-ng-base-20040316.patch [new file with mode: 0644]
2.6.5-rc1-patch-o-matic-ng-extra-20040316.patch [new file with mode: 0644]

diff --git a/2.6.5-rc1-patch-o-matic-ng-base-20040316.patch b/2.6.5-rc1-patch-o-matic-ng-base-20040316.patch
new file mode 100644 (file)
index 0000000..d010483
--- /dev/null
@@ -0,0 +1,5178 @@
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter.h linux-2.6.5-rc1/include/linux/netfilter.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter.h      2004-03-16 05:46:35.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter.h  2004-03-16 11:53:42.000000000 +0000
+@@ -99,6 +99,24 @@
+ extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
++typedef void nf_logfn(unsigned int hooknum,
++                    const struct sk_buff *skb,
++                    const struct net_device *in,
++                    const struct net_device *out,
++                    const char *prefix);
++
++/* Function to register/unregister log function. */
++int nf_log_register(int pf, nf_logfn *logfn);
++void nf_log_unregister(int pf, nf_logfn *logfn);
++
++/* Calls the registered backend logging function */
++void nf_log_packet(int pf,
++                 unsigned int hooknum,
++                 const struct sk_buff *skb,
++                 const struct net_device *in,
++                 const struct net_device *out,
++                 const char *fmt, ...);
++                   
+ /* Activate hook; either okfn or kfree_skb called, unless a hook
+    returns NF_STOLEN (in which case, it's up to the hook to deal with
+    the consequences).
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h    2004-03-16 05:47:19.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h        2004-03-16 11:53:55.000000000 +0000
+@@ -251,6 +251,9 @@
+ /* Call me when a conntrack is destroyed. */
+ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
++/* Fake conntrack entry for untracked connections */
++extern struct ip_conntrack ip_conntrack_untracked;
++
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+ ip_ct_gather_frags(struct sk_buff *skb);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_TTL.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_TTL.h     2004-03-16 11:53:46.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_ULOG.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_ULOG.h        2004-03-16 05:46:09.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_ULOG.h    2004-03-16 11:53:42.000000000 +0000
+@@ -11,6 +11,9 @@
+ #define NETLINK_NFLOG         5
+ #endif
++#define ULOG_DEFAULT_NLGROUP  1
++#define ULOG_DEFAULT_QTHRESHOLD       1
++
+ #define ULOG_MAC_LEN  80
+ #define ULOG_PREFIX_LEN       32
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connlimit.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connlimit.h   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connlimit.h       2004-03-16 11:53:47.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_conntrack.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_conntrack.h   2004-03-16 05:47:04.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_conntrack.h       2004-03-16 11:53:55.000000000 +0000
+@@ -10,6 +10,7 @@
+ #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+ #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
++#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+ /* flags, invflags: */
+ #define IPT_CONNTRACK_STATE   0x01
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_dstlimit.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_dstlimit.h    1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_dstlimit.h        2004-03-16 11:53:48.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_fuzzy.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_fuzzy.h       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_fuzzy.h   2004-03-16 11:53:50.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_ipv4options.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_ipv4options.h     2004-03-16 11:53:51.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_mport.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_mport.h       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_mport.h   2004-03-16 11:53:52.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_nth.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_nth.h     2004-03-16 11:53:53.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_quota.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_quota.h       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_quota.h   2004-03-16 11:53:54.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_realm.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_realm.h       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_realm.h   2004-03-16 11:53:56.000000000 +0000
+@@ -0,0 +1,9 @@
++#ifndef _IPT_REALM_H
++#define _IPT_REALM_H
++
++struct ipt_realm_info {
++      u_int32_t id;
++      u_int32_t mask;
++      u_int8_t invert;
++};
++#endif /*_IPT_REALM_H*/
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_sctp.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_sctp.h        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_sctp.h    2004-03-16 11:53:57.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_state.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_state.h       2004-03-16 05:47:18.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_state.h   2004-03-16 11:53:55.000000000 +0000
+@@ -4,6 +4,8 @@
+ #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+ #define IPT_STATE_INVALID (1 << 0)
++#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
++
+ struct ipt_state_info
+ {
+       unsigned int statemask;
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_u32.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_u32.h     2004-03-16 11:53:58.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv4.h linux-2.6.5-rc1/include/linux/netfilter_ipv4.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4.h 2004-03-16 05:47:18.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4.h     2004-03-16 11:53:55.000000000 +0000
+@@ -51,6 +51,8 @@
+ enum nf_ip_hook_priorities {
+       NF_IP_PRI_FIRST = INT_MIN,
++      NF_IP_PRI_CONNTRACK_DEFRAG = -400,
++      NF_IP_PRI_RAW = -300,
+       NF_IP_PRI_SELINUX_FIRST = -225,
+       NF_IP_PRI_CONNTRACK = -200,
+       NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_HL.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_HL.h     2004-03-16 11:53:43.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_REJECT.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_REJECT.h     2004-03-16 05:45:18.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-16 11:53:45.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_fuzzy.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_fuzzy.h  2004-03-16 11:53:50.000000000 +0000
+@@ -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.5-rc1.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_nth.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_nth.h        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_nth.h    2004-03-16 11:53:53.000000000 +0000
+@@ -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.5-rc1.org/net/core/netfilter.c linux-2.6.5-rc1/net/core/netfilter.c
+--- linux-2.6.5-rc1.org/net/core/netfilter.c   2004-03-16 05:46:34.000000000 +0000
++++ linux-2.6.5-rc1/net/core/netfilter.c       2004-03-16 11:53:42.000000000 +0000
+@@ -8,8 +8,10 @@
+  *
+  * February 2000: Modified by James Morris to have 1 queue per protocol.
+  * 15-Mar-2000:   Added NF_REPEAT --RR.
++ * 08-May-2003:         Internal logging interface added by Jozsef Kadlecsik.
+  */
+ #include <linux/config.h>
++#include <linux/kernel.h>
+ #include <linux/netfilter.h>
+ #include <net/protocol.h>
+ #include <linux/init.h>
+@@ -741,6 +743,72 @@
+ EXPORT_SYMBOL(skb_ip_make_writable);
+ #endif /*CONFIG_INET*/
++/* Internal logging interface, which relies on the real 
++   LOG target modules */
++
++#define NF_LOG_PREFIXLEN              128
++
++static nf_logfn *nf_logging[NPROTO]; /* = NULL */
++static int reported = 0;
++static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
++
++int nf_log_register(int pf, nf_logfn *logfn)
++{
++      int ret = -EBUSY;
++
++      /* Any setup of logging members must be done before
++       * substituting pointer. */
++      smp_wmb();
++      spin_lock(&nf_log_lock);
++      if (!nf_logging[pf]) {
++              nf_logging[pf] = logfn;
++              ret = 0;
++      }
++      spin_unlock(&nf_log_lock);
++      return ret;
++}             
++
++void nf_log_unregister(int pf, nf_logfn *logfn)
++{
++      spin_lock(&nf_log_lock);
++      if (nf_logging[pf] == logfn)
++              nf_logging[pf] = NULL;
++      spin_unlock(&nf_log_lock);
++
++      /* Give time to concurrent readers. */
++      synchronize_net();
++}             
++
++void nf_log_packet(int pf,
++                 unsigned int hooknum,
++                 const struct sk_buff *skb,
++                 const struct net_device *in,
++                 const struct net_device *out,
++                 const char *fmt, ...)
++{
++      va_list args;
++      char prefix[NF_LOG_PREFIXLEN];
++      nf_logfn *logfn;
++      
++      rcu_read_lock();
++      logfn = nf_logging[pf];
++      if (logfn) {
++              va_start(args, fmt);
++              vsnprintf(prefix, sizeof(prefix), fmt, args);
++              va_end(args);
++              /* We must read logging before nf_logfn[pf] */
++              smp_read_barrier_depends();
++              logfn(hooknum, skb, in, out, prefix);
++      } else if (!reported) {
++              printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
++                     "no backend logging module loaded in!\n");
++              reported++;
++      }
++      rcu_read_unlock();
++}
++EXPORT_SYMBOL(nf_log_register);
++EXPORT_SYMBOL(nf_log_unregister);
++EXPORT_SYMBOL(nf_log_packet);
+ /* This does not belong here, but ipt_REJECT needs it if connection
+    tracking in use: without this, connection may not be in hash table,
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig     2004-03-16 05:47:17.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig 2004-03-16 11:53:58.000000000 +0000
+@@ -579,5 +579,89 @@
+         To compile it as a module, choose M here.  If unsure, say N.
++config IP_NF_TARGET_IPV4OPTSSTRIP
++      tristate  'IPV4OPTSSTRIP target support'
++      depends on IP_NF_MANGLE
++        help
++
++config IP_NF_TARGET_TTL
++      tristate  'TTL target support'
++      depends on IP_NF_MANGLE
++        help
++
++config IP_NF_MATCH_CONNLIMIT
++      tristate  'Connections/IP limit match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_DSTLIMIT
++      tristate  'dstlimit match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_FUZZY
++      tristate  'fuzzy match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_IPV4OPTIONS
++      tristate  'IPV4OPTIONS match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_MPORT
++      tristate  'Multiple port with ranges match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_NTH
++      tristate  'Nth match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_QUOTA
++      tristate  'quota match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_TARGET_NOTRACK
++      tristate  'NOTRACK target support'
++      depends on IP_NF_RAW
++      help
++        The NOTRACK target allows a select rule to specify
++        which packets *not* to enter the conntrack/NAT
++        subsystem with all the consequences (no ICMP error tracking,
++        no protocol helpers for the selected packets).
++      
++        If you want to compile it as a module, say M here and read
++        <file:Documentation/modules.txt>.  If unsure, say `N'.
++
++config IP_NF_RAW
++      tristate  'raw table support (required for NOTRACK/TRACE)'
++      depends on IP_NF_IPTABLES
++      help
++        This option adds a `raw' table to iptables. This table is the very
++        first in the netfilter framework and hooks in at the PREROUTING
++        and OUTPUT chains.
++      
++        If you want to compile it as a module, say M here and read
++        <file:Documentation/modules.txt>.  If unsure, say `N'.
++        help
++
++config IP_NF_MATCH_REALM
++      tristate  'realm match support'
++      depends on IP_NF_IPTABLES && NET_CLS_ROUTE
++        help
++
++config IP_NF_MATCH_SCTP
++      tristate  'SCTP protocol match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_U32
++      tristate  'U32 match support'
++      depends on IP_NF_IPTABLES
++        help
++
+ endmenu
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile linux-2.6.5-rc1/net/ipv4/netfilter/Makefile
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile    2004-03-16 05:45:49.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/Makefile        2004-03-16 11:53:58.000000000 +0000
+@@ -38,19 +38,33 @@
+ obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
+ obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
+ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
++obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+ # matches
+ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
+ obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
++obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
++obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
++obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.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_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
+@@ -59,10 +73,15 @@
+ 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
+ obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
+@@ -79,8 +98,11 @@
+ 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
+ # generic ARP tables
+ obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-16 05:45:17.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_core.c     2004-03-16 11:53:55.000000000 +0000
+@@ -67,6 +67,7 @@
+ static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
+ struct list_head *ip_conntrack_hash;
+ static kmem_cache_t *ip_conntrack_cachep;
++struct ip_conntrack ip_conntrack_untracked;
+ extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
+@@ -691,42 +692,50 @@
+                            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 the expectation is dying, then this is a loser. */
+-      if (expected
+-          && expected->expectant->helper->timeout
+-          && ! del_timer(&expected->timeout))
+-              expected = NULL;
+-
+       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);
++              /* 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;
++              }
++
++              /* Expectation is dying... */
++              if (expected->expectant->helper->timeout
++                  && ! del_timer(&expected->timeout)) {
++                      goto end;       
++              }
++
++                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]);
++
++              /* 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 */
+@@ -794,6 +803,15 @@
+       int set_reply;
+       int ret;
++      /* Never happen */
++      if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
++              if (net_ratelimit()) {
++              printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
++                     (*pskb)->nh.iph->protocol, hooknum);
++              }
++              return NF_DROP;
++      }
++
+       /* FIXME: Do this right please. --RR */
+       (*pskb)->nfcache |= NFC_UNKNOWN;
+@@ -812,18 +830,10 @@
+       }
+ #endif
+-      /* Previously seen (loopback)?  Ignore.  Do this before
+-           fragment check. */
++      /* Previously seen (loopback or untracked)?  Ignore. */
+       if ((*pskb)->nfct)
+               return NF_ACCEPT;
+-      /* Gather fragments. */
+-      if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-              *pskb = ip_ct_gather_frags(*pskb);
+-              if (!*pskb)
+-                      return NF_STOLEN;
+-      }
+-
+       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+       /* It may be an icmp error... */
+@@ -1422,6 +1432,18 @@
+       /* For use by ipt_REJECT */
+       ip_ct_attach = ip_conntrack_attach;
++
++      /* Set up fake conntrack:
++          - to never be deleted, not in any hashes */
++      atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
++      /*  - and look it like as a confirmed connection */
++      set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
++      /*  - and prepare the ctinfo field for REJECT & NAT. */
++      ip_conntrack_untracked.infos[IP_CT_NEW].master =
++      ip_conntrack_untracked.infos[IP_CT_RELATED].master =
++      ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = 
++                      &ip_conntrack_untracked.ct_general;
++
+       return ret;
+ err_free_hash:
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c   2004-03-16 05:46:27.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c       2004-03-16 11:53:55.000000000 +0000
+@@ -194,6 +194,26 @@
+       return ip_conntrack_confirm(*pskb);
+ }
++static unsigned int ip_conntrack_defrag(unsigned int hooknum,
++                                      struct sk_buff **pskb,
++                                      const struct net_device *in,
++                                      const struct net_device *out,
++                                      int (*okfn)(struct sk_buff *))
++{
++      /* Previously seen (loopback)?  Ignore.  Do this before
++           fragment check. */
++      if ((*pskb)->nfct)
++              return NF_ACCEPT;
++
++      /* Gather fragments. */
++      if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
++              *pskb = ip_ct_gather_frags(*pskb);
++              if (!*pskb)
++                      return NF_STOLEN;
++      }
++      return NF_ACCEPT;
++}
++
+ static unsigned int ip_refrag(unsigned int hooknum,
+                             struct sk_buff **pskb,
+                             const struct net_device *in,
+@@ -236,6 +256,14 @@
+ /* Connection tracking may drop packets, but never alters them, so
+    make it the first hook. */
++static struct nf_hook_ops ip_conntrack_defrag_ops = {
++      .hook           = ip_conntrack_defrag,
++      .owner          = THIS_MODULE,
++      .pf             = PF_INET,
++      .hooknum        = NF_IP_PRE_ROUTING,
++      .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
++};
++
+ static struct nf_hook_ops ip_conntrack_in_ops = {
+       .hook           = ip_conntrack_in,
+       .owner          = THIS_MODULE,
+@@ -244,6 +272,14 @@
+       .priority       = NF_IP_PRI_CONNTRACK,
+ };
++static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
++      .hook           = ip_conntrack_defrag,
++      .owner          = THIS_MODULE,
++      .pf             = PF_INET,
++      .hooknum        = NF_IP_LOCAL_OUT,
++      .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
++};
++
+ static struct nf_hook_ops ip_conntrack_local_out_ops = {
+       .hook           = ip_conntrack_local,
+       .owner          = THIS_MODULE,
+@@ -470,10 +506,20 @@
+       if (!proc) goto cleanup_init;
+       proc->owner = THIS_MODULE;
++      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;
++      }
++      ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
++      if (ret < 0) {
++              printk("ip_conntrack: can't register local_out defrag hook.\n");
++              goto cleanup_defragops;
++      }
+       ret = nf_register_hook(&ip_conntrack_in_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register pre-routing hook.\n");
+-              goto cleanup_proc;
++              goto cleanup_defraglocalops;
+       }
+       ret = nf_register_hook(&ip_conntrack_local_out_ops);
+       if (ret < 0) {
+@@ -511,6 +557,10 @@
+       nf_unregister_hook(&ip_conntrack_local_out_ops);
+  cleanup_inops:
+       nf_unregister_hook(&ip_conntrack_in_ops);
++ cleanup_defraglocalops:
++      nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
++ cleanup_defragops:
++      nf_unregister_hook(&ip_conntrack_defrag_ops);
+  cleanup_proc:
+       proc_net_remove("ip_conntrack");
+  cleanup_init:
+@@ -602,5 +652,6 @@
+ EXPORT_SYMBOL(ip_conntrack_expect_list);
+ EXPORT_SYMBOL(ip_conntrack_lock);
+ EXPORT_SYMBOL(ip_conntrack_hash);
++EXPORT_SYMBOL(ip_conntrack_untracked);
+ EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
+ EXPORT_SYMBOL_GPL(ip_conntrack_put);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_core.c       2004-03-16 05:45:35.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_core.c   2004-03-16 11:53:55.000000000 +0000
+@@ -1016,6 +1016,10 @@
+       /* FIXME: Man, this is a hack.  <SIGH> */
+       IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
+       ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
++      
++      /* Initialize fake conntrack so that NAT will skip it */
++      ip_conntrack_untracked.nat.info.initialized |= 
++              (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
+       return 0;
+ }
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c     2004-03-16 11:53:44.000000000 +0000
+@@ -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 <linux/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.5-rc1.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_LOG.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_LOG.c   2004-03-16 05:47:18.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_LOG.c       2004-03-16 11:53:42.000000000 +0000
+@@ -19,6 +19,7 @@
+ #include <net/tcp.h>
+ #include <net/route.h>
++#include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv4/ipt_LOG.h>
+@@ -26,6 +27,10 @@
+ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+ MODULE_DESCRIPTION("iptables syslog logging module");
++static unsigned int nflog = 1;
++MODULE_PARM(nflog, "i");
++MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
++ 
+ #if 0
+ #define DEBUGP printk
+ #else
+@@ -324,28 +329,25 @@
+       /* maxlen = 230+   91  + 230 + 252 = 803 */
+ }
+-static unsigned int
+-ipt_log_target(struct sk_buff **pskb,
++static void
++ipt_log_packet(unsigned int hooknum,
++             const struct sk_buff *skb,
+              const struct net_device *in,
+              const struct net_device *out,
+-             unsigned int hooknum,
+-             const void *targinfo,
+-             void *userinfo)
++             const struct ipt_log_info *loginfo,
++             const char *level_string,
++             const char *prefix)
+ {
+-      const struct ipt_log_info *loginfo = targinfo;
+-      char level_string[4] = "< >";
+-
+-      level_string[1] = '0' + (loginfo->level % 8);
+       spin_lock_bh(&log_lock);
+       printk(level_string);
+       printk("%sIN=%s OUT=%s ",
+-             loginfo->prefix,
++             prefix == NULL ? loginfo->prefix : prefix,
+              in ? in->name : "",
+              out ? out->name : "");
+ #ifdef CONFIG_BRIDGE_NETFILTER
+-      if ((*pskb)->nf_bridge) {
+-              struct net_device *physindev = (*pskb)->nf_bridge->physindev;
+-              struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
++      if (skb->nf_bridge) {
++              struct net_device *physindev = skb->nf_bridge->physindev;
++              struct net_device *physoutdev = skb->nf_bridge->physoutdev;
+               if (physindev && in != physindev)
+                       printk("PHYSIN=%s ", physindev->name);
+@@ -357,25 +359,56 @@
+       if (in && !out) {
+               /* MAC logging for input chain only. */
+               printk("MAC=");
+-              if ((*pskb)->dev && (*pskb)->dev->hard_header_len
+-                  && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
++              if (skb->dev && skb->dev->hard_header_len
++                  && skb->mac.raw != (void*)skb->nh.iph) {
+                       int i;
+-                      unsigned char *p = (*pskb)->mac.raw;
+-                      for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
++                      unsigned char *p = skb->mac.raw;
++                      for (i = 0; i < skb->dev->hard_header_len; i++,p++)
+                               printk("%02x%c", *p,
+-                                     i==(*pskb)->dev->hard_header_len - 1
++                                     i==skb->dev->hard_header_len - 1
+                                      ? ' ':':');
+               } else
+                       printk(" ");
+       }
+-      dump_packet(loginfo, *pskb, 0);
++      dump_packet(loginfo, skb, 0);
+       printk("\n");
+       spin_unlock_bh(&log_lock);
++}
++
++static unsigned int
++ipt_log_target(struct sk_buff **pskb,
++             const struct net_device *in,
++             const struct net_device *out,
++             unsigned int hooknum,
++             const void *targinfo,
++             void *userinfo)
++{
++      const struct ipt_log_info *loginfo = targinfo;
++      char level_string[4] = "< >";
++
++      level_string[1] = '0' + (loginfo->level % 8);
++      ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
+       return IPT_CONTINUE;
+ }
++static void
++ipt_logfn(unsigned int hooknum,
++        const struct sk_buff *skb,
++        const struct net_device *in,
++        const struct net_device *out,
++        const char *prefix)
++{
++      struct ipt_log_info loginfo = { 
++              .level = 0, 
++              .logflags = IPT_LOG_MASK, 
++              .prefix = "" 
++      };
++
++      ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
++}
++
+ static int ipt_log_checkentry(const char *tablename,
+                             const struct ipt_entry *e,
+                             void *targinfo,
+@@ -413,11 +446,18 @@
+ static int __init init(void)
+ {
+-      return ipt_register_target(&ipt_log_reg);
++      if (ipt_register_target(&ipt_log_reg))
++              return -EINVAL;
++      if (nflog)
++              nf_log_register(PF_INET, &ipt_logfn);
++      
++      return 0;
+ }
+ static void __exit fini(void)
+ {
++      if (nflog)
++              nf_log_unregister(PF_INET, &ipt_logfn);
+       ipt_unregister_target(&ipt_log_reg);
+ }
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_NOTRACK.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_NOTRACK.c       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_NOTRACK.c   2004-03-16 11:53:55.000000000 +0000
+@@ -0,0 +1,75 @@
++/* This is a module which is used for setting up fake conntracks
++ * on packets so that they are not seen by the conntrack/NAT code.
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++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)
++{
++      /* Previously seen (loopback)? Ignore. */
++      if ((*pskb)->nfct != NULL)
++              return IPT_CONTINUE;
++
++      /* Attach fake conntrack entry. 
++         If there is a real ct entry correspondig to this packet, 
++         it'll hang aroun till timing out. We don't deal with it
++         for performance reasons. JK */
++      (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
++      nf_conntrack_get((*pskb)->nfct);
++
++      return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_entry *e,
++           void *targinfo,
++           unsigned int targinfosize,
++           unsigned int hook_mask)
++{
++      if (targinfosize != 0) {
++              printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
++                     targinfosize);
++              return 0;
++      }
++
++      if (strcmp(tablename, "raw") != 0) {
++              printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_target ipt_notrack_reg = { 
++      .name = "NOTRACK", 
++      .target = target, 
++      .checkentry = checkentry,
++      .me = THIS_MODULE 
++};
++
++static int __init init(void)
++{
++      if (ipt_register_target(&ipt_notrack_reg))
++              return -EINVAL;
++
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_notrack_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_TTL.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_TTL.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_TTL.c       2004-03-16 11:53:46.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_ULOG.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_ULOG.c  2004-03-16 05:46:08.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_ULOG.c      2004-03-16 11:53:42.000000000 +0000
+@@ -50,6 +50,7 @@
+ #include <linux/netlink.h>
+ #include <linux/netdevice.h>
+ #include <linux/mm.h>
++#include <linux/netfilter.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv4/ipt_ULOG.h>
+ #include <linux/netfilter_ipv4/lockhelp.h>
+@@ -80,6 +81,10 @@
+ MODULE_PARM(flushtimeout, "i");
+ MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
++static unsigned int nflog = 1;
++MODULE_PARM(nflog, "i");
++MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
++
+ /* global data structures */
+ typedef struct {
+@@ -157,17 +162,17 @@
+       return skb;
+ }
+-static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+-                                  const struct net_device *in,
+-                                  const struct net_device *out,
+-                                  unsigned int hooknum,
+-                                  const void *targinfo, void *userinfo)
++static void ipt_ulog_packet(unsigned int hooknum,
++                          const struct sk_buff *skb,
++                          const struct net_device *in,
++                          const struct net_device *out,
++                          const struct ipt_ulog_info *loginfo,
++                          const char *prefix)
+ {
+       ulog_buff_t *ub;
+       ulog_packet_msg_t *pm;
+       size_t size, copy_len;
+       struct nlmsghdr *nlh;
+-      struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+       /* ffs == find first bit set, necessary because userspace
+        * is already shifting groupnumber, but we need unshifted.
+@@ -176,8 +181,8 @@
+       /* calculate the size of the skb needed */
+       if ((loginfo->copy_range == 0) ||
+-          (loginfo->copy_range > (*pskb)->len)) {
+-              copy_len = (*pskb)->len;
++          (loginfo->copy_range > skb->len)) {
++              copy_len = skb->len;
+       } else {
+               copy_len = loginfo->copy_range;
+       }
+@@ -214,19 +219,21 @@
+       /* copy hook, prefix, timestamp, payload, etc. */
+       pm->data_len = copy_len;
+-      pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+-      pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+-      pm->mark = (*pskb)->nfmark;
++      pm->timestamp_sec = skb->stamp.tv_sec;
++      pm->timestamp_usec = skb->stamp.tv_usec;
++      pm->mark = skb->nfmark;
+       pm->hook = hooknum;
+-      if (loginfo->prefix[0] != '\0')
++      if (prefix != NULL)
++              strncpy(pm->prefix, prefix, sizeof(pm->prefix));
++      else if (loginfo->prefix[0] != '\0')
+               strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+       else
+               *(pm->prefix) = '\0';
+       if (in && in->hard_header_len > 0
+-          && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
++          && skb->mac.raw != (void *) skb->nh.iph
+           && in->hard_header_len <= ULOG_MAC_LEN) {
+-              memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
++              memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
+               pm->mac_len = in->hard_header_len;
+       } else
+               pm->mac_len = 0;
+@@ -241,8 +248,8 @@
+       else
+               pm->outdev_name[0] = '\0';
+-      /* copy_len <= (*pskb)->len, so can't fail. */
+-      if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
++      /* copy_len <= skb->len, so can't fail. */
++      if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
+               BUG();
+       
+       /* check if we are building multi-part messages */
+@@ -266,8 +273,7 @@
+       UNLOCK_BH(&ulog_lock);
+-      return IPT_CONTINUE;
+-
++      return;
+ nlmsg_failure:
+       PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+@@ -276,8 +282,35 @@
+       PRINTR("ipt_ULOG: Error building netlink message\n");
+       UNLOCK_BH(&ulog_lock);
++}
++
++static unsigned int ipt_ulog_target(struct sk_buff **pskb,
++                                  const struct net_device *in,
++                                  const struct net_device *out,
++                                  unsigned int hooknum,
++                                  const void *targinfo, void *userinfo)
++{
++      struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+-      return IPT_CONTINUE;
++      ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
++ 
++      return IPT_CONTINUE;
++}
++ 
++static void ipt_logfn(unsigned int hooknum,
++                    const struct sk_buff *skb,
++                    const struct net_device *in,
++                    const struct net_device *out,
++                    const char *prefix)
++{
++      struct ipt_ulog_info loginfo = { 
++              .nl_group = ULOG_DEFAULT_NLGROUP,
++              .copy_range = 0,
++              .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
++              .prefix = ""
++      };
++
++      ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
+ }
+ static int ipt_ulog_checkentry(const char *tablename,
+@@ -341,7 +374,9 @@
+               sock_release(nflognl->sk_socket);
+               return -EINVAL;
+       }
+-
++      if (nflog)
++              nf_log_register(PF_INET, &ipt_logfn);
++      
+       return 0;
+ }
+@@ -352,6 +387,8 @@
+       DEBUGP("ipt_ULOG: cleanup_module\n");
++      if (nflog)
++              nf_log_unregister(PF_INET, &ipt_logfn);
+       ipt_unregister_target(&ipt_ulog_reg);
+       sock_release(nflognl->sk_socket);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connlimit.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connlimit.c     1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connlimit.c 2004-03-16 11:53:47.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_conntrack.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_conntrack.c     2004-03-16 05:47:18.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_conntrack.c 2004-03-16 11:53:55.000000000 +0000
+@@ -35,11 +35,13 @@
+ #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+-      if (ct)
+-              statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
+-      else
+-              statebit = IPT_CONNTRACK_STATE_INVALID;
+-
++      if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
++              statebit = IPT_CONNTRACK_STATE_UNTRACKED;
++      else if (ct)
++              statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
++      else
++              statebit = IPT_CONNTRACK_STATE_INVALID;
++ 
+       if(sinfo->flags & IPT_CONNTRACK_STATE) {
+               if (ct) {
+                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_dstlimit.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_dstlimit.c  2004-03-16 11:53:48.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_fuzzy.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_fuzzy.c     2004-03-16 11:53:50.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_ipv4options.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_ipv4options.c       2004-03-16 11:53:51.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_mport.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_mport.c     2004-03-16 11:53:52.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_nth.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_nth.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_nth.c       2004-03-16 11:53:53.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_quota.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_quota.c     2004-03-16 11:53:54.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_realm.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_realm.c     2004-03-16 11:53:56.000000000 +0000
+@@ -0,0 +1,78 @@
++/* IP tables module for matching the routing realm
++ *
++ * $Id$
++ *
++ * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/route.h>
++
++#include <linux/netfilter_ipv4/ipt_realm.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
++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,
++      int *hotdrop)
++{
++      const struct ipt_realm_info *info = matchinfo;
++      struct dst_entry *dst = skb->dst;
++    
++      if (!dst)
++              return 0;
++
++      return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
++}
++
++static int check(const char *tablename,
++                 const struct ipt_ip *ip,
++                 void *matchinfo,
++                 unsigned int matchsize,
++                 unsigned int hook_mask)
++{
++      if (hook_mask
++          & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
++              (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
++              printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
++                     "LOCAL_IN or FORWARD.\n");
++              return 0;
++      }
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
++              return 0;
++
++      return 1;
++}
++
++static struct ipt_match realm_match = {
++      .name = "realm",
++      .match = match, 
++      .checkentry = check,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&realm_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&realm_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_sctp.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_sctp.c  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_sctp.c      2004-03-16 11:53:57.000000000 +0000
+@@ -0,0 +1,197 @@
++#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>
++
++#if 1
++#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;
++
++      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.5-rc1.org/net/ipv4/netfilter/ipt_state.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_state.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_state.c 2004-03-16 05:47:39.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_state.c     2004-03-16 11:53:55.000000000 +0000
+@@ -30,7 +30,9 @@
+       enum ip_conntrack_info ctinfo;
+       unsigned int statebit;
+-      if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
++      if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
++              statebit = IPT_STATE_UNTRACKED;
++      else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
+               statebit = IPT_STATE_INVALID;
+       else
+               statebit = IPT_STATE_BIT(ctinfo);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_u32.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_u32.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_u32.c       2004-03-16 11:53:58.000000000 +0000
+@@ -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.5-rc1.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.5-rc1/net/ipv4/netfilter/iptable_raw.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/iptable_raw.c       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/iptable_raw.c   2004-03-16 11:53:55.000000000 +0000
+@@ -0,0 +1,149 @@
++/* 
++ * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
++ *
++ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ */
++#include <linux/module.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
++
++/* Standard entry. */
++struct ipt_standard
++{
++      struct ipt_entry entry;
++      struct ipt_standard_target target;
++};
++
++struct ipt_error_target
++{
++      struct ipt_entry_target target;
++      char errorname[IPT_FUNCTION_MAXNAMELEN];
++};
++
++struct ipt_error
++{
++      struct ipt_entry entry;
++      struct ipt_error_target target;
++};
++
++static struct
++{
++      struct ipt_replace repl;
++      struct ipt_standard entries[2];
++      struct ipt_error term;
++} initial_table __initdata
++= { { "raw", RAW_VALID_HOOKS, 3,
++      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
++      { [NF_IP_PRE_ROUTING] 0,
++      [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
++      { [NF_IP_PRE_ROUTING] 0,
++      [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
++      0, NULL, { } },
++    {
++          /* PRE_ROUTING */
++          { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++              0,
++              sizeof(struct ipt_entry),
++              sizeof(struct ipt_standard),
++              0, { 0, 0 }, { } },
++            { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
++              -NF_ACCEPT - 1 } },
++          /* LOCAL_OUT */
++          { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++              0,
++              sizeof(struct ipt_entry),
++              sizeof(struct ipt_standard),
++              0, { 0, 0 }, { } },
++            { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
++              -NF_ACCEPT - 1 } }
++    },
++    /* ERROR */
++    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++      0,
++      sizeof(struct ipt_entry),
++      sizeof(struct ipt_error),
++      0, { 0, 0 }, { } },
++      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
++        { } },
++      "ERROR"
++      }
++    }
++};
++
++static struct ipt_table packet_raw = { 
++      .name = "raw", 
++      .table = &initial_table.repl,
++      .valid_hooks =  RAW_VALID_HOOKS, 
++      .lock = RW_LOCK_UNLOCKED, 
++      .me = THIS_MODULE
++};
++
++/* The work comes in here from netfilter.c. */
++static unsigned int
++ipt_hook(unsigned int hook,
++       struct sk_buff **pskb,
++       const struct net_device *in,
++       const struct net_device *out,
++       int (*okfn)(struct sk_buff *))
++{
++      return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
++}
++
++/* 'raw' is the very first table. */
++static struct nf_hook_ops ipt_ops[] = {
++      {
++        .hook = ipt_hook, 
++        .pf = PF_INET, 
++        .hooknum = NF_IP_PRE_ROUTING, 
++        .priority = NF_IP_PRI_RAW
++      },
++      {
++        .hook = ipt_hook, 
++        .pf = PF_INET, 
++        .hooknum = NF_IP_LOCAL_OUT, 
++        .priority = NF_IP_PRI_RAW
++      },
++};
++
++static int __init init(void)
++{
++      int ret;
++
++      /* Register table */
++      ret = ipt_register_table(&packet_raw);
++      if (ret < 0)
++              return ret;
++
++      /* Register hooks */
++      ret = nf_register_hook(&ipt_ops[0]);
++      if (ret < 0)
++              goto cleanup_table;
++
++      ret = nf_register_hook(&ipt_ops[1]);
++      if (ret < 0)
++              goto cleanup_hook0;
++
++      return ret;
++
++ cleanup_hook0:
++      nf_unregister_hook(&ipt_ops[0]);
++ cleanup_table:
++      ipt_unregister_table(&packet_raw);
++
++      return ret;
++}
++
++static void __exit fini(void)
++{
++      unsigned int i;
++
++      for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
++              nf_unregister_hook(&ipt_ops[i]);
++
++      ipt_unregister_table(&packet_raw);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/Kconfig linux-2.6.5-rc1/net/ipv6/netfilter/Kconfig
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/Kconfig     2004-03-16 05:47:18.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/Kconfig 2004-03-16 11:53:55.000000000 +0000
+@@ -218,5 +218,37 @@
+         To compile it as a module, choose M here.  If unsure, say N.
+ #dep_tristate '  LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
++config IP6_NF_TARGET_HL
++      tristate  'HL target support'
++      depends on IP6_NF_MANGLE
++        help
++
++config IP6_NF_TARGET_REJECT
++      tristate  'REJECT target support'
++      depends on IP6_NF_FILTER
++        help
++
++config IP6_NF_MATCH_FUZZY
++      tristate  'Fuzzy match support'
++      depends on IP6_NF_FILTER
++        help
++
++config IP6_NF_MATCH_NTH
++      tristate  'Nth match support'
++      depends on IP6_NF_IPTABLES
++        help
++
++config IP6_NF_RAW
++      tristate  'raw table support (required for TRACE)'
++      depends on IP6_NF_IPTABLES
++      help
++        This option adds a `raw' table to ip6tables. This table is the very
++        first in the netfilter framework and hooks in at the PREROUTING
++        and OUTPUT chains.
++      
++        If you want to compile it as a module, say M here and read
++        <file:Documentation/modules.txt>.  If unsure, say `N'.
++        help
++
+ endmenu
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/Makefile linux-2.6.5-rc1/net/ipv6/netfilter/Makefile
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/Makefile    2004-03-16 05:46:44.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/Makefile        2004-03-16 11:53:55.000000000 +0000
+@@ -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
+@@ -19,6 +20,11 @@
+ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
+ obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
+ obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
++obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
+ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
+ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
++obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
++
++obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
++obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_HL.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_HL.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_HL.c       2004-03-16 11:53:43.000000000 +0000
+@@ -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.5-rc1.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_LOG.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_LOG.c  2004-03-16 05:45:58.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_LOG.c      2004-03-16 11:53:42.000000000 +0000
+@@ -18,12 +18,17 @@
+ #include <net/udp.h>
+ #include <net/tcp.h>
+ #include <net/ipv6.h>
++#include <linux/netfilter.h>
+ #include <linux/netfilter_ipv6/ip6_tables.h>
+ MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
+ MODULE_DESCRIPTION("IP6 tables LOG target module");
+ MODULE_LICENSE("GPL");
++static unsigned int nflog = 1;
++MODULE_PARM(nflog, "i");
++MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
++ 
+ struct in_device;
+ #include <net/route.h>
+ #include <linux/netfilter_ipv6/ip6t_LOG.h>
+@@ -265,40 +270,38 @@
+       }
+ }
+-static unsigned int
+-ip6t_log_target(struct sk_buff **pskb,
+-              unsigned int hooknum,
++static void
++ip6t_log_packet(unsigned int hooknum,
++              const struct sk_buff *skb,
+               const struct net_device *in,
+               const struct net_device *out,
+-              const void *targinfo,
+-              void *userinfo)
++              const struct ip6t_log_info *loginfo,
++              const char *level_string,
++              const char *prefix)
+ {
+-      struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
+-      const struct ip6t_log_info *loginfo = targinfo;
+-      char level_string[4] = "< >";
++      struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+-      level_string[1] = '0' + (loginfo->level % 8);
+       spin_lock_bh(&log_lock);
+       printk(level_string);
+       printk("%sIN=%s OUT=%s ",
+-              loginfo->prefix,
++              prefix == NULL ? loginfo->prefix : prefix,
+               in ? in->name : "",
+               out ? out->name : "");
+       if (in && !out) {
+               /* MAC logging for input chain only. */
+               printk("MAC=");
+-              if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
+-                      if ((*pskb)->dev->type != ARPHRD_SIT){
++              if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
++                      if (skb->dev->type != ARPHRD_SIT){
+                         int i;
+-                        unsigned char *p = (*pskb)->mac.raw;
+-                        for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
++                        unsigned char *p = skb->mac.raw;
++                        for (i = 0; i < skb->dev->hard_header_len; i++,p++)
+                               printk("%02x%c", *p,
+-                                      i==(*pskb)->dev->hard_header_len - 1
++                                      i==skb->dev->hard_header_len - 1
+                                       ? ' ':':');
+                       } else {
+                         int i;
+-                        unsigned char *p = (*pskb)->mac.raw;
+-                        if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
++                        unsigned char *p = skb->mac.raw;
++                        if ( p - (ETH_ALEN*2+2) > skb->head ){
+                           p -= (ETH_ALEN+2);
+                           for (i = 0; i < (ETH_ALEN); i++,p++)
+                               printk("%02x%s", *p,
+@@ -309,10 +312,10 @@
+                                       i == ETH_ALEN-1 ? ' ' : ':');
+                         }
+                         
+-                        if (((*pskb)->dev->addr_len == 4) &&
+-                            (*pskb)->dev->hard_header_len > 20){
++                        if ((skb->dev->addr_len == 4) &&
++                            skb->dev->hard_header_len > 20){
+                           printk("TUNNEL=");
+-                          p = (*pskb)->mac.raw + 12;
++                          p = skb->mac.raw + 12;
+                           for (i = 0; i < 4; i++,p++)
+                               printk("%3d%s", *p,
+                                       i == 3 ? "->" : ".");
+@@ -328,10 +331,41 @@
+       dump_packet(loginfo, ipv6h, 1);
+       printk("\n");
+       spin_unlock_bh(&log_lock);
++}
++
++static unsigned int
++ip6t_log_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_log_info *loginfo = targinfo;
++      char level_string[4] = "< >";
++
++      level_string[1] = '0' + (loginfo->level % 8);
++      ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
+       return IP6T_CONTINUE;
+ }
++static void
++ip6t_logfn(unsigned int hooknum,
++         const struct sk_buff *skb,
++         const struct net_device *in,
++         const struct net_device *out,
++         const char *prefix)
++{
++      struct ip6t_log_info loginfo = {
++              .level = 0,
++              .logflags = IP6T_LOG_MASK,
++              .prefix = ""
++      };
++
++      ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
++}
++
+ static int ip6t_log_checkentry(const char *tablename,
+                              const struct ip6t_entry *e,
+                              void *targinfo,
+@@ -360,20 +394,27 @@
+       return 1;
+ }
+-static struct ip6t_target ip6t_log_reg
+-= { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL, 
+-    THIS_MODULE };
++static struct ip6t_target ip6t_log_reg = {
++      .name           = "LOG",
++      .target         = ip6t_log_target, 
++      .checkentry     = ip6t_log_checkentry, 
++      .me             = THIS_MODULE,
++};
+ static int __init init(void)
+ {
+       if (ip6t_register_target(&ip6t_log_reg))
+               return -EINVAL;
++      if (nflog)
++              nf_log_register(PF_INET6, &ip6t_logfn);
+       return 0;
+ }
+ static void __exit fini(void)
+ {
++      if (nflog)
++              nf_log_unregister(PF_INET6, &ip6t_logfn);
+       ip6t_unregister_target(&ip6t_log_reg);
+ }
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_REJECT.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_REJECT.c   2004-03-16 11:53:45.000000000 +0000
+@@ -0,0 +1,274 @@
++/*
++ * This is a module which is used for rejecting packets.
++ *    Added support for customized reject packets (Jozsef Kadlecsik).
++ * Sun 12 Nov 2000
++ *    Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/icmpv6.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_REJECT.h>
++
++#if 1
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#if 0
++/* Send RST reply */
++static void send_reset(struct sk_buff *oldskb)
++{
++      struct sk_buff *nskb;
++      struct tcphdr *otcph, *tcph;
++      struct rtable *rt;
++      unsigned int otcplen;
++      int needs_ack;
++
++      /* IP header checks: fragment, too short. */
++      if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
++          || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
++              return;
++
++      otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
++      otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
++
++      /* No RST for RST. */
++      if (otcph->rst)
++              return;
++
++      /* Check checksum. */
++      if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
++                       oldskb->nh.iph->daddr,
++                       csum_partial((char *)otcph, otcplen, 0)) != 0)
++              return;
++
++      /* Copy skb (even if skb is about to be dropped, we can't just
++           clone it because there may be other things, such as tcpdump,
++           interested in it) */
++      nskb = skb_copy(oldskb, GFP_ATOMIC);
++      if (!nskb)
++              return;
++
++      /* This packet will not be the same as the other: clear nf fields */
++      nf_conntrack_put(nskb->nfct);
++      nskb->nfct = NULL;
++      nskb->nfcache = 0;
++#ifdef CONFIG_NETFILTER_DEBUG
++      nskb->nf_debug = 0;
++#endif
++
++      tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
++
++      nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
++      tcph->source = xchg(&tcph->dest, tcph->source);
++
++      /* Truncate to length (no data) */
++      tcph->doff = sizeof(struct tcphdr)/4;
++      skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
++      nskb->nh.iph->tot_len = htons(nskb->len);
++
++      if (tcph->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;
++
++      /* Adjust TCP checksum */
++      tcph->check = 0;
++      tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
++                                 nskb->nh.iph->saddr,
++                                 nskb->nh.iph->daddr,
++                                 csum_partial((char *)tcph,
++                                              sizeof(struct tcphdr), 0));
++
++      /* Adjust IP TTL, DF */
++      nskb->nh.iph->ttl = MAXTTL;
++      /* Set DF, id = 0 */
++      nskb->nh.iph->frag_off = htons(IP_DF);
++      nskb->nh.iph->id = 0;
++
++      /* Adjust IP checksum */
++      nskb->nh.iph->check = 0;
++      nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
++                                         nskb->nh.iph->ihl);
++
++      /* Routing */
++      if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
++                          RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
++                          0) != 0)
++              goto free_nskb;
++
++      dst_release(nskb->dst);
++      nskb->dst = &rt->u.dst;
++
++      /* "Never happens" */
++      if (nskb->len > nskb->dst->pmtu)
++              goto free_nskb;
++
++      NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++              ip_finish_output);
++      return;
++
++ free_nskb:
++      kfree_skb(nskb);
++}
++#endif
++
++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;
++
++      /* WARNING: This code causes reentry within ip6tables.
++         This means that the ip6tables jump stack is now crap.  We
++         must return an absolute verdict. --RR */
++      DEBUGP("REJECTv6: calling icmpv6_send\n");
++      switch (reject->with) {
++      case IP6T_ICMP6_NO_ROUTE:
++              icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out);
++              break;
++      case IP6T_ICMP6_ADM_PROHIBITED:
++              icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out);
++              break;
++      case IP6T_ICMP6_NOT_NEIGHBOUR:
++              icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out);
++              break;
++      case IP6T_ICMP6_ADDR_UNREACH:
++              icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out);
++              break;
++      case IP6T_ICMP6_PORT_UNREACH:
++              icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out);
++              break;
++#if 0
++      case IPT_ICMP_ECHOREPLY: {
++              struct icmp6hdr *icmph  = (struct icmphdr *)
++                      ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
++              unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
++
++              /* Not non-head frags, or truncated */
++              if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
++                  && datalen >= 4) {
++                      /* Usually I don't like cut & pasting code,
++                           but dammit, my party is starting in 45
++                           mins! --RR */
++                      struct icmp_bxm icmp_param;
++
++                      icmp_param.icmph=*icmph;
++                      icmp_param.icmph.type=ICMP_ECHOREPLY;
++                      icmp_param.data_ptr=(icmph+1);
++                      icmp_param.data_len=datalen;
++                      icmp_reply(&icmp_param, *pskb);
++              }
++      }
++      break;
++      case IPT_TCP_RESET:
++              send_reset(*pskb);
++              break;
++#endif
++      default:
++              printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
++              break;
++      }
++
++      return NF_DROP;
++}
++
++static inline int find_ping_match(const struct ip6t_entry_match *m)
++{
++      const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
++
++      if (strcmp(m->u.kernel.match->name, "icmp6") == 0
++          && icmpinfo->type == ICMPV6_ECHO_REQUEST
++          && !(icmpinfo->invflags & IP6T_ICMP_INV))
++              return 1;
++
++      return 0;
++}
++
++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("REJECTv6: targinfosize %u != 0\n", targinfosize);
++              return 0;
++      }
++
++      /* Only allow these for packet filtering. */
++      if (strcmp(tablename, "filter") != 0) {
++              DEBUGP("REJECTv6: 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("REJECTv6: bad hook mask %X\n", hook_mask);
++              return 0;
++      }
++
++      if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
++              /* Must specify that it's an ICMP ping packet. */
++              if (e->ipv6.proto != IPPROTO_ICMPV6
++                  || (e->ipv6.invflags & IP6T_INV_PROTO)) {
++                      DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
++                      return 0;
++              }
++              /* Must contain ICMP match. */
++              if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
++                      DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\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("REJECTv6: TCP_RESET illegal for non-tcp\n");
++                      return 0;
++              }
++      }
++
++      return 1;
++}
++
++static struct ip6t_target ip6t_reject_reg
++= { { NULL, NULL }, "REJECT", reject6_target, check, NULL, 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.5-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_fuzzy.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_fuzzy.c    2004-03-16 11:53:50.000000000 +0000
+@@ -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.5-rc1.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_nth.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_nth.c  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_nth.c      2004-03-16 11:53:53.000000000 +0000
+@@ -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);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6table_raw.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6table_raw.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6table_raw.c  2004-03-16 11:53:55.000000000 +0000
+@@ -0,0 +1,154 @@
++/*
++ * IPv6 raw table, a port of the IPv4 raw table to IPv6
++ *
++ * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ */
++#include <linux/module.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++
++#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
++
++#if 0
++#define DEBUGP(x, args...)    printk(KERN_DEBUG x, ## args)
++#else
++#define DEBUGP(x, args...)
++#endif
++
++/* Standard entry. */
++struct ip6t_standard
++{
++      struct ip6t_entry entry;
++      struct ip6t_standard_target target;
++};
++
++struct ip6t_error_target
++{
++      struct ip6t_entry_target target;
++      char errorname[IP6T_FUNCTION_MAXNAMELEN];
++};
++
++struct ip6t_error
++{
++      struct ip6t_entry entry;
++      struct ip6t_error_target target;
++};
++
++static struct
++{
++      struct ip6t_replace repl;
++      struct ip6t_standard entries[2];
++      struct ip6t_error term;
++} initial_table __initdata 
++= { { "raw", RAW_VALID_HOOKS, 3,
++      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
++      { [NF_IP6_PRE_ROUTING]  0,
++      [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) },
++      { [NF_IP6_PRE_ROUTING]  0,
++      [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) },
++      0, NULL, { } },
++    {
++          /* PRE_ROUTING */
++            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++              0,
++              sizeof(struct ip6t_entry),
++              sizeof(struct ip6t_standard),
++              0, { 0, 0 }, { } },
++            { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
++              -NF_ACCEPT - 1 } },
++          /* LOCAL_OUT */
++            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++              0,
++              sizeof(struct ip6t_entry),
++              sizeof(struct ip6t_standard),
++              0, { 0, 0 }, { } },
++            { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
++              -NF_ACCEPT - 1 } },
++    },
++    /* ERROR */
++    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
++      0,
++      sizeof(struct ip6t_entry),
++      sizeof(struct ip6t_error),
++      0, { 0, 0 }, { } },
++      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
++        { } },
++      "ERROR"
++      }
++    }
++};
++
++static struct ip6t_table packet_raw = { 
++      .name = "raw", 
++      .table = &initial_table.repl,
++      .valid_hooks = RAW_VALID_HOOKS, 
++      .lock = RW_LOCK_UNLOCKED, 
++      .me = THIS_MODULE
++};
++
++/* The work comes in here from netfilter.c. */
++static unsigned int
++ip6t_hook(unsigned int hook,
++       struct sk_buff **pskb,
++       const struct net_device *in,
++       const struct net_device *out,
++       int (*okfn)(struct sk_buff *))
++{
++      return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
++}
++
++static struct nf_hook_ops ip6t_ops[] = { 
++      {
++        .hook = ip6t_hook, 
++        .pf = PF_INET6,
++        .hooknum = NF_IP6_PRE_ROUTING,
++        .priority = NF_IP6_PRI_FIRST
++      },
++      {
++        .hook = ip6t_hook, 
++        .pf = PF_INET6, 
++        .hooknum = NF_IP6_LOCAL_OUT,
++        .priority = NF_IP6_PRI_FIRST
++      },
++};
++
++static int __init init(void)
++{
++      int ret;
++
++      /* Register table */
++      ret = ip6t_register_table(&packet_raw);
++      if (ret < 0)
++              return ret;
++
++      /* Register hooks */
++      ret = nf_register_hook(&ip6t_ops[0]);
++      if (ret < 0)
++              goto cleanup_table;
++
++      ret = nf_register_hook(&ip6t_ops[1]);
++      if (ret < 0)
++              goto cleanup_hook0;
++
++      return ret;
++
++ cleanup_hook0:
++      nf_unregister_hook(&ip6t_ops[0]);
++ cleanup_table:
++      ip6t_unregister_table(&packet_raw);
++
++      return ret;
++}
++
++static void __exit fini(void)
++{
++      unsigned int i;
++
++      for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
++              nf_unregister_hook(&ip6t_ops[i]);
++
++      ip6t_unregister_table(&packet_raw);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
diff --git a/2.6.5-rc1-patch-o-matic-ng-extra-20040316.patch b/2.6.5-rc1-patch-o-matic-ng-extra-20040316.patch
new file mode 100644 (file)
index 0000000..900dac2
--- /dev/null
@@ -0,0 +1,4612 @@
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_helpers.h linux-2.6.5-rc1/include/linux/netfilter_helpers.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_helpers.h      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_helpers.h  2004-03-16 12:04:49.000000000 +0000
+@@ -0,0 +1,133 @@
++/*
++ * Helpers for netfiler modules.  This file provides implementations for basic
++ * functions such as strncasecmp(), etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_STRNCASECMP        nf_strncasecmp()
++ *   NF_NEED_STRTOU16           nf_strtou16()
++ *   NF_NEED_STRTOU32           nf_strtou32()
++ */
++#ifndef _NETFILTER_HELPERS_H
++#define _NETFILTER_HELPERS_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++#define iseol(c) ( (c) == '\r' || (c) == '\n' )
++
++/*
++ * The standard strncasecmp()
++ */
++#ifdef NF_NEED_STRNCASECMP
++static int
++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
++{
++    if (s1 == NULL || s2 == NULL)
++    {
++        if (s1 == NULL && s2 == NULL)
++        {
++            return 0;
++        }
++        return (s1 == NULL) ? -1 : 1;
++    }
++    while (len > 0 && tolower(*s1) == tolower(*s2))
++    {
++        len--;
++        s1++;
++        s2++;
++    }
++    return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
++}
++#endif /* NF_NEED_STRNCASECMP */
++
++/*
++ * Parse a string containing a 16-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU16
++static int
++nf_strtou16(const char* pbuf, u_int16_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (isdigit(pbuf[n]))
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU16 */
++
++/*
++ * Parse a string containing a 32-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU32
++static int
++nf_strtou32(const char* pbuf, u_int32_t* pval)
++{
++    int n = 0;
++
++    *pval = 0;
++    while (pbuf[n] >= '0' && pbuf[n] <= '9')
++    {
++        *pval = (*pval * 10) + (pbuf[n] - '0');
++        n++;
++    }
++
++    return n;
++}
++#endif /* NF_NEED_STRTOU32 */
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.
++ */
++#ifdef NF_NEED_NEXTLINE
++static int
++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    while (p[off] != '\n')
++    {
++        if (len-off <= 1)
++        {
++            return 0;
++        }
++
++        physlen++;
++        off++;
++    }
++
++    /* if we saw a crlf, physlen needs adjusted */
++    if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++    {
++        physlen--;
++    }
++
++    /* advance past the newline */
++    off++;
++
++    *plineoff = *poff;
++    *plinelen = physlen;
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_HELPERS_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h    2004-03-16 12:00:23.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h        2004-03-16 12:04:49.000000000 +0000
+@@ -64,6 +64,7 @@
+ };
+ /* Add protocol helper include file here */
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+@@ -71,6 +72,8 @@
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+       /* insert conntrack helper private data (expect) here */
++      struct ip_ct_rtsp_expect exp_rtsp_info;
++      struct ip_ct_rtsp_master ct_rtsp_info;
+       struct ip_ct_amanda_expect exp_amanda_info;
+       struct ip_ct_ftp_expect exp_ftp_info;
+       struct ip_ct_irc_expect exp_irc_info;
+@@ -206,6 +209,10 @@
+       } nat;
+ #endif /* CONFIG_IP_NF_NAT_NEEDED */
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++      unsigned long mark;
++#endif
++
+ };
+ /* get master conntrack via master expectation */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rpc.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rpc.h    2004-03-16 12:04:46.000000000 +0000
+@@ -0,0 +1,68 @@
++/* RPC extension for IP connection tracking, Version 2.2
++ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
++ *    - original rpc tracking module
++ *    - "recent" connection handling for kernel 2.3+ netfilter
++ *
++ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
++ *    - upgraded conntrack modules to oldnat api - kernel 2.4.0+
++ *
++ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ *    - upgraded conntrack modules to newnat api - kernel 2.4.20+
++ *    - extended matching to support filtering on procedures
++ *
++ * ip_conntrack_rpc.h,v 2.2 2003/01/12 18:30:00
++ *
++ *    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 <asm/param.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/stddef.h>
++#include <linux/list.h>
++
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#ifndef _IP_CONNTRACK_RPC_H
++#define _IP_CONNTRACK_RPC_H
++
++#define RPC_PORT       111
++
++
++/* Datum in RPC packets are encoded in XDR */
++#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf))
++
++/* Fast timeout, to deny DoS atacks */
++#define EXP (60 * HZ)
++
++/* Normal timeouts */
++#define EXPIRES (180 * HZ)
++
++/* For future conections RPC, using client's cache bindings
++ * I'll use ip_conntrack_lock to lock these lists     */
++
++/* This identifies each request and stores protocol */
++struct request_p {
++      struct list_head list;
++
++      u_int32_t xid;   
++      u_int32_t ip;
++      u_int16_t port;
++      
++      /* Protocol */
++      u_int16_t proto;
++
++      struct timer_list timeout;
++};
++
++static inline int request_p_cmp(const struct request_p *p, u_int32_t xid, 
++                              u_int32_t ip, u_int32_t port) {
++      return (p->xid == xid && p->ip == ip && p->port);
++
++}
++
++#endif /* _IP_CONNTRACK_RPC_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h   2004-03-16 12:04:49.000000000 +0000
+@@ -0,0 +1,68 @@
++/*
++ * RTSP extension for IP connection tracking.
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.h
++ *
++ *      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.
++ */
++#ifndef _IP_CONNTRACK_RTSP_H
++#define _IP_CONNTRACK_RTSP_H
++
++/* #define IP_NF_RTSP_DEBUG */
++#define IP_NF_RTSP_VERSION "0.01"
++
++/* port block types */
++typedef enum {
++    pb_single,  /* client_port=x */
++    pb_range,   /* client_port=x-y */
++    pb_discon   /* client_port=x/y (rtspbis) */
++} portblock_t;
++
++/* We record seq number and length of rtsp headers here, all in host order. */
++
++/*
++ * This structure is per expected connection.  It is a member of struct
++ * ip_conntrack_expect.  The TCP SEQ for the conntrack expect is stored
++ * there and we are expected to only store the length of the data which
++ * needs replaced.  If a packet contains multiple RTSP messages, we create
++ * one expected connection per message.
++ *
++ * We use these variables to mark the entire header block.  This may seem
++ * like overkill, but the nature of RTSP requires it.  A header may appear
++ * multiple times in a message.  We must treat two Transport headers the
++ * same as one Transport header with two entries.
++ */
++struct ip_ct_rtsp_expect
++{
++    u_int32_t   len;        /* length of header block */
++    portblock_t pbtype;     /* Type of port block that was requested */
++    u_int16_t   loport;     /* Port that was requested, low or first */
++    u_int16_t   hiport;     /* Port that was requested, high or second */
++#if 0
++    uint        method;     /* RTSP method */
++    uint        cseq;       /* CSeq from request */
++#endif
++};
++
++/* This structure exists only once per master */
++struct ip_ct_rtsp_master
++{
++    /* Empty (?) */
++};
++
++
++#ifdef __KERNEL__
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++#define RTSP_PORT   554
++
++/* Protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#endif /* __KERNEL__ */
++
++#endif /* _IP_CONNTRACK_RTSP_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h    1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_CONNMARK.h        2004-03-16 12:04:09.000000000 +0000
+@@ -0,0 +1,25 @@
++#ifndef _IPT_CONNMARK_H_target
++#define _IPT_CONNMARK_H_target
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * 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.
++ */
++
++enum {
++      IPT_CONNMARK_SET = 0,
++      IPT_CONNMARK_SAVE,
++      IPT_CONNMARK_RESTORE
++};
++
++struct ipt_connmark_target_info {
++      unsigned long mark;
++      unsigned long mask;
++      u_int8_t mode;
++};
++
++#endif /*_IPT_CONNMARK_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_IPMARK.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_IPMARK.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_IPMARK.h      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_IPMARK.h  2004-03-16 12:04:10.000000000 +0000
+@@ -0,0 +1,13 @@
++#ifndef _IPT_IPMARK_H_target
++#define _IPT_IPMARK_H_target
++
++struct ipt_ipmark_target_info {
++      unsigned long andmask;
++      unsigned long ormask;
++      unsigned int addr;
++};
++
++#define IPT_IPMARK_SRC    0
++#define IPT_IPMARK_DST    1
++
++#endif /*_IPT_IPMARK_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_XOR.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_XOR.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_XOR.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_XOR.h     2004-03-16 12:04:18.000000000 +0000
+@@ -0,0 +1,9 @@
++#ifndef _IPT_XOR_H
++#define _IPT_XOR_H
++
++struct ipt_XOR_info {
++      char            key[30];
++      u_int8_t        block_size;
++};
++
++#endif /* _IPT_XOR_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_addrtype.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_addrtype.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_addrtype.h    1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_addrtype.h        2004-03-16 12:04:20.000000000 +0000
+@@ -0,0 +1,11 @@
++#ifndef _IPT_ADDRTYPE_H
++#define _IPT_ADDRTYPE_H
++
++struct ipt_addrtype_info {
++      u_int16_t       source;         /* source-type mask */
++      u_int16_t       dest;           /* dest-type mask */
++      int             invert_source;
++      int             invert_dest;
++};
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connmark.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connmark.h    1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connmark.h        2004-03-16 12:04:09.000000000 +0000
+@@ -0,0 +1,18 @@
++#ifndef _IPT_CONNMARK_H
++#define _IPT_CONNMARK_H
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * 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.
++ */
++
++struct ipt_connmark_info {
++      unsigned long mark, mask;
++      u_int8_t invert;
++};
++
++#endif /*_IPT_CONNMARK_H*/
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_policy.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_policy.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_policy.h      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_policy.h  2004-03-16 12:04:45.000000000 +0000
+@@ -0,0 +1,52 @@
++#ifndef _IPT_POLICY_H
++#define _IPT_POLICY_H
++
++#define POLICY_MAX_ELEM       4
++
++enum ipt_policy_flags
++{
++      POLICY_MATCH_IN         = 0x1,
++      POLICY_MATCH_OUT        = 0x2,
++      POLICY_MATCH_NONE       = 0x4,
++      POLICY_MATCH_STRICT     = 0x8,
++};
++
++enum ipt_policy_modes
++{
++      POLICY_MODE_TRANSPORT,
++      POLICY_MODE_TUNNEL
++};
++
++struct ipt_policy_spec
++{
++      u_int8_t        saddr:1,
++                      daddr:1,
++                      proto:1,
++                      mode:1,
++                      spi:1,
++                      reqid:1;
++};
++
++struct ipt_policy_elem
++{
++      u_int32_t       saddr;
++      u_int32_t       smask;
++      u_int32_t       daddr;
++      u_int32_t       dmask;
++      u_int32_t       spi;
++      u_int32_t       reqid;
++      u_int8_t        proto;
++      u_int8_t        mode;
++
++      struct ipt_policy_spec  match;
++      struct ipt_policy_spec  invert;
++};
++
++struct ipt_policy_info
++{
++      struct ipt_policy_elem pol[POLICY_MAX_ELEM];
++      u_int16_t flags;
++      u_int16_t len;
++};
++
++#endif /* _IPT_POLICY_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_rpc.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_rpc.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_rpc.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_rpc.h     2004-03-16 12:04:46.000000000 +0000
+@@ -0,0 +1,35 @@
++/* RPC extension for IP netfilter matching, Version 2.2
++ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
++ *    - original rpc tracking module
++ *    - "recent" connection handling for kernel 2.3+ netfilter
++ *
++ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
++ *    - upgraded conntrack modules to oldnat api - kernel 2.4.0+
++ *
++ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ *    - upgraded conntrack modules to newnat api - kernel 2.4.20+
++ *    - extended matching to support filtering on procedures
++ *
++ * ipt_rpc.h.c,v 2.2 2003/01/12 18:30:00
++ *
++ *    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.
++ **
++ */
++
++#ifndef _IPT_RPC_H
++#define _IPT_RPC_H
++
++struct ipt_rpc_data;
++
++struct ipt_rpc_info {
++      int inverse;
++      int strict;
++      const char c_procs[1408];
++      int i_procs;
++      struct ipt_rpc_data *data;
++};
++
++#endif /* _IPT_RPC_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_string.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_string.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_string.h      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_string.h  2004-03-16 12:06:26.000000000 +0000
+@@ -0,0 +1,21 @@
++#ifndef _IPT_STRING_H
++#define _IPT_STRING_H
++
++/* *** PERFORMANCE TWEAK ***
++ * Packet size and search string threshold,
++ * above which sublinear searches is used. */
++#define IPT_STRING_HAYSTACK_THRESH    100
++#define IPT_STRING_NEEDLE_THRESH      20
++
++#define BM_MAX_NLEN 256
++#define BM_MAX_HLEN 1024
++
++typedef char *(*proc_ipt_search) (char *, char *, int, int);
++
++struct ipt_string_info {
++    char string[BM_MAX_NLEN];
++    u_int16_t invert;
++    u_int16_t len;
++};
++
++#endif /* _IPT_STRING_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_owner.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_owner.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_owner.h      2004-03-16 05:46:45.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_owner.h  2004-03-16 12:04:42.000000000 +0000
+@@ -6,12 +6,14 @@
+ #define IP6T_OWNER_GID        0x02
+ #define IP6T_OWNER_PID        0x04
+ #define IP6T_OWNER_SID        0x08
++#define IP6T_OWNER_COMM 0x10
+ struct ip6t_owner_info {
+     uid_t uid;
+     gid_t gid;
+     pid_t pid;
+     pid_t sid;
++    char comm[16];
+     u_int8_t match, invert;   /* flags */
+ };
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_mime.h linux-2.6.5-rc1/include/linux/netfilter_mime.h
+--- linux-2.6.5-rc1.org/include/linux/netfilter_mime.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/include/linux/netfilter_mime.h     2004-03-16 12:04:49.000000000 +0000
+@@ -0,0 +1,89 @@
++/*
++ * MIME functions for netfilter modules.  This file provides implementations
++ * for basic MIME parsing.  MIME headers are used in many protocols, such as
++ * HTTP, RTSP, SIP, etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested.  The following macros are used:
++ *   NF_NEED_MIME_NEXTLINE      nf_mime_nextline()
++ */
++#ifndef _NETFILTER_MIME_H
++#define _NETFILTER_MIME_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.  If the current line is empty, *plinelen will be set to zero.  If
++ * not, it will be set to the actual line length (including CRLF).
++ *
++ * 'line' in this context means logical line (includes LWS continuations).
++ * Returns 1 on success, 0 on failure.
++ */
++#ifdef NF_NEED_MIME_NEXTLINE
++static int
++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++    uint    off = *poff;
++    uint    physlen = 0;
++    int     is_first_line = 1;
++
++    if (off >= len)
++    {
++        return 0;
++    }
++
++    do
++    {
++        while (p[off] != '\n')
++        {
++            if (len-off <= 1)
++            {
++                return 0;
++            }
++
++            physlen++;
++            off++;
++        }
++
++        /* if we saw a crlf, physlen needs adjusted */
++        if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++        {
++            physlen--;
++        }
++
++        /* advance past the newline */
++        off++;
++
++        /* check for an empty line */
++        if (physlen == 0)
++        {
++            break;
++        }
++
++        /* check for colon on the first physical line */
++        if (is_first_line)
++        {
++            is_first_line = 0;
++            if (memchr(p+(*poff), ':', physlen) == NULL)
++            {
++                return 0;
++            }
++        }
++    }
++    while (p[off] == ' ' || p[off] == '\t');
++
++    *plineoff = *poff;
++    *plinelen = (physlen == 0) ? 0 : (off - *poff);
++    *poff = off;
++
++    return 1;
++}
++#endif /* NF_NEED_MIME_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_MIME_H */
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/net/tcp.h linux-2.6.5-rc1/include/net/tcp.h
+--- linux-2.6.5-rc1.org/include/net/tcp.h      2004-03-16 05:45:33.000000000 +0000
++++ linux-2.6.5-rc1/include/net/tcp.h  2004-03-16 12:04:38.000000000 +0000
+@@ -162,6 +162,7 @@
+ extern void tcp_bucket_unlock(struct sock *sk);
+ extern int tcp_port_rover;
+ extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif);
++extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 hnum, int dif);
+ /* These are AF independent. */
+ static __inline__ int tcp_bhashfn(__u16 lport)
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/net/udp.h linux-2.6.5-rc1/include/net/udp.h
+--- linux-2.6.5-rc1.org/include/net/udp.h      2004-03-16 05:47:17.000000000 +0000
++++ linux-2.6.5-rc1/include/net/udp.h  2004-03-16 12:04:38.000000000 +0000
+@@ -74,6 +74,8 @@
+ extern int    udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+ extern int    udp_disconnect(struct sock *sk, int flags);
++extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
++
+ DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
+ #define UDP_INC_STATS(field)          SNMP_INC_STATS(udp_statistics, field)
+ #define UDP_INC_STATS_BH(field)               SNMP_INC_STATS_BH(udp_statistics, field)
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig     2004-03-16 12:00:23.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig 2004-03-16 12:06:26.000000000 +0000
+@@ -672,5 +672,61 @@
+       depends on IP_NF_IPTABLES
+         help
++config IP_NF_CONNTRACK_MARK
++      bool  'Connection mark tracking support'
++config IP_NF_TARGET_CONNMARK
++      tristate  'CONNMARK target support'
++      depends on IP_NF_MANGLE
++config IP_NF_MATCH_CONNMARK
++      tristate  ' Connection mark match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_TARGET_IPMARK
++      tristate  'IPMARK target support'
++      depends on IP_NF_MANGLE
++        help
++
++config IP_NF_TARGET_XOR
++      tristate  'XOR target support'
++      depends on IP_NF_MANGLE
++        help
++
++config IP_NF_MATCH_ADDRTYPE
++      tristate  'address type match support'
++      depends on IP_NF_IPTABLES
++        help
++
++config IP_NF_MATCH_POLICY
++       tristate "IPsec policy match support"
++       depends on IP_NF_IPTABLES && XFRM
++       help
++         Policy matching allows you to match packets based on the
++         IPsec policy that was used during decapsulation/will
++         be used during encapsulation.
++
++         To compile it as a module, choose M here.  If unsure, say N.
++        help
++
++config IP_NF_MATCH_RPC
++      tristate  'RPC match support'
++      depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
++        help
++
++config IP_NF_NAT_RTSP
++      tristate
++      depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++      default IP_NF_NAT if IP_NF_RTSP=y
++      default m if IP_NF_RTSP=m
++config IP_NF_RTSP
++      tristate  ' RTSP protocol support'
++      depends on IP_NF_CONNTRACK
++        help
++
++config IP_NF_MATCH_STRING
++      tristate  'String match support'
++      depends on IP_NF_IPTABLES
++        help
++
+ endmenu
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile linux-2.6.5-rc1/net/ipv4/netfilter/Makefile
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile    2004-03-16 12:00:23.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/Makefile        2004-03-16 12:06:26.000000000 +0000
+@@ -20,6 +20,14 @@
+ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
+ # connection tracking helpers
++
++# rtsp protocol support
++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o
++ifdef CONFIG_IP_NF_NAT_RTSP
++       export-objs += ip_conntrack_rtsp.o
++endif
++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
++
+ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
+ obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
+ obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+@@ -41,6 +49,9 @@
+ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+ # matches
++obj-$(CONFIG_IP_NF_MATCH_RPC) += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ipt_rpc.o
++export-objs += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o
++
+ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
+ obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+ obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
+@@ -48,6 +59,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
+ obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
++obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
+ obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
+ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
+@@ -78,12 +90,15 @@
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
++obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.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_ADDRTYPE) += ipt_addrtype.o
+ obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
+ obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
++obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+@@ -91,6 +106,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+ obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
+ obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
++obj-$(CONFIG_IP_NF_TARGET_IPMARK) += ipt_IPMARK.o
+ obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+@@ -99,6 +115,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_XOR) += ipt_XOR.o
++obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.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
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c  2004-03-16 12:04:46.000000000 +0000
+@@ -0,0 +1,508 @@
++/* RPC extension for IP (TCP) connection tracking, Version 2.2
++ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
++ *    - original rpc tracking module
++ *    - "recent" connection handling for kernel 2.3+ netfilter
++ *
++ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
++ *    - upgraded conntrack modules to oldnat api - kernel 2.4.0+
++ *
++ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ *    - upgraded conntrack modules to newnat api - kernel 2.4.20+
++ *    - extended matching to support filtering on procedures
++ *
++ * ip_conntrack_rpc_tpc.c,v 2.2 2003/01/12 18:30:00
++ *
++ *    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.
++ **
++ *    Module load syntax:
++ *    insmod ip_conntrack_rpc_tcp.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ *    Please give the ports of all RPC servers you wish to connect to.
++ *    If you don't specify ports, the default will be port 111.
++ **
++ *    Note to all:
++ *
++ *    RPCs should not be exposed to the internet - ask the Pentagon;
++ *
++ *      "The unidentified crackers pleaded guilty in July to charges
++ *       of juvenile delinquency stemming from a string of Pentagon
++ *       network intrusions in February.
++ *
++ *       The youths, going by the names TooShort and Makaveli, used
++ *       a common server security hole to break in, according to
++ *       Dane Jasper, owner of the California Internet service
++ *       provider, Sonic. They used the hole, known as the 'statd'
++ *       exploit, to attempt more than 800 break-ins, Jasper said."
++ *
++ *    From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
++ *    URL:  http://www.wired.com/news/politics/0,1283,16098,00.html
++ **
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <asm/param.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/stddef.h>
++#include <linux/list.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_n_c = 0;
++
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
++#endif
++
++MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
++MODULE_DESCRIPTION("RPC TCP connection tracking module");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \
++                                      format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++DECLARE_RWLOCK(ipct_rpc_tcp_lock);
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock)
++#include <linux/netfilter_ipv4/listhelp.h>
++
++/* For future conections RPC, using client's cache bindings
++ * I'll use ip_conntrack_lock to lock these lists        */
++
++LIST_HEAD(request_p_list_tcp);
++
++
++static void delete_request_p(unsigned long request_p_ul) 
++{
++      struct request_p *p = (void *)request_p_ul;
++      
++      WRITE_LOCK(&ipct_rpc_tcp_lock);
++      LIST_DELETE(&request_p_list_tcp, p);
++      WRITE_UNLOCK(&ipct_rpc_tcp_lock);
++      kfree(p);
++      return;
++}
++
++
++static void req_cl(struct request_p * r)
++{
++      WRITE_LOCK(&ipct_rpc_tcp_lock);
++      del_timer(&r->timeout);
++      LIST_DELETE(&request_p_list_tcp, r);
++      WRITE_UNLOCK(&ipct_rpc_tcp_lock);
++      kfree(r);
++      return;
++}
++
++
++static void clean_request(struct list_head *list)
++{
++      struct list_head *first = list->prev;
++      struct list_head *temp = list->next;
++      struct list_head *aux;
++
++      if (list_empty(list))
++              return;
++
++      while (first != temp) {
++              aux = temp->next;
++              req_cl((struct request_p *)temp);
++              temp = aux;     
++      }
++      req_cl((struct request_p *)temp);
++      return;
++}
++
++
++static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
++                   u_int16_t port)
++{
++      struct request_p *req_p;
++      
++      /* Verifies if entry already exists */
++      WRITE_LOCK(&ipct_rpc_tcp_lock);
++      req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
++              struct request_p *, xid, ip, port);
++
++      if (req_p) {
++              /* Refresh timeout */
++              if (del_timer(&req_p->timeout)) {
++                      req_p->timeout.expires = jiffies + EXP;
++                      add_timer(&req_p->timeout);     
++              } 
++              WRITE_UNLOCK(&ipct_rpc_tcp_lock);
++              return; 
++
++      }
++      WRITE_UNLOCK(&ipct_rpc_tcp_lock);
++      
++      /* Allocate new request_p */
++      req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
++      if (!req_p) {
++              DEBUGP("can't allocate request_p\n");
++              return;                 
++      }
++      *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, 
++              { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p,
++                      NULL }}); 
++      
++      /* Initialize timer */
++      init_timer(&req_p->timeout);
++      req_p->timeout.function = delete_request_p;
++      add_timer(&req_p->timeout); 
++
++      /* Put in list */
++      WRITE_LOCK(&ipct_rpc_tcp_lock);
++      list_prepend(&request_p_list_tcp, req_p);
++      WRITE_UNLOCK(&ipct_rpc_tcp_lock); 
++      return; 
++
++}
++
++
++static int check_rpc_packet(const u_int32_t *data,
++                      int dir, struct ip_conntrack *ct,
++                      struct list_head request_p_list)
++{
++      struct request_p *req_p;
++      u_int32_t xid;
++      struct ip_conntrack_expect expect, *exp = &expect;
++
++        /* Translstion's buffer for XDR */
++        u_int16_t port_buf;
++
++
++      /* Get XID */
++      xid = *data;
++
++      /* This does sanity checking on RPC payloads,
++       * and permits only the RPC "get port" (3)
++       * in authorised procedures in client
++       * communications with the portmapper.
++       */
++
++      /* perform direction dependant RPC work */
++      if (dir == IP_CT_DIR_ORIGINAL) {
++
++              data += 5;
++
++              /* Get RPC requestor */
++              if (IXDR_GET_INT32(data) != 3) {
++                      DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
++                      return NF_ACCEPT;
++              }
++              DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
++
++              data++;
++
++              /* Jump Credentials and Verfifier */
++              data += IXDR_GET_INT32(data) + 2;
++              data += IXDR_GET_INT32(data) + 2;
++
++              /* Get RPC procedure */
++              DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
++                      (unsigned int)IXDR_GET_INT32(data));
++
++              /* Get RPC protocol and store against client parameters */
++              data = data + 2;
++              alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
++                              ct->tuplehash[dir].tuple.src.u.all);
++
++              DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
++                      xid, IXDR_GET_INT32(data),
++                      NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
++                      ntohs(ct->tuplehash[dir].tuple.src.u.all));
++
++              DEBUGP("allocated RPC request for protocol %u. [done]\n",
++                      (unsigned int)IXDR_GET_INT32(data));
++
++      } else {
++
++              /* Check for returning packet's stored counterpart */
++              req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp,
++                                struct request_p *, xid,
++                                ct->tuplehash[!dir].tuple.src.ip,
++                                ct->tuplehash[!dir].tuple.src.u.all);
++
++              /* Drop unexpected packets */
++              if (!req_p) {
++                      DEBUGP("packet is not expected. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Verifies if packet is really an RPC reply packet */
++              data = data++;
++              if (IXDR_GET_INT32(data) != 1) {
++                      DEBUGP("packet is not a valid RPC reply. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Is status accept? */
++              data++;
++              if (IXDR_GET_INT32(data)) {
++                      DEBUGP("packet is not an RPC accept. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Get Verifier length. Jump verifier */
++              data++;
++              data = data + IXDR_GET_INT32(data) + 2;
++
++              /* Is accpet status "success"? */
++              if (IXDR_GET_INT32(data)) {
++                      DEBUGP("packet is not an RPC accept status of success. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Get server port number */      
++              data++;
++              port_buf = (u_int16_t) IXDR_GET_INT32(data);
++
++              /* If a packet has made it this far then it deserves an
++               * expectation ...  if port == 0, then this service is 
++               * not going to be registered.
++               */
++              if (port_buf) {
++                      DEBUGP("port found: %u\n", port_buf);
++
++                      memset(&expect, 0, sizeof(expect));
++
++                      /* Watch out, Radioactive-Man! */
++                      exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++                      exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
++                      exp->mask.src.ip = 0xffffffff;
++                      exp->mask.dst.ip = 0xffffffff;
++
++                      switch (req_p->proto) {
++                              case IPPROTO_UDP:
++                                      exp->tuple.src.u.udp.port = 0;
++                                      exp->tuple.dst.u.udp.port = htons(port_buf);
++                                      exp->tuple.dst.protonum = IPPROTO_UDP;
++                                      exp->mask.src.u.udp.port = 0;
++                                      exp->mask.dst.u.udp.port = htons(0xffff);
++                                      exp->mask.dst.protonum = 0xffff;
++                                      break;
++
++                              case IPPROTO_TCP:
++                                      exp->tuple.src.u.tcp.port = 0;
++                                      exp->tuple.dst.u.tcp.port = htons(port_buf);
++                                      exp->tuple.dst.protonum = IPPROTO_TCP;
++                                      exp->mask.src.u.tcp.port = 0;
++                                      exp->mask.dst.u.tcp.port = htons(0xffff);
++                                      exp->mask.dst.protonum = 0xffff;
++                                      break;
++                      }
++                      exp->expectfn = NULL;
++
++                      ip_conntrack_expect_related(ct, &expect);
++
++                      DEBUGP("expect related ip   %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
++                              NIPQUAD(exp->tuple.src.ip),
++                              NIPQUAD(exp->tuple.dst.ip),
++                              port_buf, req_p->proto);
++
++                      DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
++                              NIPQUAD(exp->mask.src.ip),
++                              NIPQUAD(exp->mask.dst.ip),
++                              exp->mask.dst.protonum);
++
++              }
++
++              req_cl(req_p);
++
++              DEBUGP("packet evaluated. [expect]\n");
++              return NF_ACCEPT;
++      }
++
++      return NF_ACCEPT;
++
++}
++
++
++/* RPC TCP helper */
++static int help(const struct iphdr *iph, size_t len,
++              struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++      struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++      const u_int32_t *data = (const u_int32_t *)tcph + tcph->doff;
++      size_t tcplen = len - iph->ihl * 4;
++
++      int dir = CTINFO2DIR(ctinfo);
++      int crp_ret;
++
++
++      DEBUGP("new packet to evaluate ..\n");
++
++      /* This works for packets like handshake packets, ignore */
++      if (len == ((tcph->doff + iph->ihl) * 4)) {
++              DEBUGP("packet has no data (may still be handshaking). [skip]\n");
++              return NF_ACCEPT;
++      }
++
++      /* Until there's been traffic both ways, don't look in packets. */
++      if (ctinfo != IP_CT_ESTABLISHED
++          && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++              DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
++              DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
++              DEBUGP("packet is not yet part of a two way stream. [skip]\n");
++              return NF_ACCEPT;
++      }
++
++      /* Not whole TCP header? */
++      if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
++              DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen);
++              DEBUGP("packet does not contain a complete TCP header. [skip]\n");
++              return NF_ACCEPT;
++      }
++
++      /* FIXME: Source route IP option packets --RR */
++      if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++                       csum_partial((char *) tcph, tcplen, 0))) {
++              DEBUGP("csum; %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++                   tcph, tcplen, NIPQUAD(iph->saddr),
++                   NIPQUAD(iph->daddr));
++              DEBUGP("[note: failure to get past this error may indicate source routing]\n");
++              DEBUGP("packet contains a bad checksum. [skip]\n");
++              return NF_ACCEPT;
++      }
++
++      /* perform direction dependant protocol work */
++      if (dir == IP_CT_DIR_ORIGINAL) {
++
++              DEBUGP("packet is from the initiator. [cont]\n");
++
++              /* Tests if packet len is ok */
++              if ((tcplen - (tcph->doff * 4)) != 60) {
++                      DEBUGP("packet length is not correct. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++      } else {
++
++              DEBUGP("packet is from the receiver. [cont]\n");
++
++              /* Tests if packet len is ok */
++              if ((tcplen - (tcph->doff * 4)) != 32) {
++                      DEBUGP("packet length is not correct. [skip]\n");
++                      return NF_ACCEPT;
++              }
++      }
++
++      /* Get to the data */
++      data++;
++
++      /* Check the RPC data */
++      crp_ret = check_rpc_packet(data, dir, ct, request_p_list_tcp);
++
++      return crp_ret;
++
++}
++
++
++static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
++
++static void fini(void);
++
++
++static int __init init(void)
++{
++      int port, ret;
++      static char name[10];
++
++
++      /* If no port given, default to standard RPC port */
++      if (ports[0] == 0)
++              ports[0] = RPC_PORT;
++
++      for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
++              memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
++
++                if (ports[port] == RPC_PORT)
++                        sprintf(name, "rpc");
++                else
++                        sprintf(name, "rpc-%d", port);
++
++              rpc_helpers[port].name = name;
++              rpc_helpers[port].me = THIS_MODULE;
++              rpc_helpers[port].max_expected = 1;
++              rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++              rpc_helpers[port].timeout = 0;
++
++              rpc_helpers[port].tuple.dst.protonum = IPPROTO_TCP;
++              rpc_helpers[port].mask.dst.protonum = 0xffff;
++
++              /* RPC can come from ports 0:65535 to ports[port] (111) */
++              rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]);
++              rpc_helpers[port].mask.src.u.udp.port = htons(0xffff);
++              rpc_helpers[port].mask.dst.u.udp.port = htons(0x0);
++
++              rpc_helpers[port].help = help;
++
++              DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]);
++              DEBUGP("helper match ip   %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++                      NIPQUAD(rpc_helpers[port].tuple.dst.ip),
++                      ntohs(rpc_helpers[port].tuple.dst.u.tcp.port),
++                      NIPQUAD(rpc_helpers[port].tuple.src.ip),
++                      ntohs(rpc_helpers[port].tuple.src.u.tcp.port));
++              DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++                      NIPQUAD(rpc_helpers[port].mask.dst.ip),
++                      ntohs(rpc_helpers[port].mask.dst.u.tcp.port),
++                      NIPQUAD(rpc_helpers[port].mask.src.ip),
++                      ntohs(rpc_helpers[port].mask.src.u.tcp.port));
++
++              ret = ip_conntrack_helper_register(&rpc_helpers[port]);
++
++              if (ret) {
++                      printk("ERROR registering port %d\n",
++                              ports[port]);
++                      fini();
++                      return -EBUSY;
++              }
++              ports_n_c++;
++      }
++      return 0;
++}
++
++
++/* This function is intentionally _NOT_ defined as __exit, because 
++ * it is needed by the init function */
++static void fini(void)
++{
++      int port;
++
++      DEBUGP("cleaning request list\n");
++      clean_request(&request_p_list_tcp);
++
++      for (port = 0; (port < ports_n_c) && ports[port]; port++) {
++              DEBUGP("unregistering port %d\n", ports[port]);
++              ip_conntrack_helper_unregister(&rpc_helpers[port]);
++      }
++}
++
++
++module_init(init);
++module_exit(fini);
++
++struct module *ip_conntrack_rpc_tcp = THIS_MODULE;
++EXPORT_SYMBOL(request_p_list_tcp);
++EXPORT_SYMBOL(ip_conntrack_rpc_tcp);
++EXPORT_SYMBOL(ipct_rpc_tcp_lock);
++
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_udp.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_udp.c  2004-03-16 12:04:46.000000000 +0000
+@@ -0,0 +1,503 @@
++/* RPC extension for IP (UDP) connection tracking, Version 2.2
++ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
++ *    - original rpc tracking module
++ *    - "recent" connection handling for kernel 2.3+ netfilter
++ *
++ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
++ *    - upgraded conntrack modules to oldnat api - kernel 2.4.0+
++ *
++ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ *    - upgraded conntrack modules to newnat api - kernel 2.4.20+
++ *    - extended matching to support filtering on procedures
++ *
++ * ip_conntrack_rpc_udp.c,v 2.2 2003/01/12 18:30:00
++ *
++ *    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.
++ **
++ *    Module load syntax:
++ *    insmod ip_conntrack_rpc_udp.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ *    Please give the ports of all RPC servers you wish to connect to.
++ *    If you don't specify ports, the default will be port 111.
++ **
++ *    Note to all:
++ *
++ *    RPCs should not be exposed to the internet - ask the Pentagon;
++ *
++ *      "The unidentified crackers pleaded guilty in July to charges
++ *       of juvenile delinquency stemming from a string of Pentagon
++ *       network intrusions in February.
++ *
++ *       The youths, going by the names TooShort and Makaveli, used
++ *       a common server security hole to break in, according to
++ *       Dane Jasper, owner of the California Internet service
++ *       provider, Sonic. They used the hole, known as the 'statd'
++ *       exploit, to attempt more than 800 break-ins, Jasper said."
++ *
++ *    From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
++ *    URL:  http://www.wired.com/news/politics/0,1283,16098,00.html
++ **
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/udp.h>
++
++#include <asm/param.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/stddef.h>
++#include <linux/list.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_n_c = 0;
++
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
++#endif
++
++MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
++MODULE_DESCRIPTION("RPC UDP connection tracking module");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \
++                                      format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++DECLARE_RWLOCK(ipct_rpc_udp_lock);
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock)
++#include <linux/netfilter_ipv4/listhelp.h>
++
++/* For future conections RPC, using client's cache bindings
++ * I'll use ip_conntrack_lock to lock these lists           */
++
++LIST_HEAD(request_p_list_udp);
++
++
++static void delete_request_p(unsigned long request_p_ul)
++{
++      struct request_p *p = (void *)request_p_ul;
++      
++      WRITE_LOCK(&ipct_rpc_udp_lock);
++      LIST_DELETE(&request_p_list_udp, p);
++      WRITE_UNLOCK(&ipct_rpc_udp_lock);
++      kfree(p);
++      return;
++}
++
++
++static void req_cl(struct request_p * r)
++{
++      WRITE_LOCK(&ipct_rpc_udp_lock);
++      del_timer(&r->timeout);
++      LIST_DELETE(&request_p_list_udp, r);
++      WRITE_UNLOCK(&ipct_rpc_udp_lock);
++      kfree(r);
++      return;
++}
++
++
++static void clean_request(struct list_head *list)
++{
++      struct list_head *first = list->prev;
++      struct list_head *temp = list->next;
++      struct list_head *aux;
++
++      if (list_empty(list))
++              return;
++
++      while (first != temp) {
++              aux = temp->next;
++              req_cl((struct request_p *)temp);
++              temp = aux;     
++      }
++      req_cl((struct request_p *)temp);
++      return;
++}
++
++
++static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip,
++                   u_int16_t port)
++{
++      struct request_p *req_p;
++        
++      /* Verifies if entry already exists */
++      WRITE_LOCK(&ipct_rpc_udp_lock);
++      req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
++              struct request_p *, xid, ip, port);
++
++      if (req_p) {
++              /* Refresh timeout */
++              if (del_timer(&req_p->timeout)) {
++                      req_p->timeout.expires = jiffies + EXP;
++                      add_timer(&req_p->timeout);     
++              } 
++              WRITE_UNLOCK(&ipct_rpc_udp_lock);
++              return; 
++
++      }
++      WRITE_UNLOCK(&ipct_rpc_udp_lock);
++      
++      /* Allocate new request_p */
++      req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC);
++      if (!req_p) {
++              DEBUGP("can't allocate request_p\n");
++              return;                 
++      }
++      *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, 
++              { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p,
++                      NULL }}); 
++      
++      /* Initialize timer */
++      init_timer(&req_p->timeout);
++      req_p->timeout.function = delete_request_p;
++      add_timer(&req_p->timeout); 
++
++      /* Put in list */
++      WRITE_LOCK(&ipct_rpc_udp_lock);
++      list_prepend(&request_p_list_udp, req_p);
++      WRITE_UNLOCK(&ipct_rpc_udp_lock); 
++      return; 
++
++}
++
++
++static int check_rpc_packet(const u_int32_t *data,
++                      int dir, struct ip_conntrack *ct,
++                      struct list_head request_p_list)
++{
++      struct request_p *req_p;
++      u_int32_t xid;
++      struct ip_conntrack_expect expect, *exp = &expect;
++
++      /* Translstion's buffer for XDR */
++      u_int16_t port_buf;
++
++
++      /* Get XID */
++      xid = *data;
++
++      /* This does sanity checking on RPC payloads,
++       * and permits only the RPC "get port" (3)
++       * in authorised procedures in client
++       * communications with the portmapper.
++       */
++
++      /* perform direction dependant RPC work */
++      if (dir == IP_CT_DIR_ORIGINAL) {
++
++              data += 5;
++
++              /* Get RPC requestor */
++              if (IXDR_GET_INT32(data) != 3) {
++                      DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
++                      return NF_ACCEPT;
++              }
++              DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
++
++              data++;
++
++              /* Jump Credentials and Verfifier */
++              data = data + IXDR_GET_INT32(data) + 2;
++              data = data + IXDR_GET_INT32(data) + 2;
++
++              /* Get RPC procedure */
++              DEBUGP("RPC packet contains procedure request [%u]. [cont]\n",
++                      (unsigned int)IXDR_GET_INT32(data));
++
++              /* Get RPC protocol and store against client parameters */
++              data = data + 2;
++              alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip,
++                              ct->tuplehash[dir].tuple.src.u.all);
++
++              DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
++                      xid, IXDR_GET_INT32(data),
++                      NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
++                      ntohs(ct->tuplehash[dir].tuple.src.u.all));
++
++              DEBUGP("allocated RPC request for protocol %u. [done]\n",
++                      (unsigned int)IXDR_GET_INT32(data));
++
++      } else {
++
++              /* Check for returning packet's stored counterpart */
++              req_p = LIST_FIND(&request_p_list_udp, request_p_cmp,
++                                struct request_p *, xid,
++                                ct->tuplehash[!dir].tuple.src.ip,
++                                ct->tuplehash[!dir].tuple.src.u.all);
++
++              /* Drop unexpected packets */
++              if (!req_p) {
++                      DEBUGP("packet is not expected. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Verifies if packet is really an RPC reply packet */
++              data = data++;
++              if (IXDR_GET_INT32(data) != 1) {
++                      DEBUGP("packet is not a valid RPC reply. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Is status accept? */
++              data++;
++              if (IXDR_GET_INT32(data)) {
++                      DEBUGP("packet is not an RPC accept. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Get Verifier length. Jump verifier */
++              data++;
++              data = data + IXDR_GET_INT32(data) + 2;
++
++              /* Is accpet status "success"? */
++              if (IXDR_GET_INT32(data)) {
++                      DEBUGP("packet is not an RPC accept status of success. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Get server port number */      
++              data++;
++              port_buf = (u_int16_t) IXDR_GET_INT32(data);
++
++              /* If a packet has made it this far then it deserves an
++               * expectation ...  if port == 0, then this service is 
++               * not going to be registered.
++               */
++              if (port_buf) {
++                      DEBUGP("port found: %u\n", port_buf);
++
++                      memset(&expect, 0, sizeof(expect));
++
++                      /* Watch out, Radioactive-Man! */
++                      exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++                      exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
++                      exp->mask.src.ip = 0xffffffff;
++                      exp->mask.dst.ip = 0xffffffff;
++
++                      switch (req_p->proto) {
++                              case IPPROTO_UDP:
++                                      exp->tuple.src.u.udp.port = 0;
++                                      exp->tuple.dst.u.udp.port = htons(port_buf);
++                                      exp->tuple.dst.protonum = IPPROTO_UDP;
++                                      exp->mask.src.u.udp.port = 0;
++                                      exp->mask.dst.u.udp.port = htons(0xffff);
++                                      exp->mask.dst.protonum = 0xffff;
++                                      break;
++
++                              case IPPROTO_TCP:
++                                      exp->tuple.src.u.tcp.port = 0;
++                                      exp->tuple.dst.u.tcp.port = htons(port_buf);
++                                      exp->tuple.dst.protonum = IPPROTO_TCP;
++                                      exp->mask.src.u.tcp.port = 0;
++                                      exp->mask.dst.u.tcp.port = htons(0xffff);
++                                      exp->mask.dst.protonum = 0xffff;
++                                      break;
++                      }
++                      exp->expectfn = NULL;
++
++                      ip_conntrack_expect_related(ct, &expect);
++
++                      DEBUGP("expect related ip   %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n",
++                              NIPQUAD(exp->tuple.src.ip),
++                              NIPQUAD(exp->tuple.dst.ip),
++                              port_buf, req_p->proto);
++
++                      DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n",
++                              NIPQUAD(exp->mask.src.ip),
++                              NIPQUAD(exp->mask.dst.ip),
++                              exp->mask.dst.protonum);
++
++              }
++
++              req_cl(req_p);
++
++              DEBUGP("packet evaluated. [expect]\n");
++              return NF_ACCEPT;
++      }
++
++      return NF_ACCEPT;
++
++}
++
++
++/* RPC UDP helper */
++static int help(const struct iphdr *iph, size_t len,
++              struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++      struct udphdr *udph = (void *) iph + iph->ihl * 4;
++      const u_int32_t *data = (const u_int32_t *)udph + 2;
++      size_t udplen = len - iph->ihl * 4;
++      int dir = CTINFO2DIR(ctinfo);
++      int crp_ret;
++
++      /* Checksum */
++      const u_int16_t *chsm = (const u_int16_t *)udph + 3;
++
++
++      DEBUGP("new packet to evaluate ..\n");
++
++      /* Not whole UDP header? */
++      if (udplen < sizeof(struct udphdr)) {
++              DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen);
++              DEBUGP("packet does not contain a complete UDP header. [skip]\n");
++              return NF_ACCEPT;
++      }
++
++      /* FIXME: Source route IP option packets --RR */
++      if (*chsm) {
++              if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
++                  csum_partial((char *)udph, udplen, 0))) {
++                      DEBUGP("[note: failure to get past this error may indicate source routing]\n");
++                      DEBUGP("packet contains a bad checksum. [skip]\n");
++                      return NF_ACCEPT;
++                 } 
++      }
++
++      /* perform direction dependant protocol work */
++      if (dir == IP_CT_DIR_ORIGINAL) {
++
++              DEBUGP("packet is from the initiator. [cont]\n");
++
++              /* Tests if packet len is ok */
++              if ((udplen - sizeof(struct udphdr)) != 56) {
++                      DEBUGP("packet length is not correct. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++      } else {
++
++              DEBUGP("packet is from the receiver. [cont]\n");
++
++              /* Until there's been traffic both ways, don't look in packets. */
++              if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++                      DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo);
++                      DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n");
++                      DEBUGP("packet is not yet part of a two way stream. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++              /* Tests if packet len is ok */
++                      if ((udplen - sizeof(struct udphdr)) != 28) {
++                      DEBUGP("packet length is not correct. [skip]\n");
++                      return NF_ACCEPT;
++              }
++
++      }
++
++      /* Get to the data */
++      /* udp *data == *correct */
++
++      /* Check the RPC data */
++      crp_ret = check_rpc_packet(data, dir, ct, request_p_list_udp);
++
++      return crp_ret;
++
++}
++
++
++static struct ip_conntrack_helper rpc_helpers[MAX_PORTS];
++
++static void fini(void);
++
++
++static int __init init(void)
++{
++      int port, ret;
++      static char name[10];
++
++
++      /* If no port given, default to standard RPC port */
++      if (ports[0] == 0)
++              ports[0] = RPC_PORT;
++
++      for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
++              memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper));
++
++                if (ports[port] == RPC_PORT)
++                        sprintf(name, "rpc");
++                else
++                        sprintf(name, "rpc-%d", port);
++
++              rpc_helpers[port].name = name;
++              rpc_helpers[port].me = THIS_MODULE;
++              rpc_helpers[port].max_expected = 1;
++              rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++              rpc_helpers[port].timeout = 0;
++
++              rpc_helpers[port].tuple.dst.protonum = IPPROTO_UDP;
++              rpc_helpers[port].mask.dst.protonum = 0xffff;
++
++              /* RPC can come from ports 0:65535 to ports[port] (111) */
++              rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]);
++              rpc_helpers[port].mask.src.u.udp.port = htons(0xffff);
++              rpc_helpers[port].mask.dst.u.udp.port = htons(0x0);
++
++              rpc_helpers[port].help = help;
++
++              DEBUGP("registering helper for port #%d: %d/UDP\n", port, ports[port]);
++              DEBUGP("helper match ip   %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++                      NIPQUAD(rpc_helpers[port].tuple.dst.ip),
++                      ntohs(rpc_helpers[port].tuple.dst.u.udp.port),
++                      NIPQUAD(rpc_helpers[port].tuple.src.ip),
++                      ntohs(rpc_helpers[port].tuple.src.u.udp.port));
++              DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++                      NIPQUAD(rpc_helpers[port].mask.dst.ip),
++                      ntohs(rpc_helpers[port].mask.dst.u.udp.port),
++                      NIPQUAD(rpc_helpers[port].mask.src.ip),
++                      ntohs(rpc_helpers[port].mask.src.u.udp.port));
++
++              ret = ip_conntrack_helper_register(&rpc_helpers[port]);
++
++              if (ret) {
++                      printk("ERROR registering port %d\n",
++                              ports[port]);
++                      fini();
++                      return -EBUSY;
++              }
++              ports_n_c++;
++      }
++      return 0;
++}
++
++
++/* This function is intentionally _NOT_ defined as __exit, because 
++ * it is needed by the init function */
++static void fini(void)
++{
++      int port;
++
++      DEBUGP("cleaning request list\n");
++      clean_request(&request_p_list_udp);
++
++      for (port = 0; (port < ports_n_c) && ports[port]; port++) {
++              DEBUGP("unregistering port %d\n", ports[port]);
++              ip_conntrack_helper_unregister(&rpc_helpers[port]);
++      }
++}
++
++
++module_init(init);
++module_exit(fini);
++
++struct module *ip_conntrack_rpc_udp = THIS_MODULE;
++EXPORT_SYMBOL(request_p_list_udp);
++EXPORT_SYMBOL(ip_conntrack_rpc_udp);
++EXPORT_SYMBOL(ipct_rpc_udp_lock);
++
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rtsp.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rtsp.c     2004-03-16 12:04:49.000000000 +0000
+@@ -0,0 +1,509 @@
++/*
++ * RTSP extension for IP connection tracking
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.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.
++ *
++ * Module load syntax:
++ *   insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *                              max_outstanding=n setup_timeout=secs
++ *
++ * If no ports are specified, the default will be port 554.
++ *
++ * With max_outstanding you can define the maximum number of not yet
++ * answered SETUP requests per RTSP session (default 8).
++ * With setup_timeout you can specify how long the system waits for
++ * an expected data channel (default 300 seconds).
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#define NF_NEED_STRTOU32
++#define NF_NEED_NEXTLINE
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
++
++#define INFOP(args...) printk(KERN_INFO __FILE__ ":" __FUNCTION__ ":" args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ ":" args)
++#else
++#define DEBUGP(args...)
++#endif
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int num_ports = 0;
++static int max_outstanding = 8;
++static unsigned int setup_timeout = 300;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(max_outstanding, "i");
++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
++MODULE_PARM(setup_timeout, "i");
++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
++#endif
++
++DECLARE_LOCK(ip_rtsp_lock);
++struct module* ip_conntrack_rtsp = THIS_MODULE;
++
++/*
++ * Max mappings we will allow for one RTSP connection (for RTP, the number
++ * of allocated ports is twice this value).  Note that SMIL burns a lot of
++ * ports so keep this reasonably high.  If this is too low, you will see a
++ * lot of "no free client map entries" messages.
++ */
++#define MAX_PORT_MAPS 16
++
++/*** default port list was here in the masq code: 554, 3030, 4040 ***/
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*
++ * Parse an RTSP packet.
++ *
++ * Returns zero if parsing failed.
++ *
++ * Parameters:
++ *  IN      ptcp        tcp data pointer
++ *  IN      tcplen      tcp data len
++ *  IN/OUT  ptcpoff     points to current tcp offset
++ *  OUT     phdrsoff    set to offset of rtsp headers
++ *  OUT     phdrslen    set to length of rtsp headers
++ *  OUT     pcseqoff    set to offset of CSeq header
++ *  OUT     pcseqlen    set to length of CSeq header
++ */
++static int
++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
++                   uint* phdrsoff, uint* phdrslen,
++                   uint* pcseqoff, uint* pcseqlen)
++{
++    uint    entitylen = 0;
++    uint    lineoff;
++    uint    linelen;
++
++    if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++    {
++        return 0;
++    }
++
++    *phdrsoff = *ptcpoff;
++    while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++    {
++        if (linelen == 0)
++        {
++            if (entitylen > 0)
++            {
++                *ptcpoff += min(entitylen, tcplen - *ptcpoff);
++            }
++            break;
++        }
++        if (lineoff+linelen > tcplen)
++        {
++            INFOP("!! overrun !!\n");
++            break;
++        }
++
++        if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
++        {
++            *pcseqoff = lineoff;
++            *pcseqlen = linelen;
++        }
++        if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
++        {
++            uint off = lineoff+15;
++            SKIP_WSPACE(ptcp+lineoff, linelen, off);
++            nf_strtou32(ptcp+off, &entitylen);
++        }
++    }
++    *phdrslen = (*ptcpoff) - (*phdrsoff);
++
++    return 1;
++}
++
++/*
++ * Find lo/hi client ports (if any) in transport header
++ * In:
++ *   ptcp, tcplen = packet
++ *   tranoff, tranlen = buffer to search
++ *
++ * Out:
++ *   pport_lo, pport_hi = lo/hi ports (host endian)
++ *
++ * Returns nonzero if any client ports found
++ *
++ * Note: it is valid (and expected) for the client to request multiple
++ * transports, so we need to parse the entire line.
++ */
++static int
++rtsp_parse_transport(char* ptran, uint tranlen,
++                     struct ip_ct_rtsp_expect* prtspexp)
++{
++    int     rc = 0;
++    uint    off = 0;
++
++    if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++        nf_strncasecmp(ptran, "Transport:", 10) != 0)
++    {
++        INFOP("sanity check failed\n");
++        return 0;
++    }
++    DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
++    off += 10;
++    SKIP_WSPACE(ptran, tranlen, off);
++
++    /* Transport: tran;field;field=val,tran;field;field=val,... */
++    while (off < tranlen)
++    {
++        const char* pparamend;
++        uint        nextparamoff;
++
++        pparamend = memchr(ptran+off, ',', tranlen-off);
++        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++        nextparamoff = pparamend-ptran;
++
++        while (off < nextparamoff)
++        {
++            const char* pfieldend;
++            uint        nextfieldoff;
++
++            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++            if (strncmp(ptran+off, "client_port=", 12) == 0)
++            {
++                u_int16_t   port;
++                uint        numlen;
++
++                off += 12;
++                numlen = nf_strtou16(ptran+off, &port);
++                off += numlen;
++                if (prtspexp->loport != 0 && prtspexp->loport != port)
++                {
++                    DEBUGP("multiple ports found, port %hu ignored\n", port);
++                }
++                else
++                {
++                    prtspexp->loport = prtspexp->hiport = port;
++                    if (ptran[off] == '-')
++                    {
++                        off++;
++                        numlen = nf_strtou16(ptran+off, &port);
++                        off += numlen;
++                        prtspexp->pbtype = pb_range;
++                        prtspexp->hiport = port;
++
++                        // If we have a range, assume rtp:
++                        // loport must be even, hiport must be loport+1
++                        if ((prtspexp->loport & 0x0001) != 0 ||
++                            prtspexp->hiport != prtspexp->loport+1)
++                        {
++                            DEBUGP("incorrect range: %hu-%hu, correcting\n",
++                                   prtspexp->loport, prtspexp->hiport);
++                            prtspexp->loport &= 0xfffe;
++                            prtspexp->hiport = prtspexp->loport+1;
++                        }
++                    }
++                    else if (ptran[off] == '/')
++                    {
++                        off++;
++                        numlen = nf_strtou16(ptran+off, &port);
++                        off += numlen;
++                        prtspexp->pbtype = pb_discon;
++                        prtspexp->hiport = port;
++                    }
++                    rc = 1;
++                }
++            }
++
++            /*
++             * Note we don't look for the destination parameter here.
++             * If we are using NAT, the NAT module will handle it.  If not,
++             * and the client is sending packets elsewhere, the expectation
++             * will quietly time out.
++             */
++
++            off = nextfieldoff;
++        }
++
++        off = nextparamoff;
++    }
++
++    return rc;
++}
++
++/*** conntrack functions ***/
++
++/* outbound packet: client->server */
++static int
++help_out(const struct iphdr* iph, size_t pktlen,
++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++    int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
++    struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
++    uint    tcplen = pktlen - iph->ihl * 4;
++    char*   pdata = (char*)tcph + tcph->doff * 4;
++    uint    datalen = tcplen - tcph->doff * 4;
++    uint    dataoff = 0;
++
++    struct ip_conntrack_expect exp;
++
++    while (dataoff < datalen)
++    {
++        uint    cmdoff = dataoff;
++        uint    hdrsoff = 0;
++        uint    hdrslen = 0;
++        uint    cseqoff = 0;
++        uint    cseqlen = 0;
++        uint    lineoff = 0;
++        uint    linelen = 0;
++        uint    off;
++        int     rc;
++
++        if (!rtsp_parse_message(pdata, datalen, &dataoff,
++                                &hdrsoff, &hdrslen,
++                                &cseqoff, &cseqlen))
++        {
++            break;      /* not a valid message */
++        }
++
++        if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
++        {
++            continue;   /* not a SETUP message */
++        }
++        DEBUGP("found a setup message\n");
++
++        memset(&exp, 0, sizeof(exp));
++
++        off = 0;
++        while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
++                                &lineoff, &linelen))
++        {
++            if (linelen == 0)
++            {
++                break;
++            }
++            if (off > hdrsoff+hdrslen)
++            {
++                INFOP("!! overrun !!");
++                break;
++            }
++
++            if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
++            {
++                rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
++                                     &exp.help.exp_rtsp_info);
++            }
++        }
++
++        if (exp.help.exp_rtsp_info.loport == 0)
++        {
++            DEBUGP("no udp transports found\n");
++            continue;   /* no udp transports found */
++        }
++
++        DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
++              (int)exp.help.exp_rtsp_info.pbtype,
++              exp.help.exp_rtsp_info.loport,
++              exp.help.exp_rtsp_info.hiport);
++
++        LOCK_BH(&ip_rtsp_lock);
++        exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
++        exp.help.exp_rtsp_info.len = hdrslen;
++
++        exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++        exp.mask.src.ip  = 0xffffffff;
++        exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip;
++        exp.mask.dst.ip  = 0xffffffff;
++        exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport;
++        exp.mask.dst.u.udp.port  = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
++        exp.tuple.dst.protonum = IPPROTO_UDP;
++        exp.mask.dst.protonum  = 0xffff;
++
++        DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++                NIPQUAD(exp.tuple.src.ip),
++                ntohs(exp.tuple.src.u.tcp.port),
++                NIPQUAD(exp.tuple.dst.ip),
++                ntohs(exp.tuple.dst.u.tcp.port));
++
++        /* pass the request off to the nat helper */
++        rc = ip_conntrack_expect_related(ct, &exp);
++        UNLOCK_BH(&ip_rtsp_lock);
++        if (rc == 0)
++        {
++            DEBUGP("ip_conntrack_expect_related succeeded\n");
++        }
++        else
++        {
++            INFOP("ip_conntrack_expect_related failed (%d)\n", rc);
++        }
++    }
++
++    return NF_ACCEPT;
++}
++
++/* inbound packet: server->client */
++static int
++help_in(const struct iphdr* iph, size_t pktlen,
++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++    return NF_ACCEPT;
++}
++
++static int
++help(const struct iphdr* iph, size_t pktlen,
++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++    /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
++    struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
++    u_int32_t tcplen = pktlen - iph->ihl * 4;
++
++    /* Until there's been traffic both ways, don't look in packets. */
++    if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
++    {
++        DEBUGP("conntrackinfo = %u\n", ctinfo);
++        return NF_ACCEPT;
++    }
++
++    /* Not whole TCP header? */
++    if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4)
++    {
++        DEBUGP("tcplen = %u\n", (unsigned)tcplen);
++        return NF_ACCEPT;
++    }
++
++    /* Checksum invalid?  Ignore. */
++    /* FIXME: Source route IP option packets --RR */
++    if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++                     csum_partial((char*)tcph, tcplen, 0)))
++    {
++        DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++               tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++        return NF_ACCEPT;
++    }
++
++    switch (CTINFO2DIR(ctinfo))
++    {
++    case IP_CT_DIR_ORIGINAL:
++        help_out(iph, pktlen, ct, ctinfo);
++        break;
++    case IP_CT_DIR_REPLY:
++        help_in(iph, pktlen, ct, ctinfo);
++        break;
++    default:
++        /* oops */
++    }
++
++    return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++    int i;
++    for (i = 0; i < num_ports; i++)
++    {
++        DEBUGP("unregistering port %d\n", ports[i]);
++        ip_conntrack_helper_unregister(&rtsp_helpers[i]);
++    }
++}
++
++static int __init
++init(void)
++{
++    int i, ret;
++    struct ip_conntrack_helper *hlpr;
++    char *tmpname;
++
++    printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++    if (max_outstanding < 1)
++    {
++        printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
++        return -EBUSY;
++    }
++    if (setup_timeout < 0)
++    {
++        printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
++        return -EBUSY;
++    }
++
++    /* If no port given, default to standard rtsp port */
++    if (ports[0] == 0)
++    {
++        ports[0] = RTSP_PORT;
++    }
++
++    for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
++    {
++        hlpr = &rtsp_helpers[i];
++        memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
++        hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++        hlpr->tuple.dst.protonum = IPPROTO_TCP;
++        hlpr->mask.src.u.tcp.port = 0xFFFF;
++        hlpr->mask.dst.protonum = 0xFFFF;
++        hlpr->max_expected = max_outstanding;
++        hlpr->timeout = setup_timeout;
++        hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
++        hlpr->me = ip_conntrack_rtsp;
++        hlpr->help = help;
++
++        tmpname = &rtsp_names[i][0];
++        if (ports[i] == RTSP_PORT)
++        {
++            sprintf(tmpname, "rtsp");
++        }
++        else
++        {
++            sprintf(tmpname, "rtsp-%d", i);
++        }
++        hlpr->name = tmpname;
++
++        DEBUGP("port #%d: %d\n", i, ports[i]);
++
++        ret = ip_conntrack_helper_register(hlpr);
++
++        if (ret)
++        {
++            printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
++            fini();
++            return -EBUSY;
++        }
++        num_ports++;
++    }
++    return 0;
++}
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++EXPORT_SYMBOL(ip_rtsp_lock);
++#endif
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c   2004-03-16 12:00:23.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c       2004-03-16 12:04:09.000000000 +0000
+@@ -110,6 +110,9 @@
+               len += sprintf(buffer + len, "[ASSURED] ");
+       len += sprintf(buffer + len, "use=%u ",
+                      atomic_read(&conntrack->ct_general.use));
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++      len += sprintf(buffer + len, "mark=%ld ", conntrack->mark);
++#endif
+       len += sprintf(buffer + len, "\n");
+       return len;
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_rtsp.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_rtsp.c       1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_rtsp.c   2004-03-16 12:04:49.000000000 +0000
+@@ -0,0 +1,625 @@
++/*
++ * RTSP extension for TCP NAT alteration
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_nat_irc.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.
++ *
++ * Module load syntax:
++ *      insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ *                           stunaddr=<address>
++ *                           destaction=[auto|strip|none]
++ *
++ * If no ports are specified, the default will be port 554 only.
++ *
++ * stunaddr specifies the address used to detect that a client is using STUN.
++ * If this address is seen in the destination parameter, it is assumed that
++ * the client has already punched a UDP hole in the firewall, so we don't
++ * mangle the client_port.  If none is specified, it is autodetected.  It
++ * only needs to be set if you have multiple levels of NAT.  It should be
++ * set to the external address that the STUN clients detect.  Note that in
++ * this case, it will not be possible for clients to use UDP with servers
++ * between the NATs.
++ *
++ * If no destaction is specified, auto is used.
++ *   destaction=auto:  strip destination parameter if it is not stunaddr.
++ *   destaction=strip: always strip destination parameter (not recommended).
++ *   destaction=none:  do not touch destination parameter (not recommended).
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/kernel.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#include <linux/inet.h>
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define INFOP(args...) printk(KERN_INFO __FILE__ ":" __FUNCTION__ ":" args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ ":" args);
++#else
++#define DEBUGP(args...)
++#endif
++
++#define MAX_PORTS       8
++#define DSTACT_AUTO     0
++#define DSTACT_STRIP    1
++#define DSTACT_NONE     2
++
++static int      ports[MAX_PORTS];
++static char*    stunaddr = NULL;
++static char*    destaction = NULL;
++
++static int       num_ports = 0;
++static u_int32_t extip = 0;
++static int       dstact = 0;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP network address translation module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(stunaddr, "s");
++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
++MODULE_PARM(destaction, "s");
++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
++#endif
++
++/* protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*** helper functions ***/
++
++static void
++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
++{
++    struct iphdr*   iph  = (struct iphdr*)skb->nh.iph;
++    struct tcphdr*  tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
++
++    *pptcpdata = (char*)tcph + tcph->doff*4;
++    *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
++}
++
++/*** nat functions ***/
++
++/*
++ * Mangle the "Transport:" header:
++ *   - Replace all occurences of "client_port=<spec>"
++ *   - Handle destination parameter
++ *
++ * In:
++ *   ct, ctinfo = conntrack context
++ *   pskb       = packet
++ *   tranoff    = Transport header offset from TCP data
++ *   tranlen    = Transport header length (incl. CRLF)
++ *   rport_lo   = replacement low  port (host endian)
++ *   rport_hi   = replacement high port (host endian)
++ *
++ * Returns packet size difference.
++ *
++ * Assumes that a complete transport header is present, ending with CR or LF
++ */
++static int
++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++                 struct ip_conntrack_expect* exp,
++                 struct sk_buff** pskb, uint tranoff, uint tranlen)
++{
++    char*       ptcp;
++    uint        tcplen;
++    char*       ptran;
++    char        rbuf1[16];      /* Replacement buffer (one port) */
++    uint        rbuf1len;       /* Replacement len (one port) */
++    char        rbufa[16];      /* Replacement buffer (all ports) */
++    uint        rbufalen;       /* Replacement len (all ports) */
++    u_int32_t   newip;
++    u_int16_t   loport, hiport;
++    uint        off = 0;
++    uint        diff;           /* Number of bytes we removed */
++
++    struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++    struct ip_conntrack_tuple t;
++
++    char    szextaddr[15+1];
++    uint    extaddrlen;
++    int     is_stun;
++
++    get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++    ptran = ptcp+tranoff;
++
++    if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++        tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++        nf_strncasecmp(ptran, "Transport:", 10) != 0)
++    {
++        INFOP("sanity check failed\n");
++        return 0;
++    }
++    off += 10;
++    SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++    t = exp->tuple;
++    t.dst.ip = newip;
++
++    extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
++                       : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
++    DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++
++    rbuf1len = rbufalen = 0;
++    switch (prtspexp->pbtype)
++    {
++    case pb_single:
++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++        {
++            t.dst.u.udp.port = htons(loport);
++            if (ip_conntrack_change_expect(exp, &t) == 0)
++            {
++                DEBUGP("using port %hu\n", loport);
++                break;
++            }
++        }
++        if (loport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            rbufalen = sprintf(rbufa, "%hu", loport);
++        }
++        break;
++    case pb_range:
++        for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
++        {
++            t.dst.u.udp.port = htons(loport);
++            if (ip_conntrack_change_expect(exp, &t) == 0)
++            {
++                hiport = loport + ~exp->mask.dst.u.udp.port;
++                DEBUGP("using ports %hu-%hu\n", loport, hiport);
++                break;
++            }
++        }
++        if (loport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
++        }
++        break;
++    case pb_discon:
++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++        {
++            t.dst.u.udp.port = htons(loport);
++            if (ip_conntrack_change_expect(exp, &t) == 0)
++            {
++                DEBUGP("using port %hu (1 of 2)\n", loport);
++                break;
++            }
++        }
++        for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
++        {
++            t.dst.u.udp.port = htons(hiport);
++            if (ip_conntrack_change_expect(exp, &t) == 0)
++            {
++                DEBUGP("using port %hu (2 of 2)\n", hiport);
++                break;
++            }
++        }
++        if (loport != 0 && hiport != 0)
++        {
++            rbuf1len = sprintf(rbuf1, "%hu", loport);
++            if (hiport == loport+1)
++            {
++                rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++            }
++            else
++            {
++                rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
++            }
++        }
++        break;
++    default:
++        /* oops */
++    }
++
++    if (rbuf1len == 0)
++    {
++        return 0;   /* cannot get replacement port(s) */
++    }
++
++    /* Transport: tran;field;field=val,tran;field;field=val,... */
++    while (off < tranlen)
++    {
++        uint        saveoff;
++        const char* pparamend;
++        uint        nextparamoff;
++
++        pparamend = memchr(ptran+off, ',', tranlen-off);
++        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++        nextparamoff = pparamend-ptcp;
++
++        /*
++         * We pass over each param twice.  On the first pass, we look for a
++         * destination= field.  It is handled by the security policy.  If it
++         * is present, allowed, and equal to our external address, we assume
++         * that STUN is being used and we leave the client_port= field alone.
++         */
++        is_stun = 0;
++        saveoff = off;
++        while (off < nextparamoff)
++        {
++            const char* pfieldend;
++            uint        nextfieldoff;
++
++            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++            if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
++            {
++                if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
++                {
++                    is_stun = 1;
++                }
++                if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
++                {
++                    diff = nextfieldoff-off;
++                    if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++                                                         off, diff, NULL, 0))
++                    {
++                        /* mangle failed, all we can do is bail */
++                        return 0;
++                    }
++                    get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++                    ptran = ptcp+tranoff;
++                    tranlen -= diff;
++                    nextparamoff -= diff;
++                    nextfieldoff -= diff;
++                }
++            }
++
++            off = nextfieldoff;
++        }
++        if (is_stun)
++        {
++            continue;
++        }
++        off = saveoff;
++        while (off < nextparamoff)
++        {
++            const char* pfieldend;
++            uint        nextfieldoff;
++
++            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++            if (strncmp(ptran+off, "client_port=", 12) == 0)
++            {
++                u_int16_t   port;
++                uint        numlen;
++                uint        origoff;
++                uint        origlen;
++                char*       rbuf    = rbuf1;
++                uint        rbuflen = rbuf1len;
++
++                off += 12;
++                origoff = (ptran-ptcp)+off;
++                origlen = 0;
++                numlen = nf_strtou16(ptran+off, &port);
++                off += numlen;
++                origlen += numlen;
++                if (port != prtspexp->loport)
++                {
++                    DEBUGP("multiple ports found, port %hu ignored\n", port);
++                }
++                else
++                {
++                    if (ptran[off] == '-' || ptran[off] == '/')
++                    {
++                        off++;
++                        origlen++;
++                        numlen = nf_strtou16(ptran+off, &port);
++                        off += numlen;
++                        origlen += numlen;
++                        rbuf = rbufa;
++                        rbuflen = rbufalen;
++                    }
++
++                    /*
++                     * note we cannot just memcpy() if the sizes are the same.
++                     * the mangle function does skb resizing, checks for a
++                     * cloned skb, and updates the checksums.
++                     *
++                     * parameter 4 below is offset from start of tcp data.
++                     */
++                    diff = origlen-rbuflen;
++                    if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++                                              origoff, origlen, rbuf, rbuflen))
++                    {
++                        /* mangle failed, all we can do is bail */
++                        return 0;
++                    }
++                    get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++                    ptran = ptcp+tranoff;
++                    tranlen -= diff;
++                    nextparamoff -= diff;
++                    nextfieldoff -= diff;
++                }
++            }
++
++            off = nextfieldoff;
++        }
++
++        off = nextparamoff;
++    }
++
++    return 1;
++}
++
++static unsigned int
++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info)
++{
++    struct ip_nat_multi_range mr;
++    u_int32_t newdstip, newsrcip, newip;
++
++    struct ip_conntrack *master = master_ct(ct);
++
++    IP_NF_ASSERT(info);
++    IP_NF_ASSERT(master);
++
++    IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++    newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++    newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++    newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
++
++    DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n",
++           NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
++
++    mr.rangesize = 1;
++    /* We don't want to manip the per-protocol, just the IPs. */
++    mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++    mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++    return ip_nat_setup_info(ct, &mr, hooknum);
++}
++
++static uint
++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++         struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++    char*   ptcp;
++    uint    tcplen;
++    uint    hdrsoff;
++    uint    hdrslen;
++    uint    lineoff;
++    uint    linelen;
++    uint    off;
++
++    struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++    struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
++
++    struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++
++    get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++
++    hdrsoff = exp->seq - ntohl(tcph->seq);
++    hdrslen = prtspexp->len;
++    off = hdrsoff;
++
++    while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
++    {
++        if (linelen == 0)
++        {
++            break;
++        }
++        if (off > hdrsoff+hdrslen)
++        {
++            INFOP("!! overrun !!");
++            break;
++        }
++        DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++        if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
++        {
++            uint oldtcplen = tcplen;
++            if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
++            {
++                break;
++            }
++            get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++            hdrslen -= (oldtcplen-tcplen);
++            off -= (oldtcplen-tcplen);
++            lineoff -= (oldtcplen-tcplen);
++            linelen -= (oldtcplen-tcplen);
++            DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++        }
++    }
++
++    return NF_ACCEPT;
++}
++
++static uint
++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++         struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++    /* XXX: unmangle */
++    return NF_ACCEPT;
++}
++
++static uint
++help(struct ip_conntrack* ct,
++     struct ip_conntrack_expect* exp,
++     struct ip_nat_info* info,
++     enum ip_conntrack_info ctinfo,
++     unsigned int hooknum,
++     struct sk_buff** pskb)
++{
++    struct iphdr*  iph  = (struct iphdr*)(*pskb)->nh.iph;
++    struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
++    uint datalen;
++    int dir;
++    struct ip_ct_rtsp_expect* ct_rtsp_info;
++    int rc = NF_ACCEPT;
++
++    if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
++    {
++        DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb);
++        return NF_ACCEPT;
++    }
++
++    ct_rtsp_info = &exp->help.exp_rtsp_info;
++
++    /*
++     * Only mangle things once: original direction in POST_ROUTING
++     * and reply direction on PRE_ROUTING.
++     */
++    dir = CTINFO2DIR(ctinfo);
++    if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++          || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
++    {
++        DEBUGP("Not touching dir %s at hook %s\n",
++               dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++               hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++               : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++               : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++        return NF_ACCEPT;
++    }
++    DEBUGP("got beyond not touching\n");
++
++    datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
++
++    LOCK_BH(&ip_rtsp_lock);
++    /* Ensure the packet contains all of the marked data */
++    if (!between(exp->seq + ct_rtsp_info->len,
++                 ntohl(tcph->seq), ntohl(tcph->seq) + datalen))
++    {
++        /* Partial retransmission?  Probably a hacker. */
++        if (net_ratelimit())
++        {
++            INFOP("partial packet %u/%u in %u/%u\n",
++                   exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
++        }
++        UNLOCK_BH(&ip_rtsp_lock);
++        return NF_DROP;
++    }
++
++    switch (dir)
++    {
++    case IP_CT_DIR_ORIGINAL:
++        rc = help_out(ct, ctinfo, exp, pskb);
++        break;
++    case IP_CT_DIR_REPLY:
++        rc = help_in(ct, ctinfo, exp, pskb);
++        break;
++    default:
++        /* oops */
++    }
++    UNLOCK_BH(&ip_rtsp_lock);
++
++    return rc;
++}
++
++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as  __exit */
++static void
++fini(void)
++{
++    int i;
++
++    for (i = 0; i < num_ports; i++)
++    {
++        DEBUGP("unregistering helper for port %d\n", ports[i]);
++        ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
++    }
++}
++
++static int __init
++init(void)
++{
++    int ret = 0;
++    int i;
++    struct ip_nat_helper* hlpr;
++    char* tmpname;
++
++    printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++    if (ports[0] == 0)
++    {
++        ports[0] = RTSP_PORT;
++    }
++
++    for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
++    {
++        hlpr = &ip_nat_rtsp_helpers[i];
++        memset(hlpr, 0, sizeof(struct ip_nat_helper));
++
++        hlpr->tuple.dst.protonum = IPPROTO_TCP;
++        hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++        hlpr->mask.src.u.tcp.port = 0xFFFF;
++        hlpr->mask.dst.protonum = 0xFFFF;
++        hlpr->help = help;
++        hlpr->flags = 0;
++        hlpr->me = THIS_MODULE;
++        hlpr->expect = expected;
++
++        tmpname = &rtsp_names[i][0];
++        if (ports[i] == RTSP_PORT)
++        {
++                sprintf(tmpname, "rtsp");
++        }
++        else
++        {
++                sprintf(tmpname, "rtsp-%d", i);
++        }
++        hlpr->name = tmpname;
++
++        DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
++        ret = ip_nat_helper_register(hlpr);
++
++        if (ret)
++        {
++            printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
++            fini();
++            return 1;
++        }
++        num_ports++;
++    }
++    if (stunaddr != NULL)
++    {
++        extip = in_aton(stunaddr);
++    }
++    if (destaction != NULL)
++    {
++        if (strcmp(destaction, "auto") == 0)
++        {
++            dstact = DSTACT_AUTO;
++        }
++        if (strcmp(destaction, "strip") == 0)
++        {
++            dstact = DSTACT_STRIP;
++        }
++        if (strcmp(destaction, "none") == 0)
++        {
++            dstact = DSTACT_NONE;
++        }
++    }
++    return ret;
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_tables.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_tables.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_tables.c 2004-03-16 05:45:50.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_tables.c     2004-03-16 12:04:36.000000000 +0000
+@@ -8,6 +8,10 @@
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
++ *  6 Mar 2002 Robert Olsson <robban@robtex.com>
++ * 17 Apr 2003 Chris  Wilson <chris@netservers.co.uk>
++ *     - mark_source_chains speedup for complex chains
++ *
+  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+  *    - increase module usage count as soon as we have rules inside
+  *      a table
+@@ -498,6 +502,9 @@
+ {
+       unsigned int hook;
++      /* keep track of where we have been: */
++      unsigned char *been = vmalloc(newinfo->size);
++
+       /* No recursion; use packet counter to save back ptrs (reset
+          to 0 as we leave), and comefrom to save source hook bitmask */
+       for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) {
+@@ -510,6 +517,7 @@
+               /* Set initial back pointer. */
+               e->counters.pcnt = pos;
++              memset(been, 0, newinfo->size);
+               for (;;) {
+                       struct ipt_standard_target *t
+@@ -518,6 +526,7 @@
+                       if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
+                               printk("iptables: loop hook %u pos %u %08X.\n",
+                                      hook, pos, e->comefrom);
++                              vfree(been);
+                               return 0;
+                       }
+                       e->comefrom
+@@ -565,10 +574,14 @@
+                       } else {
+                               int newpos = t->verdict;
+-                              if (strcmp(t->target.u.user.name,
++                              if ( (pos < 0 || pos >= newinfo->size
++                                    || !been[pos]) 
++                                  && strcmp(t->target.u.user.name,
+                                          IPT_STANDARD_TARGET) == 0
+                                   && newpos >= 0) {
+                                       /* This a jump; chase it. */
++                                      if (pos >= 0 && pos < newinfo->size)
++                                              been[pos]++;
+                                       duprintf("Jump rule %u -> %u\n",
+                                                pos, newpos);
+                               } else {
+@@ -584,6 +597,7 @@
+               next:
+               duprintf("Finished chain %u\n", hook);
+       }
++      vfree(been);
+       return 1;
+ }
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_CONNMARK.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_CONNMARK.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_CONNMARK.c  2004-03-16 12:04:09.000000000 +0000
+@@ -0,0 +1,118 @@
++/* This kernel module is used to modify the connection mark values, or
++ * to optionally restore the skb nfmark from the connection mark
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * 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
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables CONNMARK matching module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++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)
++{
++      const struct ipt_connmark_target_info *markinfo = targinfo;
++      unsigned long diff;
++      unsigned long nfmark;
++      unsigned long newmark;
++
++      enum ip_conntrack_info ctinfo;
++      struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
++      if (ct) {
++          switch(markinfo->mode) {
++          case IPT_CONNMARK_SET:
++              newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
++              if (newmark != ct->mark)
++                  ct->mark = newmark;
++              break;
++          case IPT_CONNMARK_SAVE:
++              newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
++              if (ct->mark != newmark)
++                  ct->mark = newmark;
++              break;
++          case IPT_CONNMARK_RESTORE:
++              nfmark = (*pskb)->nfmark;
++              diff = (ct->mark ^ nfmark & markinfo->mask);
++              if (diff != 0) {
++                  (*pskb)->nfmark = nfmark ^ diff;
++                  (*pskb)->nfcache |= NFC_ALTERED;
++              }
++              break;
++          }
++      }
++
++      return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_entry *e,
++         void *targinfo,
++         unsigned int targinfosize,
++         unsigned int hook_mask)
++{
++      struct ipt_connmark_target_info *matchinfo = targinfo;
++      if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
++              printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
++                     targinfosize,
++                     IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
++              return 0;
++      }
++
++      if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
++          if (strcmp(tablename, "mangle") != 0) {
++                  printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++                  return 0;
++          }
++      }
++
++      return 1;
++}
++
++static struct ipt_target ipt_connmark_reg = {
++      .name = "CONNMARK",
++      .target = &target,
++      .checkentry = &checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_target(&ipt_connmark_reg);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_connmark_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPMARK.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPMARK.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPMARK.c        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPMARK.c    2004-03-16 12:04:10.000000000 +0000
+@@ -0,0 +1,81 @@
++/* This is a module which is used for setting the NFMARK field of an skb. */
++#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_IPMARK.h>
++
++MODULE_AUTHOR("Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>");
++MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address");
++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)
++{
++      const struct ipt_ipmark_target_info *ipmarkinfo = targinfo;
++      struct iphdr *iph = (*pskb)->nh.iph;
++      unsigned long mark;
++
++      if (ipmarkinfo->addr == IPT_IPMARK_SRC)
++              mark = (unsigned long) ntohl(iph->saddr);
++      else
++              mark = (unsigned long) ntohl(iph->daddr);
++
++      mark &= ipmarkinfo->andmask;
++      mark |= ipmarkinfo->ormask;
++      
++      if ((*pskb)->nfmark != mark) {
++              (*pskb)->nfmark = mark;
++              (*pskb)->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 (targinfosize != IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))) {
++              printk(KERN_WARNING "IPMARK: targinfosize %u != %Zu\n",
++                     targinfosize,
++                     IPT_ALIGN(sizeof(struct ipt_ipmark_target_info)));
++              return 0;
++      }
++
++      if (strcmp(tablename, "mangle") != 0) {
++              printk(KERN_WARNING "IPMARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_target ipt_ipmark_reg = { 
++      .name = "IPMARK",
++      .target = target,
++      .checkentry = checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_target(&ipt_ipmark_reg);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_ipmark_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_XOR.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_XOR.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_XOR.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_XOR.c       2004-03-16 12:04:18.000000000 +0000
+@@ -0,0 +1,117 @@
++/* XOR target for IP tables
++ * (C) 2000 by Tim Vandermeersch <Tim.Vandermeersch@pandora.be>
++ * Based on ipt_TTL.c
++ *
++ * Version 1.0
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_XOR.h>
++
++MODULE_AUTHOR("Tim Vandermeersch <Tim.Vandermeersch@pandora.be>");
++MODULE_DESCRIPTION("IP tables XOR module");
++MODULE_LICENSE("GPL");
++
++static unsigned int 
++ipt_xor_target(struct sk_buff **pskb, 
++              const struct net_device *in, const struct net_device *out, 
++              unsigned int hooknum, const void *targinfo, void *userinfo)
++{
++      struct ipt_XOR_info *info = (void *) targinfo;
++      struct iphdr *iph;
++      struct tcphdr *tcph;
++      struct udphdr *udph;
++      int i, j, k;
++
++      if (!skb_ip_make_writable(pskb, (*pskb)->len))
++              return NF_DROP;
++
++      iph = (*pskb)->nh.iph;
++  
++      if (iph->protocol == IPPROTO_TCP) {
++              tcph = (struct tcphdr *) ((*pskb)->data + iph->ihl*4);
++              for (i=0, j=0; i<(ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4); ) {
++                      for (k=0; k<=info->block_size; k++) {
++                              (char) (*pskb)->data[ iph->ihl*4 + tcph->doff*4 + i ] ^= 
++                                              info->key[j];
++                              i++;
++                      }
++                      j++;
++                      if (info->key[j] == 0x00)
++                              j = 0;
++              }
++      } else if (iph->protocol == IPPROTO_UDP) {
++              udph = (struct udphdr *) ((*pskb)->data + iph->ihl*4);
++              for (i=0, j=0; i<(ntohs(udph->len)-8); ) {
++                      for (k=0; k<=info->block_size; k++) {
++                              (char) (*pskb)->data[ iph->ihl*4 + sizeof(struct udphdr) + i ] ^= 
++                                              info->key[j];
++                              i++;
++                      }
++                      j++;
++                      if (info->key[j] == 0x00)
++                              j = 0;
++              }
++      }
++  
++      return IPT_CONTINUE;
++}
++
++static int ipt_xor_checkentry(const char *tablename, const struct ipt_entry *e,
++              void *targinfo, unsigned int targinfosize, 
++              unsigned int hook_mask)
++{
++      struct ipt_XOR_info *info = targinfo;
++
++      if (targinfosize != IPT_ALIGN(sizeof(struct ipt_XOR_info))) {
++              printk(KERN_WARNING "XOR: targinfosize %u != %Zu\n", 
++                              targinfosize, IPT_ALIGN(sizeof(struct ipt_XOR_info)));
++              return 0;
++      }       
++
++      if (strcmp(tablename, "mangle")) {
++              printk(KERN_WARNING "XOR: can only be called from"
++                              "\"mangle\" table, not \"%s\"\n", tablename);
++              return 0; 
++      }
++
++      if (!strcmp(info->key, "")) {
++              printk(KERN_WARNING "XOR: You must specify a key");
++              return 0;
++      }
++
++      if (info->block_size == 0) {
++              printk(KERN_WARNING "XOR: You must specify a block-size");
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_target ipt_XOR = { 
++      .name = "XOR",
++      .target = ipt_xor_target, 
++      .checkentry = ipt_xor_checkentry,
++      .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++      return ipt_register_target(&ipt_XOR);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_target(&ipt_XOR);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_addrtype.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_addrtype.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_addrtype.c  2004-03-16 12:04:20.000000000 +0000
+@@ -0,0 +1,68 @@
++/*
++ *  iptables module to match inet_addr_type() of an ip.
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/route.h>
++
++#include <linux/netfilter_ipv4/ipt_addrtype.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_LICENSE("GPL");
++
++static inline int match_type(u_int32_t addr, u_int16_t mask)
++{
++      return !!(mask & (1 << inet_addr_type(addr)));
++}
++
++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_addrtype_info *info = matchinfo;
++      const struct iphdr *iph = skb->nh.iph;
++      int ret = 1;
++
++      if (info->source)
++              ret &= match_type(iph->saddr, info->source)^info->invert_source;
++      if (info->dest)
++              ret &= match_type(iph->daddr, info->dest)^info->invert_dest;
++      
++      return ret;
++}
++
++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_addrtype_info))) {
++              printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.",
++                     matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info)));
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_match addrtype_match = { 
++      .name = "addrtype",
++      .match = match,
++      .checkentry = checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&addrtype_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&addrtype_match);
++
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connmark.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connmark.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connmark.c      1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connmark.c  2004-03-16 12:04:09.000000000 +0000
+@@ -0,0 +1,81 @@
++/* This kernel module matches connection mark values set by the
++ * CONNMARK target
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * 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
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables connmark match module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connmark.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++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_connmark_info *info = matchinfo;
++      enum ip_conntrack_info ctinfo;
++      struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++      if (!ct)
++              return 0;
++
++      return ((ct->mark & info->mask) == info->mark) ^ info->invert;
++}
++
++static int
++checkentry(const char *tablename,
++         const struct ipt_ip *ip,
++         void *matchinfo,
++         unsigned int matchsize,
++         unsigned int hook_mask)
++{
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
++              return 0;
++
++      return 1;
++}
++
++static struct ipt_match connmark_match = {
++      .name = "connmark",
++      .match = &match,
++      .checkentry = &checkentry,
++      .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&connmark_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&connmark_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_owner.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_owner.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_owner.c 2004-03-16 05:47:19.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_owner.c     2004-03-16 12:04:38.000000000 +0000
+@@ -6,12 +6,19 @@
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
++ *
++ * 03/26/2003 Patrick McHardy <kaber@trash.net>       : LOCAL_IN support
+  */
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/file.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
+ #include <net/sock.h>
++#include <net/tcp.h>
++#include <net/udp.h>
+ #include <linux/netfilter_ipv4/ipt_owner.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+@@ -21,7 +28,7 @@
+ MODULE_DESCRIPTION("iptables owner match");
+ static int
+-match_comm(const struct sk_buff *skb, const char *comm)
++match_comm(const struct sock *sk, const char *comm)
+ {
+       struct task_struct *g, *p;
+       struct files_struct *files;
+@@ -38,7 +45,7 @@
+                       spin_lock(&files->file_lock);
+                       for (i=0; i < files->max_fds; i++) {
+                               if (fcheck_files(files, i) ==
+-                                  skb->sk->sk_socket->file) {
++                                  sk->sk_socket->file) {
+                                       spin_unlock(&files->file_lock);
+                                       task_unlock(p);
+                                       read_unlock(&tasklist_lock);
+@@ -54,7 +61,7 @@
+ }
+ static int
+-match_pid(const struct sk_buff *skb, pid_t pid)
++match_pid(const struct sock *sk, pid_t pid)
+ {
+       struct task_struct *p;
+       struct files_struct *files;
+@@ -70,7 +77,7 @@
+               spin_lock(&files->file_lock);
+               for (i=0; i < files->max_fds; i++) {
+                       if (fcheck_files(files, i) ==
+-                          skb->sk->sk_socket->file) {
++                          sk->sk_socket->file) {
+                               spin_unlock(&files->file_lock);
+                               task_unlock(p);
+                               read_unlock(&tasklist_lock);
+@@ -86,10 +93,10 @@
+ }
+ static int
+-match_sid(const struct sk_buff *skb, pid_t sid)
++match_sid(const struct sock *sk, pid_t sid)
+ {
+       struct task_struct *g, *p;
+-      struct file *file = skb->sk->sk_socket->file;
++      struct file *file = sk->sk_socket->file;
+       int i, found=0;
+       read_lock(&tasklist_lock);
+@@ -129,41 +136,71 @@
+       int *hotdrop)
+ {
+       const struct ipt_owner_info *info = matchinfo;
++      struct iphdr *iph = skb->nh.iph;
++      struct sock *sk = NULL;
++      int ret = 0;
++
++      if (out) {
++              sk = skb->sk;
++      } else {
++              if (iph->protocol == IPPROTO_TCP) {
++                      struct tcphdr *tcph =
++                              (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
++                      sk = tcp_v4_lookup(iph->saddr, tcph->source,
++                                         iph->daddr, tcph->dest,
++                                         skb->dev->ifindex);
++                      if (sk && sk->sk_state == TCP_TIME_WAIT) {
++                              tcp_tw_put((struct tcp_tw_bucket *)sk);
++                              return ret;
++                      }
++              } else if (iph->protocol == IPPROTO_UDP) {
++                      struct udphdr *udph =
++                              (struct udphdr *)((u_int32_t *)iph + iph->ihl);
++                      sk = udp_v4_lookup(iph->saddr, udph->source, iph->daddr,
++                                         udph->dest, skb->dev->ifindex);
++              }
++      }
+-      if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
+-              return 0;
++      if (!sk || !sk->sk_socket || !sk->sk_socket->file)
++              goto out;
+       if(info->match & IPT_OWNER_UID) {
+-              if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
++              if ((sk->sk_socket->file->f_uid != info->uid) ^
+                   !!(info->invert & IPT_OWNER_UID))
+-                      return 0;
++                      goto out;
+       }
+       if(info->match & IPT_OWNER_GID) {
+-              if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
++              if ((sk->sk_socket->file->f_gid != info->gid) ^
+                   !!(info->invert & IPT_OWNER_GID))
+-                      return 0;
++                      goto out;
+       }
+       if(info->match & IPT_OWNER_PID) {
+-              if (!match_pid(skb, info->pid) ^
++              if (!match_pid(sk, info->pid) ^
+                   !!(info->invert & IPT_OWNER_PID))
+-                      return 0;
++                      goto out;
+       }
+       if(info->match & IPT_OWNER_SID) {
+-              if (!match_sid(skb, info->sid) ^
++              if (!match_sid(sk, info->sid) ^
+                   !!(info->invert & IPT_OWNER_SID))
+-                      return 0;
++                      goto out;
+       }
+       if(info->match & IPT_OWNER_COMM) {
+-              if (!match_comm(skb, info->comm) ^
++              if (!match_comm(sk, info->comm) ^
+                   !!(info->invert & IPT_OWNER_COMM))
+-                      return 0;
++                      goto out;
+       }
+-      return 1;
++      ret = 1;
++
++out:
++      if (in && sk)
++              sock_put(sk);
++
++      return ret;
+ }
+ static int
+@@ -173,11 +210,19 @@
+            unsigned int matchsize,
+            unsigned int hook_mask)
+ {
+-        if (hook_mask
+-            & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
+-                printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
+-                return 0;
+-        }
++      if (hook_mask
++          & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING) |
++          (1 << NF_IP_LOCAL_IN))) {
++              printk("ipt_owner: only valid for LOCAL_IN, LOCAL_OUT "
++                     "or POST_ROUTING.\n");
++              return 0;
++      }
++
++      if ((hook_mask & (1 << NF_IP_LOCAL_IN))
++          && ip->proto != IPPROTO_TCP && ip->proto != IPPROTO_UDP) {
++              printk("ipt_owner: only TCP or UDP can be used in LOCAL_IN\n");
++              return 0;
++      }
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
+               printk("Matchsize %u != %Zu\n", matchsize,
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_policy.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_policy.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_policy.c        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_policy.c    2004-03-16 12:04:45.000000000 +0000
+@@ -0,0 +1,176 @@
++/* IP tables module for matching IPsec policy
++ *
++ * Copyright (c) 2004 Patrick McHardy, <kaber@trash.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <net/xfrm.h>
++
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ipt_policy.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
++MODULE_DESCRIPTION("IPtables IPsec policy matching module");
++MODULE_LICENSE("GPL");
++
++
++static inline int
++match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
++{
++#define MISMATCH(x,y) (e->match.x && ((e->x != (y)) ^ e->invert.x))
++
++      if (MISMATCH(saddr, x->props.saddr.a4 & e->smask) ||
++          MISMATCH(daddr, x->id.daddr.a4 & e->dmask) ||
++          MISMATCH(proto, x->id.proto) ||
++          MISMATCH(mode, x->props.mode) ||
++          MISMATCH(spi, x->id.spi) ||
++          MISMATCH(reqid, x->props.reqid))
++              return 0;
++      return 1;
++}
++
++static int
++match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
++{
++      const struct ipt_policy_elem *e;
++      struct sec_path *sp = skb->sp;
++      int strict = info->flags & POLICY_MATCH_STRICT;
++      int i, pos;
++
++      if (sp == NULL)
++              return -1;
++      if (strict && info->len != sp->len)
++              return 0;
++
++      for (i = sp->len - 1; i >= 0; i--) {
++              pos = strict ? i - sp->len + 1 : 0;
++              if (pos >= info->len)
++                      return 0;
++              e = &info->pol[pos];
++
++              if (match_xfrm_state(sp->x[i].xvec, e)) {
++                      if (!strict)
++                              return 1;
++              } else if (strict)
++                      return 0;
++      }
++
++      return strict ? 1 : 0;
++}
++
++static int
++match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
++{
++      const struct ipt_policy_elem *e;
++      struct dst_entry *dst = skb->dst;
++      int strict = info->flags & POLICY_MATCH_STRICT;
++      int i, pos;
++
++      if (dst->xfrm == NULL)
++              return -1;
++
++      for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
++              pos = strict ? i : 0;
++              if (pos >= info->len)
++                      return 0;
++              e = &info->pol[pos];
++
++              if (match_xfrm_state(dst->xfrm, e)) {
++                      if (!strict)
++                              return 1;
++              } else if (strict)
++                      return 0;
++      }
++
++      return strict ? 1 : 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_policy_info *info = matchinfo;
++      int ret;
++
++      if (info->flags & POLICY_MATCH_IN)
++              ret = match_policy_in(skb, info);
++      else
++              ret = match_policy_out(skb, info);
++
++      if (ret < 0) {
++              if (info->flags & POLICY_MATCH_NONE)
++                      ret = 1;
++              else
++                      ret = 0;
++      } else if (info->flags & POLICY_MATCH_NONE)
++              ret = 0;
++
++      return ret;
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++                      void *matchinfo, unsigned int matchsize,
++                      unsigned int hook_mask)
++{
++      struct ipt_policy_info *info = matchinfo;
++
++      if (matchsize != IPT_ALIGN(sizeof(*info))) {
++              printk(KERN_ERR "ipt_policy: matchsize %u != %u\n",
++                     matchsize, IPT_ALIGN(sizeof(*info)));
++              return 0;
++      }
++      if (!(info->flags & (POLICY_MATCH_IN|POLICY_MATCH_OUT))) {
++              printk(KERN_ERR "ipt_policy: neither incoming nor "
++                              "outgoing policy selected\n");
++              return 0;
++      }
++      if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
++          && info->flags & POLICY_MATCH_OUT) {
++              printk(KERN_ERR "ipt_policy: output policy not valid in "
++                              "PRE_ROUTING and INPUT\n");
++              return 0;
++      }
++      if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
++          && info->flags & POLICY_MATCH_IN) {
++              printk(KERN_ERR "ipt_policy: input policy not valid in "
++                              "POST_ROUTING and OUTPUT\n");
++              return 0;
++      }
++      if (info->len > POLICY_MAX_ELEM) {
++              printk(KERN_ERR "ipt_policy: too many policy elements\n");
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct ipt_match policy_match =
++{
++      .name           = "policy",
++      .match          = match,
++      .checkentry     = checkentry,
++      .me             = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++      return ipt_register_match(&policy_match);
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&policy_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_rpc.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_rpc.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_rpc.c   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_rpc.c       2004-03-16 12:04:46.000000000 +0000
+@@ -0,0 +1,428 @@
++/* RPC extension for IP connection matching, Version 2.2
++ * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
++ *    - original rpc tracking module
++ *    - "recent" connection handling for kernel 2.3+ netfilter
++ *
++ * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
++ *    - upgraded conntrack modules to oldnat api - kernel 2.4.0+
++ *
++ * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ *    - upgraded conntrack modules to newnat api - kernel 2.4.20+
++ *    - extended matching to support filtering on procedures
++ *
++ * ipt_rpc.c,v 2.2 2003/01/12 18:30:00
++ *
++ *    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.
++ **
++ *    Module load syntax:
++ *    insmod ipt_rpc.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ *    Please give the ports of all RPC servers you wish to connect to.
++ *    If you don't specify ports, the default will be port 111.
++ **
++ *    Note to all:
++ *
++ *    RPCs should not be exposed to the internet - ask the Pentagon;
++ *
++ *      "The unidentified crackers pleaded guilty in July to charges
++ *       of juvenile delinquency stemming from a string of Pentagon
++ *       network intrusions in February.
++ *
++ *       The youths, going by the names TooShort and Makaveli, used
++ *       a common server security hole to break in, according to
++ *       Dane Jasper, owner of the California Internet service
++ *       provider, Sonic. They used the hole, known as the 'statd'
++ *       exploit, to attempt more than 800 break-ins, Jasper said."
++ *
++ *    From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
++ *    URL:  http://www.wired.com/news/politics/0,1283,16098,00.html
++ **
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <linux/udp.h>
++#include <linux/tcp.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rpc.h>
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ipt_rpc.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_n_c = 0;
++
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers");
++#endif
++
++MODULE_AUTHOR("Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>");
++MODULE_DESCRIPTION("RPC connection matching module");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG "ipt_rpc: " \
++                                      format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++EXPORT_NO_SYMBOLS;
++
++/* vars from ip_conntrack_rpc_tcp */
++extern struct list_head request_p_list_tcp;
++extern struct module *ip_conntrack_rpc_tcp;
++
++/* vars from ip_conntrack_rpc_udp */
++extern struct list_head request_p_list_udp;
++extern struct module *ip_conntrack_rpc_udp;
++
++DECLARE_RWLOCK_EXTERN(ipct_rpc_tcp_lock);
++DECLARE_RWLOCK_EXTERN(ipct_rpc_udp_lock);
++
++#define ASSERT_READ_LOCK(x)                                   \
++do {                                                          \
++      if (x == &request_p_list_udp)                           \
++              MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock);        \
++      else if (x == &request_p_list_tcp)                      \
++              MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock);        \
++} while (0)
++
++#define ASSERT_WRITE_LOCK(x)                                  \
++do {                                                          \
++      if (x == &request_p_list_udp)                           \
++              MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock);       \
++      else if (x == &request_p_list_tcp)                      \
++              MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock);       \
++} while (0)
++
++#include <linux/netfilter_ipv4/listhelp.h>
++
++const int IPT_RPC_CHAR_LEN = 11;
++
++
++static int k_atoi(char *string)
++{
++      unsigned int result = 0;
++      int maxoctet = IPT_RPC_CHAR_LEN;
++
++      for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) {
++              if (*string < 0)
++                      return(0);
++              if (*string == 0)
++                      break;
++              if (*string < 48 || *string > 57) {
++                      return(0);
++              }
++              result = result * 10 + ( *string - 48 );
++      }
++      return(result);
++}
++
++
++static int match_rpcs(char *c_procs, int i_procs, int proc)
++{
++      int   proc_ctr;
++      char *proc_ptr;
++      unsigned int proc_num;
++
++      DEBUGP("entered match_rpcs [%i] [%i] ..\n", i_procs, proc);
++
++      if (i_procs == -1)
++              return 1;
++
++      for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) {
++
++              proc_ptr = c_procs;
++              proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN;
++              proc_num = k_atoi(proc_ptr);
++
++              if (proc_num == proc)
++                      return 1;
++      }
++
++      return 0;
++}
++
++
++static int check_rpc_packet(const u_int32_t *data, const void *matchinfo,
++                      int *hotdrop, int dir, struct ip_conntrack *ct,
++                      int offset, struct list_head request_p_list)
++{
++      const struct ipt_rpc_info *rpcinfo = matchinfo;
++      struct request_p *req_p;
++      u_int32_t xid;
++
++
++      /* Get XID */
++      xid = *data;
++
++      /* This does sanity checking on RPC payloads,
++       * and permits only the RPC "get port" (3)
++       * in authorised procedures in client
++       * communications with the portmapper.
++       */
++
++      data += 5;
++
++      /* Get RPC requestor */
++      if (IXDR_GET_INT32(data) != 3) {
++              DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n");
++              if(rpcinfo->strict == 1)
++                      *hotdrop = 1;
++              return 0;
++      }
++      DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n");
++
++      data++;
++
++      /* Jump Credentials and Verfifier */
++      data = data + IXDR_GET_INT32(data) + 2;
++      data = data + IXDR_GET_INT32(data) + 2;
++
++      /* Get RPC procedure */
++      if (match_rpcs((char *)&rpcinfo->c_procs,
++          rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) {
++              DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n",
++                      (unsigned int)IXDR_GET_INT32(data));
++
++              /* If the RPC conntrack half entry already exists .. */
++
++              switch (ct->tuplehash[0].tuple.dst.protonum) {
++                      case IPPROTO_UDP:
++                              WRITE_LOCK(&ipct_rpc_udp_lock);
++                      case IPPROTO_TCP:
++                              WRITE_LOCK(&ipct_rpc_tcp_lock);
++              }
++              req_p = LIST_FIND(&request_p_list, request_p_cmp,
++                                struct request_p *, xid,
++                                ct->tuplehash[dir].tuple.src.ip,
++                                ct->tuplehash[dir].tuple.src.u.all);
++
++              if (req_p) {
++                      DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n",
++                              xid, ct->tuplehash[dir].tuple.dst.protonum,
++                              NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
++                              ntohs(ct->tuplehash[dir].tuple.src.u.all));
++
++                      /* .. remove it */
++                      if (del_timer(&req_p->timeout))
++                              req_p->timeout.expires = 0;
++
++                              LIST_DELETE(&request_p_list, req_p);
++                      DEBUGP("RPC req_p removed. [done]\n");
++
++              } else {
++                      DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n",
++                              xid, ct->tuplehash[dir].tuple.dst.protonum,
++                              NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
++                              ntohs(ct->tuplehash[dir].tuple.src.u.all));
++
++              }
++              switch (ct->tuplehash[0].tuple.dst.protonum) {
++                      case IPPROTO_UDP:
++                              WRITE_UNLOCK(&ipct_rpc_udp_lock);
++                      case IPPROTO_TCP:
++                              WRITE_UNLOCK(&ipct_rpc_tcp_lock);
++              }
++
++              if(rpcinfo->strict == 1)
++                      *hotdrop = 1;
++              return 0;
++      }
++
++      DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n",
++              (unsigned int)IXDR_GET_INT32(data));
++      return (1 && (!offset));
++}
++
++
++static int match(const struct sk_buff *skb, const struct net_device *in,
++               const struct net_device *out, const void *matchinfo,
++               int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
++{
++      struct ip_conntrack *ct;
++      enum ip_conntrack_info ctinfo;
++      const u_int32_t *data;
++      enum ip_conntrack_dir dir;
++      const struct tcphdr *tcp;
++      const struct ipt_rpc_info *rpcinfo = matchinfo;
++      int port, portsok;
++      int tval;
++
++
++      DEBUGP("new packet to evaluate ..\n");
++
++      ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++      if (!ct) {
++              DEBUGP("no ct available [skip]\n");
++              return 0;
++      }
++
++      DEBUGP("ct detected. [cont]\n");
++      dir = CTINFO2DIR(ctinfo);
++
++      /* we only want the client to server packets for matching */
++      if (dir != IP_CT_DIR_ORIGINAL)
++              return 0;
++
++      /* This does sanity checking on UDP or TCP packets,
++       * like their respective modules.
++       */
++
++      switch (ct->tuplehash[0].tuple.dst.protonum) {
++
++              case IPPROTO_UDP:
++                      DEBUGP("PROTO_UDP [cont]\n");
++                      if (offset == 0 && datalen < sizeof(struct udphdr)) {
++                              DEBUGP("packet does not contain a complete header. [drop]\n");
++                              return 0;
++                      }
++
++                      for (port=0,portsok=0; port <= ports_n_c; port++) {
++                              if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
++                                      portsok++;
++                                      break;
++                              }
++                      }
++                      if (portsok == 0) {
++                              DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
++                                      ntohs(ct->tuplehash[dir].tuple.dst.u.all));
++                              return 0;
++                      }
++
++                      if ((datalen - sizeof(struct udphdr)) != 56) {
++                              DEBUGP("packet length is not correct for RPC content. [skip]\n");
++                              if (rpcinfo->strict == 1)
++                                      *hotdrop = 1;
++                              return 0;
++                      }
++                      DEBUGP("packet length is correct. [cont]\n");
++
++                      /* Get to the data */
++                      data = (const u_int32_t *)hdr + 2;
++
++                      /* Check the RPC data */
++                      tval = check_rpc_packet(data, matchinfo, hotdrop,
++                                              dir, ct, offset,
++                                              request_p_list_udp);
++
++                      return tval;
++                      
++              
++              case IPPROTO_TCP:
++                      DEBUGP("PROTO_TCP [cont]\n");
++                      if (offset == 0 && datalen < sizeof(struct tcphdr)) {
++                              DEBUGP("packet does not contain a complete header. [drop]\n");
++                              return 0;
++                      }
++      
++                      for (port=0,portsok=0; port <= ports_n_c; port++) {
++                              if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) {
++                                      portsok++;
++                                      break;
++                              }
++                      }
++                      if (portsok == 0) {
++                              DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n",
++                                      ntohs(ct->tuplehash[dir].tuple.dst.u.all));
++                              return 0;
++                      }
++
++                      tcp = hdr;
++                      if (datalen == (tcp->doff * 4)) {
++                              DEBUGP("packet does not contain any data. [match]\n");
++                              return (1 && (!offset));
++                      }
++
++                      /* Tests if packet len is ok */
++                      if ((datalen - (tcp->doff * 4)) != 60) {
++                              DEBUGP("packet length is not correct for RPC content. [skip]\n");
++                              if(rpcinfo->strict == 1)
++                                      *hotdrop = 1;
++                              return 0;
++                      }
++                      DEBUGP("packet length is correct. [cont]\n");
++
++                      /* Get to the data */
++                      data = (const u_int32_t *)tcp + tcp->doff + 1;  
++
++                      /* Check the RPC data */
++                      tval = check_rpc_packet(data, matchinfo, hotdrop,
++                                              dir, ct, offset,
++                                              request_p_list_tcp);
++
++                      return tval;
++
++      }
++
++      DEBUGP("transport protocol=%u, is not supported [skip]\n",
++              ct->tuplehash[0].tuple.dst.protonum);
++      return 0;
++}
++
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo,
++                 unsigned int matchsize, unsigned int hook_mask)
++{
++      if (hook_mask
++          & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_POST_ROUTING)
++              | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) {
++              printk("ipt_rpc: only valid for PRE_ROUTING, FORWARD, POST_ROUTING, LOCAL_IN and/or LOCAL_OUT targets.\n");
++              return 0;
++      }
++
++      if (matchsize != IPT_ALIGN(sizeof(struct ipt_rpc_info)))
++              return 0;
++
++      return 1;
++}
++
++
++static struct ipt_match rpc_match = { { NULL, NULL }, "rpc",
++                                      &match, &checkentry, NULL,
++                                      THIS_MODULE };
++
++
++static int __init init(void)
++{
++      int port;
++
++      DEBUGP("incrementing usage counts\n");
++      __MOD_INC_USE_COUNT(ip_conntrack_rpc_udp);
++      __MOD_INC_USE_COUNT(ip_conntrack_rpc_tcp);
++
++      /* If no port given, default to standard RPC port */
++      if (ports[0] == 0)
++              ports[0] = RPC_PORT;
++
++      DEBUGP("registering match [%s] for;\n", rpc_match.name);
++      for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
++              DEBUGP("  port %i (UDP|TCP);\n", ports[port]);
++              ports_n_c++;
++      }
++      
++      return ipt_register_match(&rpc_match);
++}
++
++
++static void fini(void)
++{
++      DEBUGP("unregistering match\n");
++      ipt_unregister_match(&rpc_match);
++
++      DEBUGP("decrementing usage counts\n");
++      __MOD_DEC_USE_COUNT(ip_conntrack_rpc_tcp);
++      __MOD_DEC_USE_COUNT(ip_conntrack_rpc_udp);
++}
++
++
++module_init(init);
++module_exit(fini);
++
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_string.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_string.c
+--- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_string.c        1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_string.c    2004-03-16 12:06:26.000000000 +0000
+@@ -0,0 +1,218 @@
++/* Kernel module to match a string into a packet.
++ *
++ * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
++ * 
++ * ChangeLog
++ *    19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk>
++ *            Fixed SMP re-entrancy problem using per-cpu data areas
++ *            for the skip/shift tables.
++ *    02.05.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ *            Fixed kernel panic, due to overrunning boyer moore string
++ *            tables. Also slightly tweaked heuristic for deciding what
++ *            search algo to use.
++ *    27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ *            Implemented Boyer Moore Sublinear search algorithm
++ *            alongside the existing linear search based on memcmp().
++ *            Also a quick check to decide which method to use on a per
++ *            packet basis.
++ */
++
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_string.h>
++
++MODULE_LICENSE("GPL");
++
++struct string_per_cpu {
++      int *skip;
++      int *shift;
++      int *len;
++};
++
++struct string_per_cpu *bm_string_data=NULL;
++
++/* Boyer Moore Sublinear string search - VERY FAST */
++char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len) 
++{
++      int M1, right_end, sk, sh;  
++      int ended, j, i;
++
++      int *skip, *shift, *len;
++      
++      /* use data suitable for this CPU */
++      shift=bm_string_data[smp_processor_id()].shift;
++      skip=bm_string_data[smp_processor_id()].skip;
++      len=bm_string_data[smp_processor_id()].len;
++      
++      /* Setup skip/shift tables */
++      M1 = right_end = needle_len-1;
++      for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len;  
++      for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i;  
++
++      for (i = 1; i < needle_len; i++) {   
++              for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++);  
++              len[i] = j;  
++      }  
++
++      shift[0] = 1;  
++      for (i = 1; i < needle_len; i++) shift[i] = needle_len;  
++      for (i = M1; i > 0; i--) shift[len[i]] = i;  
++      ended = 0;  
++      
++      for (i = 0; i < needle_len; i++) {  
++              if (len[i] == M1 - i) ended = i;  
++              if (ended) shift[i] = ended;  
++      }  
++
++      /* Do the search*/  
++      while (right_end < haystack_len)
++      {
++              for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++);  
++              if (i == needle_len) {
++                      return haystack+(right_end - M1);
++              }
++              
++              sk = skip[haystack[right_end - i]];  
++              sh = shift[i];
++              right_end = max(right_end - i + sk, right_end + sh);  
++      }
++
++      return NULL;
++}  
++
++/* Linear string search based on memcmp() */
++char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len) 
++{
++      char *k = haystack + (haystack_len-needle_len);
++      char *t = haystack;
++      
++      while ( t <= k ) {
++              if (memcmp(t, needle, needle_len) == 0)
++                      return t;
++              t++;
++      }
++
++      return NULL;
++}
++
++
++static int
++match(const struct sk_buff *skb,
++      const struct net_device *in,
++      const struct net_device *out,
++      const void *matchinfo,
++      int offset,
++      const void *hdr,
++      u_int16_t datalen,
++      int *hotdrop)
++{
++      const struct ipt_string_info *info = matchinfo;
++      struct iphdr *ip = skb->nh.iph;
++      int hlen, nlen;
++      char *needle, *haystack;
++      proc_ipt_search search=search_linear;
++
++      if ( !ip ) return 0;
++
++      /* get lenghts, and validate them */
++      nlen=info->len;
++      hlen=ntohs(ip->tot_len)-(ip->ihl*4);
++      if ( nlen > hlen ) return 0;
++
++      needle=(char *)&info->string;
++      haystack=(char *)ip+(ip->ihl*4);
++
++      /* The sublinear search comes in to its own
++       * on the larger packets */
++      if ( (hlen>IPT_STRING_HAYSTACK_THRESH) &&
++              (nlen>IPT_STRING_NEEDLE_THRESH) ) {
++              if ( hlen < BM_MAX_HLEN ) {
++                      search=search_sublinear;
++              }else{
++                      if (net_ratelimit())
++                              printk(KERN_INFO "ipt_string: Packet too big "
++                                      "to attempt sublinear string search "
++                                      "(%d bytes)\n", hlen );
++              }
++      }
++      
++    return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert);
++}
++
++static int
++checkentry(const char *tablename,
++           const struct ipt_ip *ip,
++           void *matchinfo,
++           unsigned int matchsize,
++           unsigned int hook_mask)
++{
++
++       if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
++               return 0;
++
++       return 1;
++}
++
++void string_freeup_data(void)
++{
++      int c;
++      
++      if ( bm_string_data ) {
++              for(c=0; c<smp_num_cpus; c++) {
++                      if ( bm_string_data[c].shift ) kfree(bm_string_data[c].shift);
++                      if ( bm_string_data[c].skip ) kfree(bm_string_data[c].skip);
++                      if ( bm_string_data[c].len ) kfree(bm_string_data[c].len);
++              }
++              kfree(bm_string_data);
++      }
++}
++
++static struct ipt_match string_match
++= { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++      int c;
++      size_t tlen;
++      size_t alen;
++
++      tlen=sizeof(struct string_per_cpu)*smp_num_cpus;
++      alen=sizeof(int)*BM_MAX_HLEN;
++      
++      /* allocate array of structures */
++      if ( !(bm_string_data=kmalloc(tlen,GFP_KERNEL)) ) {
++              return 0;
++      }
++      
++      memset(bm_string_data, 0, tlen);
++      
++      /* allocate our skip/shift tables */
++      for(c=0; c<smp_num_cpus; c++) {
++              if ( !(bm_string_data[c].shift=kmalloc(alen, GFP_KERNEL)) )
++                      goto alloc_fail;
++              if ( !(bm_string_data[c].skip=kmalloc(alen, GFP_KERNEL)) )
++                      goto alloc_fail;
++              if ( !(bm_string_data[c].len=kmalloc(alen, GFP_KERNEL)) )
++                      goto alloc_fail;
++      }
++      
++      return ipt_register_match(&string_match);
++
++alloc_fail:
++      string_freeup_data();
++      return 0;
++}
++
++static void __exit fini(void)
++{
++      ipt_unregister_match(&string_match);
++      string_freeup_data();
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/tcp_ipv4.c linux-2.6.5-rc1/net/ipv4/tcp_ipv4.c
+--- linux-2.6.5-rc1.org/net/ipv4/tcp_ipv4.c    2004-03-16 05:45:58.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/tcp_ipv4.c        2004-03-16 12:04:38.000000000 +0000
+@@ -2667,6 +2667,7 @@
+ EXPORT_SYMBOL(tcp_v4_connect);
+ EXPORT_SYMBOL(tcp_v4_do_rcv);
+ EXPORT_SYMBOL(tcp_v4_lookup_listener);
++EXPORT_SYMBOL(tcp_v4_lookup);
+ EXPORT_SYMBOL(tcp_v4_rebuild_header);
+ EXPORT_SYMBOL(tcp_v4_remember_stamp);
+ EXPORT_SYMBOL(tcp_v4_send_check);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/udp.c linux-2.6.5-rc1/net/ipv4/udp.c
+--- linux-2.6.5-rc1.org/net/ipv4/udp.c 2004-03-16 05:45:49.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv4/udp.c     2004-03-16 12:04:38.000000000 +0000
+@@ -1543,6 +1543,7 @@
+ EXPORT_SYMBOL(udp_port_rover);
+ EXPORT_SYMBOL(udp_prot);
+ EXPORT_SYMBOL(udp_sendmsg);
++EXPORT_SYMBOL(udp_v4_lookup);
+ #ifdef CONFIG_PROC_FS
+ EXPORT_SYMBOL(udp_proc_register);
+diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_owner.c linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_owner.c
+--- linux-2.6.5-rc1.org/net/ipv6/netfilter/ip6t_owner.c        2004-03-16 05:47:17.000000000 +0000
++++ linux-2.6.5-rc1/net/ipv6/netfilter/ip6t_owner.c    2004-03-16 12:04:42.000000000 +0000
+@@ -21,6 +21,38 @@
+ MODULE_LICENSE("GPL");
+ static int
++match_comm(const struct sk_buff *skb, const char *comm)
++{
++      struct task_struct *p;
++      struct files_struct *files;
++      int i;
++
++      read_lock(&tasklist_lock);
++      for_each_task(p) {
++              if(strncmp(p->comm, comm, sizeof(p->comm)))
++                      continue;
++
++              task_lock(p);
++              files = p->files;
++              if(files) {
++                      read_lock(&files->file_lock);
++                      for (i=0; i < files->max_fds; i++) {
++                              if (fcheck_files(files, i) == skb->sk->socket->file) {
++                                      read_unlock(&files->file_lock);
++                                      task_unlock(p);
++                                      read_unlock(&tasklist_lock);
++                                      return 1;
++                              }
++                      }
++                      read_unlock(&files->file_lock);
++              }
++              task_unlock(p);
++      }
++      read_unlock(&tasklist_lock);
++      return 0;
++}
++
++static int
+ match_pid(const struct sk_buff *skb, pid_t pid)
+ {
+       struct task_struct *p;
+@@ -125,6 +157,12 @@
+                       return 0;
+       }
++      if(info->match & IP6T_OWNER_COMM) {
++              if (!match_comm(skb, info->comm) ^
++                  !!(info->invert & IP6T_OWNER_COMM))
++                      return 0;
++      }
++
+       return 1;
+ }
This page took 0.424654 seconds and 4 git commands to generate.