--- /dev/null
+diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack_helper.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack_helper.h 2004-03-04 06:16:37.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack_helper.h 2004-03-04 08:39:18.000000000 +0000
+@@ -35,9 +35,13 @@
+
+ extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
++
++/* Allocate space for an expectation: this is mandatory before calling
++ ip_conntrack_expect_related. */
++extern int ip_conntrack_expect_alloc(struct ip_conntrack_expect **new);
+ /* Add an expected connection: can have more than one per connection */
+-extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
+- struct ip_conntrack_expect *exp);
++extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp,
++ struct ip_conntrack *related_to);
+ extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+ struct ip_conntrack_tuple *newtuple);
+ extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
+diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h 2004-03-04 08:39:28.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-03-04 08:39:29.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-03-04 08:39:31.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h 2004-03-04 08:39:33.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h 2004-03-04 08:39:34.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h 2004-03-04 08:39:36.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h 2004-03-04 08:39:54.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h 2004-03-04 08:39:55.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h 2004-03-04 08:39:25.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_HOPLIMIT_H
++#define _IP6T_HOPLIMIT_H
++
++enum {
++ IP6T_HOPLIMIT_SET = 0,
++ IP6T_HOPLIMIT_INC,
++ IP6T_HOPLIMIT_DEC
++};
++
++#define IP6T_HOPLIMIT_MAXMODE IP6T_HOPLIMIT_DEC
++
++struct ip6t_HOPLIMIT_info {
++ u_int8_t mode;
++ u_int8_t hop_limit;
++};
++
++
++#endif
+diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-04 06:16:34.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-04 08:39:28.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h
+--- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h 2004-03-04 08:39:34.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig 2004-03-04 06:16:58.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig 2004-03-04 08:39:55.000000000 +0000
+@@ -579,5 +579,60 @@
+
+ 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_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
++
+ endmenu
+
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.4-rc2/net/ipv4/netfilter/Makefile
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile 2004-03-04 06:16:38.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/Makefile 2004-03-04 08:39:55.000000000 +0000
+@@ -42,15 +42,28 @@
+ # 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
+@@ -61,8 +74,10 @@
+
+ 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,6 +94,8 @@
+ obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
++obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_amanda.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_amanda.c 2004-03-04 06:16:50.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_amanda.c 2004-03-04 08:39:18.000000000 +0000
+@@ -46,7 +46,7 @@
+ static int help(struct sk_buff *skb,
+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+ {
+- struct ip_conntrack_expect exp;
++ struct ip_conntrack_expect *exp;
+ struct ip_ct_amanda_expect *exp_amanda_info;
+ char *data, *data_limit, *tmp;
+ unsigned int dataoff, i;
+@@ -79,20 +79,22 @@
+ goto out;
+ data += strlen("CONNECT ");
+
+- memset(&exp, 0, sizeof(exp));
+- exp.tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+- exp.tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+- exp.tuple.dst.protonum = IPPROTO_TCP;
+- exp.mask.src.ip = 0xFFFFFFFF;
+- exp.mask.dst.ip = 0xFFFFFFFF;
+- exp.mask.dst.protonum = 0xFFFF;
+- exp.mask.dst.u.tcp.port = 0xFFFF;
++ if (ip_conntrack_expect_alloc(&exp) < 0)
++ return -ENOMEM;
++
++ exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ exp->tuple.dst.protonum = IPPROTO_TCP;
++ exp->mask.src.ip = 0xFFFFFFFF;
++ exp->mask.dst.ip = 0xFFFFFFFF;
++ exp->mask.dst.protonum = 0xFFFF;
++ exp->mask.dst.u.tcp.port = 0xFFFF;
+
+ /* Only search first line. */
+ if ((tmp = strchr(data, '\n')))
+ *tmp = '\0';
+
+- exp_amanda_info = &exp.help.exp_amanda_info;
++ exp_amanda_info = &exp->help.exp_amanda_info;
+ for (i = 0; i < ARRAY_SIZE(conns); i++) {
+ char *match = strstr(data, conns[i]);
+ if (!match)
+@@ -104,8 +106,8 @@
+ if (exp_amanda_info->port == 0 || exp_amanda_info->len > 5)
+ break;
+
+- exp.tuple.dst.u.tcp.port = htons(exp_amanda_info->port);
+- ip_conntrack_expect_related(ct, &exp);
++ exp->tuple.dst.u.tcp.port = htons(exp_amanda_info->port);
++ ip_conntrack_expect_related(exp, ct);
+ }
+
+ out:
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-04 06:16:34.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-04 08:39:20.000000000 +0000
+@@ -691,42 +691,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 */
+@@ -917,11 +925,53 @@
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ }
+
++int
++ip_conntrack_expect_alloc(struct ip_conntrack_expect **new)
++{
++ *new = (struct ip_conntrack_expect *)
++ kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
++ if (!*new) {
++ DEBUGP("expect_related: OOM allocating expect\n");
++ return -ENOMEM;
++ }
++
++ /* tuple_cmp compares whole union, we have to initialized cleanly */
++ memset(*new, 0, sizeof(struct ip_conntrack_expect));
++
++ return 1;
++}
++
++static void
++ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
++ struct ip_conntrack *related_to)
++{
++ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
++ new->expectant = related_to;
++ new->sibling = NULL;
++ atomic_set(&new->use, 1);
++
++ /* add to expected list for this connection */
++ list_add(&new->expected_list, &related_to->sibling_list);
++ /* add to global list of expectations */
++
++ list_prepend(&ip_conntrack_expect_list, &new->list);
++ /* add and start timer if required */
++ if (related_to->helper->timeout) {
++ init_timer(&new->timeout);
++ new->timeout.data = (unsigned long)new;
++ new->timeout.function = expectation_timed_out;
++ new->timeout.expires = jiffies +
++ related_to->helper->timeout * HZ;
++ add_timer(&new->timeout);
++ }
++ related_to->expecting++;
++}
++
+ /* Add a related connection. */
+-int ip_conntrack_expect_related(struct ip_conntrack *related_to,
+- struct ip_conntrack_expect *expect)
++int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
++ struct ip_conntrack *related_to)
+ {
+- struct ip_conntrack_expect *old, *new;
++ struct ip_conntrack_expect *old;
+ int ret = 0;
+
+ WRITE_LOCK(&ip_conntrack_lock);
+@@ -943,7 +993,7 @@
+ if (related_to->helper->timeout) {
+ if (!del_timer(&old->timeout)) {
+ /* expectation is dying. Fall through */
+- old = NULL;
++ goto out;
+ } else {
+ old->timeout.expires = jiffies +
+ related_to->helper->timeout * HZ;
+@@ -951,10 +1001,10 @@
+ }
+ }
+
+- if (old) {
+- WRITE_UNLOCK(&ip_conntrack_lock);
+- return -EEXIST;
+- }
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ kfree(expect);
++ return -EEXIST;
++
+ } else if (related_to->helper->max_expected &&
+ related_to->expecting >= related_to->helper->max_expected) {
+ struct list_head *cur_item;
+@@ -971,6 +1021,7 @@
+ related_to->helper->name,
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
++ kfree(expect);
+ return -EPERM;
+ }
+ DEBUGP("ip_conntrack: max number of expected "
+@@ -1010,37 +1061,12 @@
+ &expect->mask)) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_related: busy!\n");
++
++ kfree(expect);
+ return -EBUSY;
+ }
+-
+- new = (struct ip_conntrack_expect *)
+- kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
+- if (!new) {
+- WRITE_UNLOCK(&ip_conntrack_lock);
+- DEBUGP("expect_relaed: OOM allocating expect\n");
+- return -ENOMEM;
+- }
+-
+- DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+- memcpy(new, expect, sizeof(*expect));
+- new->expectant = related_to;
+- new->sibling = NULL;
+- atomic_set(&new->use, 1);
+-
+- /* add to expected list for this connection */
+- list_add(&new->expected_list, &related_to->sibling_list);
+- /* add to global list of expectations */
+- list_prepend(&ip_conntrack_expect_list, &new->list);
+- /* add and start timer if required */
+- if (related_to->helper->timeout) {
+- init_timer(&new->timeout);
+- new->timeout.data = (unsigned long)new;
+- new->timeout.function = expectation_timed_out;
+- new->timeout.expires = jiffies +
+- related_to->helper->timeout * HZ;
+- add_timer(&new->timeout);
+- }
+- related_to->expecting++;
++
++out: ip_conntrack_expect_insert(expect, related_to);
+
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_ftp.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-03-04 06:16:55.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-03-04 08:39:18.000000000 +0000
+@@ -256,8 +256,8 @@
+ int dir = CTINFO2DIR(ctinfo);
+ unsigned int matchlen, matchoff;
+ struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+- struct ip_conntrack_expect expect, *exp = &expect;
+- struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
++ struct ip_conntrack_expect *exp;
++ struct ip_ct_ftp_expect *exp_ftp_info;
+
+ unsigned int i;
+ int found = 0;
+@@ -346,8 +346,12 @@
+ DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
+ (int)matchlen, data + matchoff,
+ matchlen, ntohl(tcph.seq) + matchoff);
+-
+- memset(&expect, 0, sizeof(expect));
++
++ /* Allocate expectation which will be inserted */
++ if (ip_conntrack_expect_alloc(&exp) < 0)
++ return -ENOMEM;
++
++ exp_ftp_info = &exp->help.exp_ftp_info;
+
+ /* Update the ftp info */
+ if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
+@@ -389,7 +393,7 @@
+ exp->expectfn = NULL;
+
+ /* Ignore failure; should only happen with NAT */
+- ip_conntrack_expect_related(ct, &expect);
++ ip_conntrack_expect_related(exp, ct);
+ ret = NF_ACCEPT;
+ out:
+ UNLOCK_BH(&ip_ftp_lock);
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_irc.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_irc.c 2004-03-04 06:16:55.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_irc.c 2004-03-04 08:39:18.000000000 +0000
+@@ -106,8 +106,8 @@
+ struct tcphdr tcph;
+ char *data, *data_limit;
+ int dir = CTINFO2DIR(ctinfo);
+- struct ip_conntrack_expect expect, *exp = &expect;
+- struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
++ struct ip_conntrack_expect *exp;
++ struct ip_ct_irc_expect *exp_irc_info = NULL;
+
+ u_int32_t dcc_ip;
+ u_int16_t dcc_port;
+@@ -190,8 +190,11 @@
+
+ continue;
+ }
+-
+- memset(&expect, 0, sizeof(expect));
++
++ if (ip_conntrack_expect_alloc(&exp) < 0)
++ return -ENOMEM;
++
++ exp_irc_info = &exp->help.exp_irc_info;
+
+ /* save position of address in dcc string,
+ * necessary for NAT */
+@@ -218,7 +221,7 @@
+ NIPQUAD(exp->tuple.dst.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
+
+- ip_conntrack_expect_related(ct, &expect);
++ ip_conntrack_expect_related(exp, ct);
+
+ goto out;
+ } /* for .. NUM_DCCPROTO */
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-04 06:16:44.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-04 08:39:18.000000000 +0000
+@@ -591,6 +591,7 @@
+ EXPORT_SYMBOL(ip_ct_find_proto);
+ EXPORT_SYMBOL(__ip_ct_find_proto);
+ EXPORT_SYMBOL(ip_ct_find_helper);
++EXPORT_SYMBOL(ip_conntrack_expect_alloc);
+ EXPORT_SYMBOL(ip_conntrack_expect_related);
+ EXPORT_SYMBOL(ip_conntrack_change_expect);
+ EXPORT_SYMBOL(ip_conntrack_unexpect_related);
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2004-03-04 06:16:44.000000000 +0000
+@@ -0,0 +1,606 @@
++/* This file contains all the functions required for the standalone
++ ip_conntrack module.
++
++ These are not required by the compatibility layer.
++*/
++
++/* (C) 1999-2001 Paul `Rusty' Russell
++ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
++ *
++ * 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/config.h>
++#include <linux/types.h>
++#include <linux/ip.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++#endif
++#include <net/checksum.h>
++
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
++
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++
++static int kill_proto(const struct ip_conntrack *i, void *data)
++{
++ return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
++ *((u_int8_t *) data));
++}
++
++static unsigned int
++print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
++ struct ip_conntrack_protocol *proto)
++{
++ int len;
++
++ len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
++ NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
++
++ len += proto->print_tuple(buffer + len, tuple);
++
++ return len;
++}
++
++/* FIXME: Don't print source proto part. --RR */
++static unsigned int
++print_expect(char *buffer, const struct ip_conntrack_expect *expect)
++{
++ unsigned int len;
++
++ if (expect->expectant->helper->timeout)
++ len = sprintf(buffer, "EXPECTING: %lu ",
++ timer_pending(&expect->timeout)
++ ? (expect->timeout.expires - jiffies)/HZ : 0);
++ else
++ len = sprintf(buffer, "EXPECTING: - ");
++ len += sprintf(buffer + len, "use=%u proto=%u ",
++ atomic_read(&expect->use), expect->tuple.dst.protonum);
++ len += print_tuple(buffer + len, &expect->tuple,
++ __ip_ct_find_proto(expect->tuple.dst.protonum));
++ len += sprintf(buffer + len, "\n");
++ return len;
++}
++
++static unsigned int
++print_conntrack(char *buffer, struct ip_conntrack *conntrack)
++{
++ unsigned int len;
++ struct ip_conntrack_protocol *proto
++ = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.protonum);
++
++ len = sprintf(buffer, "%-8s %u %lu ",
++ proto->name,
++ conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
++ .tuple.dst.protonum,
++ timer_pending(&conntrack->timeout)
++ ? (conntrack->timeout.expires - jiffies)/HZ : 0);
++
++ len += proto->print_conntrack(buffer + len, conntrack);
++ len += print_tuple(buffer + len,
++ &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
++ proto);
++ if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
++ len += sprintf(buffer + len, "[UNREPLIED] ");
++ len += print_tuple(buffer + len,
++ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
++ proto);
++ if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
++ len += sprintf(buffer + len, "[ASSURED] ");
++ len += sprintf(buffer + len, "use=%u ",
++ atomic_read(&conntrack->ct_general.use));
++ len += sprintf(buffer + len, "\n");
++
++ return len;
++}
++
++/* Returns true when finished. */
++static inline int
++conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
++ char *buffer, off_t offset, off_t *upto,
++ unsigned int *len, unsigned int maxlen)
++{
++ unsigned int newlen;
++ IP_NF_ASSERT(hash->ctrack);
++
++ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
++
++ /* Only count originals */
++ if (DIRECTION(hash))
++ return 0;
++
++ if ((*upto)++ < offset)
++ return 0;
++
++ newlen = print_conntrack(buffer + *len, hash->ctrack);
++ if (*len + newlen > maxlen)
++ return 1;
++ else *len += newlen;
++
++ return 0;
++}
++
++static int
++list_conntracks(char *buffer, char **start, off_t offset, int length)
++{
++ unsigned int i;
++ unsigned int len = 0;
++ off_t upto = 0;
++ struct list_head *e;
++
++ READ_LOCK(&ip_conntrack_lock);
++ /* Traverse hash; print originals then reply. */
++ for (i = 0; i < ip_conntrack_htable_size; i++) {
++ if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
++ struct ip_conntrack_tuple_hash *,
++ buffer, offset, &upto, &len, length))
++ goto finished;
++ }
++
++ /* Now iterate through expecteds. */
++ READ_LOCK(&ip_conntrack_expect_tuple_lock);
++ list_for_each(e, &ip_conntrack_expect_list) {
++ unsigned int last_len;
++ struct ip_conntrack_expect *expect
++ = (struct ip_conntrack_expect *)e;
++ if (upto++ < offset) continue;
++
++ last_len = len;
++ len += print_expect(buffer + len, expect);
++ if (len > length) {
++ len = last_len;
++ goto finished_expects;
++ }
++ }
++
++ finished_expects:
++ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
++ finished:
++ READ_UNLOCK(&ip_conntrack_lock);
++
++ /* `start' hack - see fs/proc/generic.c line ~165 */
++ *start = (char *)((unsigned int)upto - offset);
++ return len;
++}
++
++static unsigned int ip_confirm(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ /* We've seen it coming out the other side: confirm it */
++ return ip_conntrack_confirm(*pskb);
++}
++
++static unsigned int ip_refrag(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ struct rtable *rt = (struct rtable *)(*pskb)->dst;
++
++ /* We've seen it coming out the other side: confirm */
++ if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
++ return NF_DROP;
++
++ /* Local packets are never produced too large for their
++ interface. We degfragment them at LOCAL_OUT, however,
++ so we have to refragment them here. */
++ if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
++ !skb_shinfo(*pskb)->tso_size) {
++ /* No hook can be after us, so this should be OK. */
++ ip_fragment(*pskb, okfn);
++ return NF_STOLEN;
++ }
++ return NF_ACCEPT;
++}
++
++static unsigned int ip_conntrack_local(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ /* root is playing with raw sockets. */
++ if ((*pskb)->len < sizeof(struct iphdr)
++ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
++ if (net_ratelimit())
++ printk("ipt_hook: happy cracking.\n");
++ return NF_ACCEPT;
++ }
++ return ip_conntrack_in(hooknum, pskb, in, out, okfn);
++}
++
++/* Connection tracking may drop packets, but never alters them, so
++ make it the first hook. */
++static struct nf_hook_ops ip_conntrack_in_ops = {
++ .hook = ip_conntrack_in,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_PRE_ROUTING,
++ .priority = NF_IP_PRI_CONNTRACK,
++};
++
++static struct nf_hook_ops ip_conntrack_local_out_ops = {
++ .hook = ip_conntrack_local,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_LOCAL_OUT,
++ .priority = NF_IP_PRI_CONNTRACK,
++};
++
++/* Refragmenter; last chance. */
++static struct nf_hook_ops ip_conntrack_out_ops = {
++ .hook = ip_refrag,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_POST_ROUTING,
++ .priority = NF_IP_PRI_LAST,
++};
++
++static struct nf_hook_ops ip_conntrack_local_in_ops = {
++ .hook = ip_confirm,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_LOCAL_IN,
++ .priority = NF_IP_PRI_LAST-1,
++};
++
++/* Sysctl support */
++
++#ifdef CONFIG_SYSCTL
++
++/* From ip_conntrack_core.c */
++extern int ip_conntrack_max;
++extern unsigned int ip_conntrack_htable_size;
++
++/* From ip_conntrack_proto_tcp.c */
++extern unsigned long ip_ct_tcp_timeout_syn_sent;
++extern unsigned long ip_ct_tcp_timeout_syn_recv;
++extern unsigned long ip_ct_tcp_timeout_established;
++extern unsigned long ip_ct_tcp_timeout_fin_wait;
++extern unsigned long ip_ct_tcp_timeout_close_wait;
++extern unsigned long ip_ct_tcp_timeout_last_ack;
++extern unsigned long ip_ct_tcp_timeout_time_wait;
++extern unsigned long ip_ct_tcp_timeout_close;
++
++/* From ip_conntrack_proto_udp.c */
++extern unsigned long ip_ct_udp_timeout;
++extern unsigned long ip_ct_udp_timeout_stream;
++
++/* From ip_conntrack_proto_icmp.c */
++extern unsigned long ip_ct_icmp_timeout;
++
++/* From ip_conntrack_proto_icmp.c */
++extern unsigned long ip_ct_generic_timeout;
++
++static struct ctl_table_header *ip_ct_sysctl_header;
++
++static ctl_table ip_ct_sysctl_table[] = {
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
++ .procname = "ip_conntrack_max",
++ .data = &ip_conntrack_max,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
++ .procname = "ip_conntrack_buckets",
++ .data = &ip_conntrack_htable_size,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0444,
++ .proc_handler = &proc_dointvec,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
++ .procname = "ip_conntrack_tcp_timeout_syn_sent",
++ .data = &ip_ct_tcp_timeout_syn_sent,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
++ .procname = "ip_conntrack_tcp_timeout_syn_recv",
++ .data = &ip_ct_tcp_timeout_syn_recv,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
++ .procname = "ip_conntrack_tcp_timeout_established",
++ .data = &ip_ct_tcp_timeout_established,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
++ .procname = "ip_conntrack_tcp_timeout_fin_wait",
++ .data = &ip_ct_tcp_timeout_fin_wait,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
++ .procname = "ip_conntrack_tcp_timeout_close_wait",
++ .data = &ip_ct_tcp_timeout_close_wait,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
++ .procname = "ip_conntrack_tcp_timeout_last_ack",
++ .data = &ip_ct_tcp_timeout_last_ack,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
++ .procname = "ip_conntrack_tcp_timeout_time_wait",
++ .data = &ip_ct_tcp_timeout_time_wait,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
++ .procname = "ip_conntrack_tcp_timeout_close",
++ .data = &ip_ct_tcp_timeout_close,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
++ .procname = "ip_conntrack_udp_timeout",
++ .data = &ip_ct_udp_timeout,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
++ .procname = "ip_conntrack_udp_timeout_stream",
++ .data = &ip_ct_udp_timeout_stream,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
++ .procname = "ip_conntrack_icmp_timeout",
++ .data = &ip_ct_icmp_timeout,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ {
++ .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
++ .procname = "ip_conntrack_generic_timeout",
++ .data = &ip_ct_generic_timeout,
++ .maxlen = sizeof(unsigned int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec_jiffies,
++ },
++ { .ctl_name = 0 }
++};
++
++#define NET_IP_CONNTRACK_MAX 2089
++
++static ctl_table ip_ct_netfilter_table[] = {
++ {
++ .ctl_name = NET_IPV4_NETFILTER,
++ .procname = "netfilter",
++ .mode = 0555,
++ .child = ip_ct_sysctl_table,
++ },
++ {
++ .ctl_name = NET_IP_CONNTRACK_MAX,
++ .procname = "ip_conntrack_max",
++ .data = &ip_conntrack_max,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec
++ },
++ { .ctl_name = 0 }
++};
++
++static ctl_table ip_ct_ipv4_table[] = {
++ {
++ .ctl_name = NET_IPV4,
++ .procname = "ipv4",
++ .mode = 0555,
++ .child = ip_ct_netfilter_table,
++ },
++ { .ctl_name = 0 }
++};
++
++static ctl_table ip_ct_net_table[] = {
++ {
++ .ctl_name = CTL_NET,
++ .procname = "net",
++ .mode = 0555,
++ .child = ip_ct_ipv4_table,
++ },
++ { .ctl_name = 0 }
++};
++#endif
++static int init_or_cleanup(int init)
++{
++ struct proc_dir_entry *proc;
++ int ret = 0;
++
++ if (!init) goto cleanup;
++
++ ret = ip_conntrack_init();
++ if (ret < 0)
++ goto cleanup_nothing;
++
++ proc = proc_net_create("ip_conntrack",0,list_conntracks);
++ if (!proc) goto cleanup_init;
++ proc->owner = THIS_MODULE;
++
++ ret = nf_register_hook(&ip_conntrack_in_ops);
++ if (ret < 0) {
++ printk("ip_conntrack: can't register pre-routing hook.\n");
++ goto cleanup_proc;
++ }
++ ret = nf_register_hook(&ip_conntrack_local_out_ops);
++ if (ret < 0) {
++ printk("ip_conntrack: can't register local out hook.\n");
++ goto cleanup_inops;
++ }
++ ret = nf_register_hook(&ip_conntrack_out_ops);
++ if (ret < 0) {
++ printk("ip_conntrack: can't register post-routing hook.\n");
++ goto cleanup_inandlocalops;
++ }
++ ret = nf_register_hook(&ip_conntrack_local_in_ops);
++ if (ret < 0) {
++ printk("ip_conntrack: can't register local in hook.\n");
++ goto cleanup_inoutandlocalops;
++ }
++#ifdef CONFIG_SYSCTL
++ ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
++ if (ip_ct_sysctl_header == NULL) {
++ printk("ip_conntrack: can't register to sysctl.\n");
++ goto cleanup;
++ }
++#endif
++
++ return ret;
++
++ cleanup:
++#ifdef CONFIG_SYSCTL
++ unregister_sysctl_table(ip_ct_sysctl_header);
++#endif
++ nf_unregister_hook(&ip_conntrack_local_in_ops);
++ cleanup_inoutandlocalops:
++ nf_unregister_hook(&ip_conntrack_out_ops);
++ cleanup_inandlocalops:
++ nf_unregister_hook(&ip_conntrack_local_out_ops);
++ cleanup_inops:
++ nf_unregister_hook(&ip_conntrack_in_ops);
++ cleanup_proc:
++ proc_net_remove("ip_conntrack");
++ cleanup_init:
++ ip_conntrack_cleanup();
++ cleanup_nothing:
++ return ret;
++}
++
++/* FIXME: Allow NULL functions and sub in pointers to generic for
++ them. --RR */
++int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
++{
++ int ret = 0;
++ struct list_head *i;
++
++ WRITE_LOCK(&ip_conntrack_lock);
++ list_for_each(i, &protocol_list) {
++ if (((struct ip_conntrack_protocol *)i)->proto
++ == proto->proto) {
++ ret = -EBUSY;
++ goto out;
++ }
++ }
++
++ list_prepend(&protocol_list, proto);
++
++ out:
++ WRITE_UNLOCK(&ip_conntrack_lock);
++ return ret;
++}
++
++void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
++{
++ WRITE_LOCK(&ip_conntrack_lock);
++
++ /* ip_ct_find_proto() returns proto_generic in case there is no protocol
++ * helper. So this should be enough - HW */
++ LIST_DELETE(&protocol_list, proto);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ /* Somebody could be still looking at the proto in bh. */
++ synchronize_net();
++
++ /* Remove all contrack entries for this protocol */
++ ip_ct_selective_cleanup(kill_proto, &proto->proto);
++}
++
++static int __init init(void)
++{
++ return init_or_cleanup(1);
++}
++
++static void __exit fini(void)
++{
++ init_or_cleanup(0);
++}
++
++module_init(init);
++module_exit(fini);
++
++/* Some modules need us, but don't depend directly on any symbol.
++ They should call this. */
++void need_ip_conntrack(void)
++{
++}
++
++EXPORT_SYMBOL(ip_conntrack_protocol_register);
++EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
++EXPORT_SYMBOL(invert_tuplepr);
++EXPORT_SYMBOL(ip_conntrack_alter_reply);
++EXPORT_SYMBOL(ip_conntrack_destroyed);
++EXPORT_SYMBOL(ip_conntrack_get);
++EXPORT_SYMBOL(need_ip_conntrack);
++EXPORT_SYMBOL(ip_conntrack_helper_register);
++EXPORT_SYMBOL(ip_conntrack_helper_unregister);
++EXPORT_SYMBOL(ip_ct_selective_cleanup);
++EXPORT_SYMBOL(ip_ct_refresh);
++EXPORT_SYMBOL(ip_ct_find_proto);
++EXPORT_SYMBOL(__ip_ct_find_proto);
++EXPORT_SYMBOL(ip_ct_find_helper);
++EXPORT_SYMBOL(ip_conntrack_expect_related);
++EXPORT_SYMBOL(ip_conntrack_change_expect);
++EXPORT_SYMBOL(ip_conntrack_unexpect_related);
++EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
++EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
++EXPORT_SYMBOL(ip_conntrack_tuple_taken);
++EXPORT_SYMBOL(ip_ct_gather_frags);
++EXPORT_SYMBOL(ip_conntrack_htable_size);
++EXPORT_SYMBOL(ip_conntrack_expect_list);
++EXPORT_SYMBOL(ip_conntrack_lock);
++EXPORT_SYMBOL(ip_conntrack_hash);
++EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
++EXPORT_SYMBOL_GPL(ip_conntrack_put);
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_tftp.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_tftp.c 2004-03-04 06:16:41.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_tftp.c 2004-03-04 08:39:18.000000000 +0000
+@@ -44,7 +44,7 @@
+ enum ip_conntrack_info ctinfo)
+ {
+ struct tftphdr tftph;
+- struct ip_conntrack_expect exp;
++ struct ip_conntrack_expect *exp;
+
+ if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
+ &tftph, sizeof(tftph)) != 0)
+@@ -57,19 +57,21 @@
+ DEBUGP("");
+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+- memset(&exp, 0, sizeof(exp));
+
+- exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+- exp.mask.src.ip = 0xffffffff;
+- exp.mask.dst.ip = 0xffffffff;
+- exp.mask.dst.u.udp.port = 0xffff;
+- exp.mask.dst.protonum = 0xffff;
+- exp.expectfn = NULL;
++ if (ip_conntrack_expect_alloc(&exp) < 0)
++ return -ENOMEM;
++
++ exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
++ exp->mask.src.ip = 0xffffffff;
++ exp->mask.dst.ip = 0xffffffff;
++ exp->mask.dst.u.udp.port = 0xffff;
++ exp->mask.dst.protonum = 0xffff;
++ exp->expectfn = NULL;
+
+ DEBUGP("expect: ");
+- DUMP_TUPLE(&exp.tuple);
+- DUMP_TUPLE(&exp.mask);
+- ip_conntrack_expect_related(ct, &exp);
++ DUMP_TUPLE(&exp->tuple);
++ DUMP_TUPLE(&exp->mask);
++ ip_conntrack_expect_related(exp, ct);
+ break;
+ default:
+ DEBUGP("Unknown opcode\n");
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-03-04 08:39:26.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c 2004-03-04 08:39:28.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c 2004-03-04 08:39:29.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c 2004-03-04 08:39:31.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c 2004-03-04 08:39:33.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c 2004-03-04 08:39:34.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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c 2004-03-04 08:39:36.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("a_lock);
++
++ if (q->quota >= datalen) {
++ /* we can afford this one */
++ q->quota -= datalen;
++ spin_unlock_bh("a_lock);
++
++#ifdef DEBUG_IPT_QUOTA
++ printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
++#endif
++ return 1;
++ }
++
++ /* so we do not allow even small packets from now on */
++ q->quota = 0;
++
++#ifdef DEBUG_IPT_QUOTA
++ printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
++#endif
++
++ spin_unlock_bh("a_lock);
++ return 0;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ /* TODO: spinlocks? sanity checks? */
++ 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("a_match);
++}
++
++static void __exit
++fini(void)
++{
++ ipt_unregister_match("a_match);
++}
++
++module_init(init);
++module_exit(fini);
++
+diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c 2004-03-04 08:39:54.000000000 +0000
+@@ -0,0 +1,70 @@
++/* Kernel module to match realm from routing. */
++#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;
++ u32 id;
++
++ if(dst == NULL)
++ return 0;
++ id = dst->tclassid;
++
++ return (info->id == (id & 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 linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c
+--- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c 2004-03-04 08:39:55.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 linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig 2004-03-04 06:17:03.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig 2004-03-04 08:39:34.000000000 +0000
+@@ -218,5 +218,25 @@
+ 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_HOPLIMIT
++ tristate 'HOPLIMIT 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
++
+ endmenu
+
+diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile linux-2.6.4-rc2/net/ipv6/netfilter/Makefile
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile 2004-03-04 06:16:48.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/Makefile 2004-03-04 08:39:34.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,10 @@
+ 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_MATCH_NTH) += ip6t_nth.o
++obj-$(CONFIG_IP6_NF_TARGET_HOPLIMIT) += ip6t_HL.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c 2004-03-04 08:39:25.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_HOPLIMIT_info *info = targinfo;
++ u_int16_t diffs[2];
++ int new_hl;
++
++ switch (info->mode) {
++ case IP6T_HOPLIMIT_SET:
++ new_hl = info->hop_limit;
++ break;
++ case IP6T_HOPLIMIT_INC:
++ new_hl = ip6h->hop_limit + info->hop_limit;
++ if (new_hl > 255)
++ new_hl = 255;
++ break;
++ case IP6T_HOPLIMIT_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_HOPLIMIT_info *info = targinfo;
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HOPLIMIT_info))) {
++ printk(KERN_WARNING "HOPLIMIT: targinfosize %u != %Zu\n",
++ targinfosize,
++ IP6T_ALIGN(sizeof(struct ip6t_HOPLIMIT_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "HOPLIMIT: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ if (info->mode > IP6T_HOPLIMIT_MAXMODE) {
++ printk(KERN_WARNING "HOPLIMIT: invalid or unknown Mode %u\n",
++ info->mode);
++ return 0;
++ }
++
++ if ((info->mode != IP6T_HOPLIMIT_SET) && (info->hop_limit == 0)) {
++ printk(KERN_WARNING "HOPLIMIT: increment/decrement doesn't make sense with value 0\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_HOPLIMIT = { { NULL, NULL }, "HL",
++ ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ip6t_register_target(&ip6t_HOPLIMIT);
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_HOPLIMIT);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c 2004-03-04 08:39:28.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 linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c 2004-03-04 08:39:30.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 linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c
+--- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c 2004-03-04 08:39:34.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);