--- /dev/null
+ Netfilter SNAP 20040608
+ included:
+ updates/01_iptables-1.2.10
+ updates/02_linux-2.6.4
+ updates/04_linux-2.6.6-helper_reassign
+ updates/05_linux-2.6.6-orphaned_expect
+ PENDING/expect-evict-order
+ PENDING/expect-slab-cache
+ PENDING/init_conntrack-optimize
+ PENDING/ipt_helper-invert-fix
+ PENDING/mangle-reroute
+ PENDING/nf-log
+ PENDING/nf_reset
+ PENDING/proc-no-internal-targets
+ PENDING/proc_net_conntrack-permissions
+ BASE/HOPLIMIT
+ BASE/IPV4OPTSSTRING
+ BASE/NETLINK // fix socket -> sk_socket
+ BASE/REJECT
+ BASE/TTL
+ BASE/connlimit
+ BASE/dstlimit
+ BASE/fuzzy
+ BASE/ipv4options
+ BASE/mport
+ BASE/nth
+ BASE/osf // fix socket -> sk_socket
+ BASE/pool // added EXPORT_SYMBOL(ip_pool_mod, ip_pool_match)
+ BASE/psd
+ BASE/quota
+ BASE/random
+ BASE/raw // removed linux-2.6.patch - included in kernel
+ BASE/realm
+ BASE/sctp
+ BASE/time
+ BASE/u32
+ EXTRA/CONNMARK
+ EXTRA/IPMARK
+ EXTRA/ROUTE
+ EXTRA/TARPIT
+ EXTRA/TRACE // ip_output.c fix
+ EXTRA/XOR
+ EXTRA/addrtype
+ EXTRA/eggdrop-conntrack
+ EXTRA/h323-conntrack-nat
+ EXTRA/ipsec-01-output-hooks // fixed
+ EXTRA/ipsec-02-input-hooks
+ EXTRA/ipsec-03-policy-lookup
+ EXTRA/ipsec-04-policy-check
+ EXTRA/ipt_helper-any
+ EXTRA/mms-conntrack-nat
+ EXTRA/owner-socketlookup
+ EXTRA/ownercmd
+ EXTRA/policy
+ EXTRA/quake3-conntrack-nat
+ EXTRA/rsh
+ EXTRA/rtsp-conntrack
+ EXTRA/sctp-conntrack-nat
+ EXTRA/string // required unclean module - included - req fix
+ EXTRA/talk-conntrack-nat
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter.h linux-2.6.7-rc3/include/linux/netfilter.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter.h 2004-06-07 21:14:24.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter.h 2004-06-08 10:38:46.000000000 +0200
+@@ -23,6 +23,7 @@
+ <= 0x2000 is used for protocol-flags. */
+ #define NFC_UNKNOWN 0x4000
+ #define NFC_ALTERED 0x8000
++#define NFC_TRACE 0x10000
+
+ #ifdef __KERNEL__
+ #include <linux/config.h>
+@@ -137,12 +138,14 @@
+ /* This is gross, but inline doesn't cut it for avoiding the function
+ call in fast path: gcc doesn't inline (needs value tracking?). --RR */
+ #ifdef CONFIG_NETFILTER_DEBUG
+-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
+- nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)
++#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
++(!(cond) \
++ ? (okfn)(skb) \
++ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN))
+ #define NF_HOOK_THRESH nf_hook_slow
+ #else
+-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
+-(list_empty(&nf_hooks[(pf)][(hook)]) \
++#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
++(!(cond) || list_empty(&nf_hooks[(pf)][(hook)]) \
+ ? (okfn)(skb) \
+ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN))
+ #define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
+@@ -150,6 +153,8 @@
+ ? (okfn)(skb) \
+ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), (thresh)))
+ #endif
++#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
++ NF_HOOK_COND((pf), (hook), (skb), (indev), (outdev), (okfn), 1)
+
+ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+ struct net_device *indev, struct net_device *outdev,
+@@ -188,7 +193,24 @@
+
+ #else /* !CONFIG_NETFILTER */
+ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
++#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
+ #endif /*CONFIG_NETFILTER*/
+
++#ifdef CONFIG_XFRM
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++struct flowi;
++extern void nf_nat_decode_session4(struct sk_buff *skb, struct flowi *fl);
++
++static inline void
++nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family)
++{
++ if (family == AF_INET)
++ nf_nat_decode_session4(skb, fl);
++}
++#else /* CONFIG_IP_NF_NAT_NEEDED */
++#define nf_nat_decode_session(skb,fl,family)
++#endif /* CONFIG_IP_NF_NAT_NEEDED */
++#endif /* CONFIG_XFRM */
++
+ #endif /*__KERNEL__*/
+ #endif /*__LINUX_NETFILTER_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_helpers.h linux-2.6.7-rc3/include/linux/netfilter_helpers.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_helpers.h 2004-06-08 10:40:46.000000000 +0200
+@@ -0,0 +1,133 @@
++/*
++ * Helpers for netfiler modules. This file provides implementations for basic
++ * functions such as strncasecmp(), etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested. The following macros are used:
++ * NF_NEED_STRNCASECMP nf_strncasecmp()
++ * NF_NEED_STRTOU16 nf_strtou16()
++ * NF_NEED_STRTOU32 nf_strtou32()
++ */
++#ifndef _NETFILTER_HELPERS_H
++#define _NETFILTER_HELPERS_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++#define iseol(c) ( (c) == '\r' || (c) == '\n' )
++
++/*
++ * The standard strncasecmp()
++ */
++#ifdef NF_NEED_STRNCASECMP
++static int
++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
++{
++ if (s1 == NULL || s2 == NULL)
++ {
++ if (s1 == NULL && s2 == NULL)
++ {
++ return 0;
++ }
++ return (s1 == NULL) ? -1 : 1;
++ }
++ while (len > 0 && tolower(*s1) == tolower(*s2))
++ {
++ len--;
++ s1++;
++ s2++;
++ }
++ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
++}
++#endif /* NF_NEED_STRNCASECMP */
++
++/*
++ * Parse a string containing a 16-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU16
++static int
++nf_strtou16(const char* pbuf, u_int16_t* pval)
++{
++ int n = 0;
++
++ *pval = 0;
++ while (isdigit(pbuf[n]))
++ {
++ *pval = (*pval * 10) + (pbuf[n] - '0');
++ n++;
++ }
++
++ return n;
++}
++#endif /* NF_NEED_STRTOU16 */
++
++/*
++ * Parse a string containing a 32-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU32
++static int
++nf_strtou32(const char* pbuf, u_int32_t* pval)
++{
++ int n = 0;
++
++ *pval = 0;
++ while (pbuf[n] >= '0' && pbuf[n] <= '9')
++ {
++ *pval = (*pval * 10) + (pbuf[n] - '0');
++ n++;
++ }
++
++ return n;
++}
++#endif /* NF_NEED_STRTOU32 */
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.
++ */
++#ifdef NF_NEED_NEXTLINE
++static int
++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++ uint off = *poff;
++ uint physlen = 0;
++
++ if (off >= len)
++ {
++ return 0;
++ }
++
++ while (p[off] != '\n')
++ {
++ if (len-off <= 1)
++ {
++ return 0;
++ }
++
++ physlen++;
++ off++;
++ }
++
++ /* if we saw a crlf, physlen needs adjusted */
++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++ {
++ physlen--;
++ }
++
++ /* advance past the newline */
++ off++;
++
++ *plineoff = *poff;
++ *plinelen = physlen;
++ *poff = off;
++
++ return 1;
++}
++#endif /* NF_NEED_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_HELPERS_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-06-07 21:14:59.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack.h 2004-06-08 10:41:27.000000000 +0200
+@@ -51,10 +51,12 @@
+
+ #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>
+
+ /* per conntrack: protocol private data */
+ union ip_conntrack_proto {
+ /* insert conntrack proto private data here */
++ struct ip_ct_sctp sctp;
+ struct ip_ct_tcp tcp;
+ struct ip_ct_icmp icmp;
+ };
+@@ -64,6 +66,11 @@
+ };
+
+ /* Add protocol helper include file here */
++#include <linux/netfilter_ipv4/ip_conntrack_talk.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rsh.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+@@ -71,6 +78,11 @@
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+ /* insert conntrack helper private data (expect) here */
++ struct ip_ct_talk_expect exp_talk_info;
++ struct ip_ct_rtsp_expect exp_rtsp_info;
++ struct ip_ct_rsh_expect exp_rsh_info;
++ struct ip_ct_mms_expect exp_mms_info;
++ struct ip_ct_h225_expect exp_h225_info;
+ struct ip_ct_amanda_expect exp_amanda_info;
+ struct ip_ct_ftp_expect exp_ftp_info;
+ struct ip_ct_irc_expect exp_irc_info;
+@@ -85,6 +97,11 @@
+ /* per conntrack: application helper private data */
+ union ip_conntrack_help {
+ /* insert conntrack helper private data (master) here */
++ struct ip_ct_talk_master ct_talk_info;
++ struct ip_ct_rtsp_master ct_rtsp_info;
++ struct ip_ct_rsh_master ct_rsh_info;
++ struct ip_ct_mms_master ct_mms_info;
++ struct ip_ct_h225_master ct_h225_info;
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
+ };
+@@ -207,6 +224,10 @@
+ } nat;
+ #endif /* CONFIG_IP_NF_NAT_NEEDED */
+
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++ unsigned long mark;
++#endif
++
+ };
+
+ /* get master conntrack via master expectation */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2004-06-08 10:38:40.000000000 +0200
+@@ -0,0 +1,31 @@
++#ifndef _IP_CONNTRACK_H323_H
++#define _IP_CONNTRACK_H323_H
++/* H.323 connection tracking. */
++
++#ifdef __KERNEL__
++/* Protects H.323 related data */
++#include <linux/netfilter_ipv4/lockhelp.h>
++DECLARE_LOCK_EXTERN(ip_h323_lock);
++#endif
++
++/* Default H.225 port */
++#define H225_PORT 1720
++
++/* This structure is per expected connection */
++struct ip_ct_h225_expect {
++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */
++ enum ip_conntrack_dir dir; /* Direction of the original connection */
++ unsigned int offset; /* offset of the address in the payload */
++};
++
++/* This structure exists only once per master */
++struct ip_ct_h225_master {
++ int is_h225; /* H.225 or H.245 connection */
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ enum ip_conntrack_dir dir; /* Direction of the original connection */
++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */
++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */
++#endif
++};
++
++#endif /* _IP_CONNTRACK_H323_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_mms.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2004-06-08 10:39:44.000000000 +0200
+@@ -0,0 +1,31 @@
++#ifndef _IP_CONNTRACK_MMS_H
++#define _IP_CONNTRACK_MMS_H
++/* MMS tracking. */
++
++#ifdef __KERNEL__
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++DECLARE_LOCK_EXTERN(ip_mms_lock);
++
++#define MMS_PORT 1755
++#define MMS_SRV_MSG_ID 196610
++
++#define MMS_SRV_MSG_OFFSET 36
++#define MMS_SRV_UNICODE_STRING_OFFSET 60
++#define MMS_SRV_CHUNKLENLV_OFFSET 16
++#define MMS_SRV_CHUNKLENLM_OFFSET 32
++#define MMS_SRV_MESSAGELENGTH_OFFSET 8
++#endif
++
++/* This structure is per expected connection */
++struct ip_ct_mms_expect {
++ u_int32_t len;
++ u_int32_t padding;
++ u_int16_t port;
++};
++
++/* This structure exists only once per master */
++struct ip_ct_mms_master {
++};
++
++#endif /* _IP_CONNTRACK_MMS_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_quake3.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_quake3.h 2004-06-08 10:40:36.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IP_CT_QUAKE3
++#define _IP_CT_QUAKE3
++
++/* Don't confuse with 27960, often used as the Server Port */
++#define QUAKE3_MASTER_PORT 27950
++
++struct quake3_search {
++ const char marker[4]; /* always 0xff 0xff 0xff 0xff ? */
++ const char *pattern;
++ size_t plen;
++};
++
++/* This structure is per expected connection */
++struct ip_ct_quake3_expect {
++};
++
++/* This structure exists only once per master */
++struct ip_ct_quake3_master {
++};
++
++#endif /* _IP_CT_QUAKE3 */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_rsh.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_rsh.h 2004-06-08 10:40:43.000000000 +0200
+@@ -0,0 +1,35 @@
++/* RSH extension for IP connection tracking, Version 1.0
++ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ * based on HW's ip_conntrack_irc.c
++ *
++ * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#ifndef _IP_CONNTRACK_RSH_H
++#define _IP_CONNTRACK_RSH_H
++
++#ifdef __KERNEL__
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++DECLARE_LOCK_EXTERN(ip_rsh_lock);
++#endif
++
++
++#define RSH_PORT 514
++
++/* This structure is per expected connection */
++struct ip_ct_rsh_expect
++{
++ u_int16_t port;
++};
++
++/* This structure exists only once per master */
++struct ip_ct_rsh_master {
++};
++
++#endif /* _IP_CONNTRACK_RSH_H */
++
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2004-06-08 10:40:46.000000000 +0200
+@@ -0,0 +1,68 @@
++/*
++ * RTSP extension for IP connection tracking.
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.h
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#ifndef _IP_CONNTRACK_RTSP_H
++#define _IP_CONNTRACK_RTSP_H
++
++/* #define IP_NF_RTSP_DEBUG */
++#define IP_NF_RTSP_VERSION "0.01"
++
++/* port block types */
++typedef enum {
++ pb_single, /* client_port=x */
++ pb_range, /* client_port=x-y */
++ pb_discon /* client_port=x/y (rtspbis) */
++} portblock_t;
++
++/* We record seq number and length of rtsp headers here, all in host order. */
++
++/*
++ * This structure is per expected connection. It is a member of struct
++ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored
++ * there and we are expected to only store the length of the data which
++ * needs replaced. If a packet contains multiple RTSP messages, we create
++ * one expected connection per message.
++ *
++ * We use these variables to mark the entire header block. This may seem
++ * like overkill, but the nature of RTSP requires it. A header may appear
++ * multiple times in a message. We must treat two Transport headers the
++ * same as one Transport header with two entries.
++ */
++struct ip_ct_rtsp_expect
++{
++ u_int32_t len; /* length of header block */
++ portblock_t pbtype; /* Type of port block that was requested */
++ u_int16_t loport; /* Port that was requested, low or first */
++ u_int16_t hiport; /* Port that was requested, high or second */
++#if 0
++ uint method; /* RTSP method */
++ uint cseq; /* CSeq from request */
++#endif
++};
++
++/* This structure exists only once per master */
++struct ip_ct_rtsp_master
++{
++ /* Empty (?) */
++};
++
++
++#ifdef __KERNEL__
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++#define RTSP_PORT 554
++
++/* Protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#endif /* __KERNEL__ */
++
++#endif /* _IP_CONNTRACK_RTSP_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_sctp.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_sctp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_sctp.h 2004-06-08 10:40:55.000000000 +0200
+@@ -0,0 +1,25 @@
++#ifndef _IP_CONNTRACK_SCTP_H
++#define _IP_CONNTRACK_SCTP_H
++/* SCTP tracking. */
++
++enum sctp_conntrack {
++ SCTP_CONNTRACK_NONE,
++ SCTP_CONNTRACK_CLOSED,
++ SCTP_CONNTRACK_COOKIE_WAIT,
++ SCTP_CONNTRACK_COOKIE_ECHOED,
++ SCTP_CONNTRACK_ESTABLISHED,
++ SCTP_CONNTRACK_SHUTDOWN_SENT,
++ SCTP_CONNTRACK_SHUTDOWN_RECD,
++ SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
++ SCTP_CONNTRACK_MAX
++};
++
++struct ip_ct_sctp
++{
++ enum sctp_conntrack state;
++
++ u_int32_t vtag[IP_CT_DIR_MAX];
++ u_int32_t ttag[IP_CT_DIR_MAX];
++};
++
++#endif /* _IP_CONNTRACK_SCTP_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_talk.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_talk.h 2004-06-08 10:41:27.000000000 +0200
+@@ -0,0 +1,152 @@
++#ifndef _IP_CONNTRACK_TALK_H
++#define _IP_CONNTRACK_TALK_H
++/* TALK tracking. */
++
++#ifdef __KERNEL__
++#include <linux/in.h>
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++/* Protects talk part of conntracks */
++DECLARE_LOCK_EXTERN(ip_talk_lock);
++#endif
++
++
++#define TALK_PORT 517
++#define NTALK_PORT 518
++
++/* talk structures and constants from <protocols/talkd.h> */
++
++/*
++ * 4.3BSD struct sockaddr
++ */
++struct talk_addr {
++ u_int16_t ta_family;
++ u_int16_t ta_port;
++ u_int32_t ta_addr;
++ u_int32_t ta_junk1;
++ u_int32_t ta_junk2;
++};
++
++#define TALK_OLD_NSIZE 9
++#define TALK_NSIZE 12
++#define TALK_TTY_NSIZE 16
++
++/*
++ * Client->server request message formats.
++ */
++struct talk_msg {
++ u_char type; /* request type, see below */
++ char l_name[TALK_OLD_NSIZE];/* caller's name */
++ char r_name[TALK_OLD_NSIZE];/* callee's name */
++ u_char pad;
++ u_int32_t id_num; /* message id */
++ int32_t pid; /* caller's process id */
++ char r_tty[TALK_TTY_NSIZE];/* callee's tty name */
++ struct talk_addr addr; /* old (4.3) style */
++ struct talk_addr ctl_addr; /* old (4.3) style */
++};
++
++struct ntalk_msg {
++ u_char vers; /* protocol version */
++ u_char type; /* request type, see below */
++ u_char answer; /* not used */
++ u_char pad;
++ u_int32_t id_num; /* message id */
++ struct talk_addr addr; /* old (4.3) style */
++ struct talk_addr ctl_addr; /* old (4.3) style */
++ int32_t pid; /* caller's process id */
++ char l_name[TALK_NSIZE];/* caller's name */
++ char r_name[TALK_NSIZE];/* callee's name */
++ char r_tty[TALK_TTY_NSIZE];/* callee's tty name */
++};
++
++struct ntalk2_msg {
++ u_char vers; /* talk protocol version */
++ u_char type; /* request type */
++ u_char answer; /* */
++ u_char extended; /* !0 if additional parts */
++ u_int32_t id_num; /* message id number (dels) */
++ struct talk_addr addr; /* target address */
++ struct talk_addr ctl_addr; /* reply to address */
++ int32_t pid; /* caller's process id */
++ char l_name[TALK_NSIZE]; /* caller's name */
++ char r_name[TALK_NSIZE]; /* callee's name */
++ char r_tty[TALK_TTY_NSIZE]; /* callee's tty */
++};
++
++/*
++ * Server->client response message formats.
++ */
++struct talk_response {
++ u_char type; /* type of request message, see below */
++ u_char answer; /* response to request message, see below */
++ u_char pad[2];
++ u_int32_t id_num; /* message id */
++ struct talk_addr addr; /* address for establishing conversation */
++};
++
++struct ntalk_response {
++ u_char vers; /* protocol version */
++ u_char type; /* type of request message, see below */
++ u_char answer; /* response to request message, see below */
++ u_char pad;
++ u_int32_t id_num; /* message id */
++ struct talk_addr addr; /* address for establishing conversation */
++};
++
++struct ntalk2_response {
++ u_char vers; /* protocol version */
++ u_char type; /* type of request message */
++ u_char answer; /* response to request */
++ u_char rvers; /* Version of answering vers*/
++ u_int32_t id_num; /* message id number */
++ struct talk_addr addr; /* address for connection */
++ /* This is at the end to compatiblize this with NTALK version. */
++ char r_name[TALK_NSIZE]; /* callee's name */
++};
++
++#define TALK_STR(data, talk_str, member) ((struct talk_str *)data)->member)
++#define TALK_RESP(data, ver, member) (ver ? ((struct ntalk_response *)data)->member : ((struct talk_response *)data)->member)
++#define TALK_MSG(data, ver, member) (ver ? ((struct ntalk_msg *)data)->member : ((struct talk_msg *)data)->member)
++
++#define TALK_VERSION 0 /* protocol versions */
++#define NTALK_VERSION 1
++#define NTALK2_VERSION 2
++
++/* message type values */
++#define LEAVE_INVITE 0 /* leave invitation with server */
++#define LOOK_UP 1 /* check for invitation by callee */
++#define DELETE 2 /* delete invitation by caller */
++#define ANNOUNCE 3 /* announce invitation by caller */
++/* NTALK2 */
++#define REPLY_QUERY 4 /* request reply data from local daemon */
++
++/* answer values */
++#define SUCCESS 0 /* operation completed properly */
++#define NOT_HERE 1 /* callee not logged in */
++#define FAILED 2 /* operation failed for unexplained reason */
++#define MACHINE_UNKNOWN 3 /* caller's machine name unknown */
++#define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */
++#define UNKNOWN_REQUEST 5 /* request has invalid type value */
++#define BADVERSION 6 /* request has invalid protocol version */
++#define BADADDR 7 /* request has invalid addr value */
++#define BADCTLADDR 8 /* request has invalid ctl_addr value */
++/* NTALK2 */
++#define NO_CALLER 9 /* no-one calling answer from REPLY */
++#define TRY_HERE 10 /* Not on this machine, try this */
++#define SELECTIVE_REFUSAL 11 /* User Filter refusal. */
++#define MAX_RESPONSE_TYPE 11 /* Make sure this is updated */
++
++/* We don't really need much for talk */
++struct ip_ct_talk_expect
++{
++ /* Port that was to be used */
++ u_int16_t port;
++};
++
++/* This structure exists only once per master */
++struct ip_ct_talk_master
++{
++};
++
++#endif /* _IP_CONNTRACK_TALK_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2004-06-07 21:14:55.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2004-06-08 10:40:55.000000000 +0200
+@@ -25,6 +25,9 @@
+ struct {
+ u_int16_t id;
+ } icmp;
++ struct {
++ u_int16_t port;
++ } sctp;
+ };
+
+ /* The manipulable part of the tuple. */
+@@ -55,6 +58,9 @@
+ struct {
+ u_int8_t type, code;
+ } icmp;
++ struct {
++ u_int16_t port;
++ } sctp;
+ } u;
+
+ /* The protocol. */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_pool.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_pool.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_pool.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_pool.h 2004-06-08 10:31:45.000000000 +0200
+@@ -0,0 +1,64 @@
++#ifndef _IP_POOL_H
++#define _IP_POOL_H
++
++/***************************************************************************/
++/* This program is free software; you can redistribute it and/or modify */
++/* it under the terms of the GNU General Public License as published by */
++/* the Free Software Foundation; either version 2 of the License, or */
++/* (at your option) any later version. */
++/* */
++/* This program is distributed in the hope that it will be useful, */
++/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
++/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
++/* GNU General Public License for more details. */
++/* */
++/* You should have received a copy of the GNU General Public License */
++/* along with this program; if not, write to the Free Software */
++/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
++/***************************************************************************/
++
++/* A sockopt of such quality has hardly ever been seen before on the open
++ * market! This little beauty, hardly ever used: above 64, so it's
++ * traditionally used for firewalling, not touched (even once!) by the
++ * 2.0, 2.2 and 2.4 kernels!
++ *
++ * Comes with its own certificate of authenticity, valid anywhere in the
++ * Free world!
++ *
++ * Rusty, 19.4.2000
++ */
++#define SO_IP_POOL 81
++
++typedef int ip_pool_t; /* pool index */
++#define IP_POOL_NONE ((ip_pool_t)-1)
++
++struct ip_pool_request {
++ int op;
++ ip_pool_t index;
++ u_int32_t addr;
++ u_int32_t addr2;
++};
++
++/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */
++
++#define IP_POOL_BAD001 0x00000010
++
++#define IP_POOL_FLUSH 0x00000011 /* req.index, no arguments */
++#define IP_POOL_INIT 0x00000012 /* from addr to addr2 incl. */
++#define IP_POOL_DESTROY 0x00000013 /* req.index, no arguments */
++#define IP_POOL_ADD_ADDR 0x00000014 /* add addr to pool */
++#define IP_POOL_DEL_ADDR 0x00000015 /* del addr from pool */
++#define IP_POOL_HIGH_NR 0x00000016 /* result in req.index */
++#define IP_POOL_LOOKUP 0x00000017 /* result in addr and addr2 */
++#define IP_POOL_USAGE 0x00000018 /* result in addr */
++#define IP_POOL_TEST_ADDR 0x00000019 /* result (0/1) returned */
++
++#ifdef __KERNEL__
++
++/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */
++extern int ip_pool_match(ip_pool_t pool, u_int32_t addr);
++extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel);
++
++#endif
++
++#endif /*_IP_POOL_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_tables.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ip_tables.h 2004-06-07 21:14:25.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ip_tables.h 2004-06-08 10:37:30.000000000 +0200
+@@ -134,6 +134,12 @@
+ /* Back pointer */
+ unsigned int comefrom;
+
++ /* Name of the chain */
++ char *chainname;
++
++ /* Rule number in the chain. */
++ u_int32_t rulenum;
++
+ /* Packet and byte counters. */
+ struct ipt_counters counters;
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2004-06-08 10:36:58.000000000 +0200
+@@ -0,0 +1,25 @@
++#ifndef _IPT_CONNMARK_H_target
++#define _IPT_CONNMARK_H_target
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++enum {
++ IPT_CONNMARK_SET = 0,
++ IPT_CONNMARK_SAVE,
++ IPT_CONNMARK_RESTORE
++};
++
++struct ipt_connmark_target_info {
++ unsigned long mark;
++ unsigned long mask;
++ u_int8_t mode;
++};
++
++#endif /*_IPT_CONNMARK_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_IPMARK.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_IPMARK.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_IPMARK.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_IPMARK.h 2004-06-08 10:37:02.000000000 +0200
+@@ -0,0 +1,13 @@
++#ifndef _IPT_IPMARK_H_target
++#define _IPT_IPMARK_H_target
++
++struct ipt_ipmark_target_info {
++ unsigned long andmask;
++ unsigned long ormask;
++ unsigned int addr;
++};
++
++#define IPT_IPMARK_SRC 0
++#define IPT_IPMARK_DST 1
++
++#endif /*_IPT_IPMARK_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_NETLINK.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_NETLINK.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_NETLINK.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_NETLINK.h 2004-06-08 10:31:09.000000000 +0200
+@@ -0,0 +1,27 @@
++#ifndef _IPT_FWMON_H
++#define _IPT_FWMON_H
++
++/* Bitmask macros */
++#define MASK(x,y) (x & y)
++#define MASK_SET(x,y) x |= y
++#define MASK_UNSET(x,y) x &= ~y
++
++#define USE_MARK 0x00000001
++#define USE_DROP 0x00000002
++#define USE_SIZE 0x00000004
++
++struct ipt_nldata
++{
++ unsigned int flags;
++ unsigned int mark;
++ unsigned int size;
++};
++
++/* Old header */
++struct netlink_t {
++ unsigned int len;
++ unsigned int mark;
++ char iface[IFNAMSIZ];
++};
++
++#endif /*_IPT_FWMON_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_ROUTE.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_ROUTE.h 2004-06-08 10:37:08.000000000 +0200
+@@ -0,0 +1,22 @@
++/* Header file for iptables ipt_ROUTE target
++ *
++ * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++#ifndef _IPT_ROUTE_H_target
++#define _IPT_ROUTE_H_target
++
++#define IPT_ROUTE_IFNAMSIZ 16
++
++struct ipt_route_target_info {
++ char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw; /* IP address of gateway */
++ u_int8_t flags;
++};
++
++/* Values for "flags" field */
++#define IPT_ROUTE_CONTINUE 0x01
++
++#endif /*_IPT_ROUTE_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_TTL.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_TTL.h 2004-06-08 10:31:21.000000000 +0200
+@@ -0,0 +1,21 @@
++/* TTL modification module for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
++
++#ifndef _IPT_TTL_H
++#define _IPT_TTL_H
++
++enum {
++ IPT_TTL_SET = 0,
++ IPT_TTL_INC,
++ IPT_TTL_DEC
++};
++
++#define IPT_TTL_MAXMODE IPT_TTL_DEC
++
++struct ipt_TTL_info {
++ u_int8_t mode;
++ u_int8_t ttl;
++};
++
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_XOR.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_XOR.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_XOR.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_XOR.h 2004-06-08 10:37:54.000000000 +0200
+@@ -0,0 +1,9 @@
++#ifndef _IPT_XOR_H
++#define _IPT_XOR_H
++
++struct ipt_XOR_info {
++ char key[30];
++ u_int8_t block_size;
++};
++
++#endif /* _IPT_XOR_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_addrtype.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_addrtype.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_addrtype.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_addrtype.h 2004-06-08 10:38:04.000000000 +0200
+@@ -0,0 +1,11 @@
++#ifndef _IPT_ADDRTYPE_H
++#define _IPT_ADDRTYPE_H
++
++struct ipt_addrtype_info {
++ u_int16_t source; /* source-type mask */
++ u_int16_t dest; /* dest-type mask */
++ int invert_source;
++ int invert_dest;
++};
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_connlimit.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-06-08 10:31:23.000000000 +0200
+@@ -0,0 +1,12 @@
++#ifndef _IPT_CONNLIMIT_H
++#define _IPT_CONNLIMIT_H
++
++struct ipt_connlimit_data;
++
++struct ipt_connlimit_info {
++ int limit;
++ int inverse;
++ u_int32_t mask;
++ struct ipt_connlimit_data *data;
++};
++#endif /* _IPT_CONNLIMIT_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_connmark.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_connmark.h 2004-06-08 10:36:58.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef _IPT_CONNMARK_H
++#define _IPT_CONNMARK_H
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++struct ipt_connmark_info {
++ unsigned long mark, mask;
++ u_int8_t invert;
++};
++
++#endif /*_IPT_CONNMARK_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_dstlimit.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-06-08 10:31:34.000000000 +0200
+@@ -0,0 +1,39 @@
++#ifndef _IPT_DSTLIMIT_H
++#define _IPT_DSTLIMIT_H
++
++/* timings are in milliseconds. */
++#define IPT_DSTLIMIT_SCALE 10000
++/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
++ seconds, or one every 59 hours. */
++
++/* details of this structure hidden by the implementation */
++struct ipt_dstlimit_htable;
++
++#define IPT_DSTLIMIT_HASH_DIP 0x0001
++#define IPT_DSTLIMIT_HASH_DPT 0x0002
++#define IPT_DSTLIMIT_HASH_SIP 0x0004
++
++struct dstlimit_cfg {
++ u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */
++ u_int32_t avg; /* Average secs between packets * scale */
++ u_int32_t burst; /* Period multiplier for upper limit. */
++
++ /* user specified */
++ u_int32_t size; /* how many buckets */
++ u_int32_t max; /* max number of entries */
++ u_int32_t gc_interval; /* gc interval */
++ u_int32_t expire; /* when do entries expire? */
++};
++
++struct ipt_dstlimit_info {
++ char name [IFNAMSIZ]; /* name */
++ struct dstlimit_cfg cfg;
++ struct ipt_dstlimit_htable *hinfo;
++
++ /* Used internally by the kernel */
++ union {
++ void *ptr;
++ struct ipt_dstlimit_info *master;
++ } u;
++};
++#endif /*_IPT_DSTLIMIT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_fuzzy.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-06-08 10:31:37.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IPT_FUZZY_H
++#define _IPT_FUZZY_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#define MAXFUZZYRATE 10000000
++#define MINFUZZYRATE 3
++
++struct ipt_fuzzy_info {
++ u_int32_t minimum_rate;
++ u_int32_t maximum_rate;
++ u_int32_t packets_total;
++ u_int32_t bytes_total;
++ u_int32_t previous_time;
++ u_int32_t present_time;
++ u_int32_t mean_rate;
++ u_int8_t acceptance_rate;
++};
++
++#endif /*_IPT_FUZZY_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_ipv4options.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-06-08 10:31:39.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef __ipt_ipv4options_h_included__
++#define __ipt_ipv4options_h_included__
++
++#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */
++#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */
++#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */
++#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */
++#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10
++#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */
++#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40
++#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */
++#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
++#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */
++#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */
++
++struct ipt_ipv4options_info {
++ u_int16_t options;
++};
++
++
++#endif /* __ipt_ipv4options_h_included__ */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_mport.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_mport.h 2004-06-08 10:31:40.000000000 +0200
+@@ -0,0 +1,24 @@
++#ifndef _IPT_MPORT_H
++#define _IPT_MPORT_H
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#define IPT_MPORT_SOURCE (1<<0)
++#define IPT_MPORT_DESTINATION (1<<1)
++#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
++
++#define IPT_MULTI_PORTS 15
++
++/* Must fit inside union ipt_matchinfo: 32 bytes */
++/* every entry in ports[] except for the last one has one bit in pflags
++ * associated with it. If this bit is set, the port is the first port of
++ * a portrange, with the next entry being the last.
++ * End of list is marked with pflags bit set and port=65535.
++ * If 14 ports are used (last one does not have a pflag), the last port
++ * is repeated to fill the last entry in ports[] */
++struct ipt_mport
++{
++ u_int8_t flags:2; /* Type of comparison */
++ u_int16_t pflags:14; /* Port flags */
++ u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
++};
++#endif /*_IPT_MPORT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_nth.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_nth.h 2004-06-08 10:31:42.000000000 +0200
+@@ -0,0 +1,19 @@
++#ifndef _IPT_NTH_H
++#define _IPT_NTH_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#ifndef IPT_NTH_NUM_COUNTERS
++#define IPT_NTH_NUM_COUNTERS 16
++#endif
++
++struct ipt_nth_info {
++ u_int8_t every;
++ u_int8_t not;
++ u_int8_t startat;
++ u_int8_t counter;
++ u_int8_t packet;
++};
++
++#endif /*_IPT_NTH_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_osf.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_osf.h 2004-06-08 10:31:44.000000000 +0200
+@@ -0,0 +1,148 @@
++/*
++ * ipt_osf.h
++ *
++ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _IPT_OSF_H
++#define _IPT_OSF_H
++
++#define MAXGENRELEN 32
++#define MAXDETLEN 64
++
++#define IPT_OSF_GENRE 1
++#define IPT_OSF_SMART 2
++#define IPT_OSF_LOG 4
++#define IPT_OSF_NETLINK 8
++
++#define IPT_OSF_LOGLEVEL_ALL 0
++#define IPT_OSF_LOGLEVEL_FIRST 1
++
++#include <linux/list.h>
++
++#ifndef __KERNEL__
++#include <netinet/ip.h>
++#include <netinet/tcp.h>
++
++struct list_head
++{
++ struct list_head *prev, *next;
++};
++#endif
++
++struct ipt_osf_info
++{
++ char genre[MAXGENRELEN];
++ int len;
++ unsigned long flags;
++ int loglevel;
++ int invert; /* UNSUPPORTED */
++};
++
++struct osf_wc
++{
++ char wc;
++ unsigned long val;
++};
++
++/* This struct represents IANA options
++ * http://www.iana.org/assignments/tcp-parameters
++ */
++struct osf_opt
++{
++ unsigned char kind;
++ unsigned char length;
++ struct osf_wc wc;
++};
++
++struct osf_finger
++{
++ struct list_head flist;
++ struct osf_wc wss;
++ unsigned char ttl;
++ unsigned char df;
++ unsigned long ss;
++ unsigned char genre[MAXGENRELEN];
++ unsigned char version[MAXGENRELEN], subtype[MAXGENRELEN];
++
++ /* Not needed, but for consistency with original table from Michal Zalewski */
++ unsigned char details[MAXDETLEN];
++
++ int opt_num;
++ struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
++
++};
++
++struct ipt_osf_nlmsg
++{
++ struct osf_finger f;
++ struct iphdr ip;
++ struct tcphdr tcp;
++};
++
++#ifdef __KERNEL__
++
++/* Defines for IANA option kinds */
++
++#define OSFOPT_EOL 0 /* End of options */
++#define OSFOPT_NOP 1 /* NOP */
++#define OSFOPT_MSS 2 /* Maximum segment size */
++#define OSFOPT_WSO 3 /* Window scale option */
++#define OSFOPT_SACKP 4 /* SACK permitted */
++#define OSFOPT_SACK 5 /* SACK */
++#define OSFOPT_ECHO 6
++#define OSFOPT_ECHOREPLY 7
++#define OSFOPT_TS 8 /* Timestamp option */
++#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */
++#define OSFOPT_POSP 10 /* Partial Order Service Profile */
++/* Others are not used in current OSF */
++
++static struct osf_opt IANA_opts[] =
++{
++ {0, 1,},
++ {1, 1,},
++ {2, 4,},
++ {3, 3,},
++ {4, 2,},
++ {5, 1 ,}, /* SACK length is not defined */
++ {6, 6,},
++ {7, 6,},
++ {8, 10,},
++ {9, 2,},
++ {10, 3,},
++ {11, 1,}, /* CC: Suppose 1 */
++ {12, 1,}, /* the same */
++ {13, 1,}, /* and here too */
++ {14, 3,},
++ {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
++ {16, 1,},
++ {17, 1,},
++ {18, 3,},
++ {19, 18,},
++ {20, 1,},
++ {21, 1,},
++ {22, 1,},
++ {23, 1,},
++ {24, 1,},
++ {25, 1,},
++ {26, 1,},
++};
++
++#endif /* __KERNEL__ */
++
++#endif /* _IPT_OSF_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_policy.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_policy.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_policy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_policy.h 2004-06-08 10:42:36.000000000 +0200
+@@ -0,0 +1,52 @@
++#ifndef _IPT_POLICY_H
++#define _IPT_POLICY_H
++
++#define POLICY_MAX_ELEM 4
++
++enum ipt_policy_flags
++{
++ POLICY_MATCH_IN = 0x1,
++ POLICY_MATCH_OUT = 0x2,
++ POLICY_MATCH_NONE = 0x4,
++ POLICY_MATCH_STRICT = 0x8,
++};
++
++enum ipt_policy_modes
++{
++ POLICY_MODE_TRANSPORT,
++ POLICY_MODE_TUNNEL
++};
++
++struct ipt_policy_spec
++{
++ u_int8_t saddr:1,
++ daddr:1,
++ proto:1,
++ mode:1,
++ spi:1,
++ reqid:1;
++};
++
++struct ipt_policy_elem
++{
++ u_int32_t saddr;
++ u_int32_t smask;
++ u_int32_t daddr;
++ u_int32_t dmask;
++ u_int32_t spi;
++ u_int32_t reqid;
++ u_int8_t proto;
++ u_int8_t mode;
++
++ struct ipt_policy_spec match;
++ struct ipt_policy_spec invert;
++};
++
++struct ipt_policy_info
++{
++ struct ipt_policy_elem pol[POLICY_MAX_ELEM];
++ u_int16_t flags;
++ u_int16_t len;
++};
++
++#endif /* _IPT_POLICY_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_pool.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_pool.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_pool.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_pool.h 2004-06-08 10:31:45.000000000 +0200
+@@ -0,0 +1,25 @@
++#ifndef _IPT_POOL_H
++#define _IPT_POOL_H
++
++#include <linux/netfilter_ipv4/ip_pool.h>
++
++#define IPT_POOL_INV_SRC 0x00000001
++#define IPT_POOL_INV_DST 0x00000002
++#define IPT_POOL_DEL_SRC 0x00000004
++#define IPT_POOL_DEL_DST 0x00000008
++#define IPT_POOL_INV_MOD_SRC 0x00000010
++#define IPT_POOL_INV_MOD_DST 0x00000020
++#define IPT_POOL_MOD_SRC_ACCEPT 0x00000040
++#define IPT_POOL_MOD_DST_ACCEPT 0x00000080
++#define IPT_POOL_MOD_SRC_DROP 0x00000100
++#define IPT_POOL_MOD_DST_DROP 0x00000200
++
++/* match info */
++struct ipt_pool_info
++{
++ ip_pool_t src;
++ ip_pool_t dst;
++ unsigned flags;
++};
++
++#endif /*_IPT_POOL_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_psd.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_psd.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_psd.h 2004-06-08 10:31:53.000000000 +0200
+@@ -0,0 +1,40 @@
++#ifndef _IPT_PSD_H
++#define _IPT_PSD_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++/*
++ * High port numbers have a lower weight to reduce the frequency of false
++ * positives, such as from passive mode FTP transfers.
++ */
++#define PORT_WEIGHT_PRIV 3
++#define PORT_WEIGHT_HIGH 1
++
++/*
++ * Port scan detection thresholds: at least COUNT ports need to be scanned
++ * from the same source, with no longer than DELAY ticks between ports.
++ */
++#define SCAN_MIN_COUNT 7
++#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
++#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT
++#define SCAN_DELAY_THRESHOLD (300) /* old usage of HZ here was erroneously and broke under uml */
++
++/*
++ * Keep track of up to LIST_SIZE source addresses, using a hash table of
++ * HASH_SIZE entries for faster lookups, but limiting hash collisions to
++ * HASH_MAX source addresses per the same hash value.
++ */
++#define LIST_SIZE 0x100
++#define HASH_LOG 9
++#define HASH_SIZE (1 << HASH_LOG)
++#define HASH_MAX 0x10
++
++struct ipt_psd_info {
++ unsigned int weight_threshold;
++ unsigned int delay_threshold;
++ unsigned short lo_ports_weight;
++ unsigned short hi_ports_weight;
++};
++
++#endif /*_IPT_PSD_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_quota.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_quota.h 2004-06-08 10:31:54.000000000 +0200
+@@ -0,0 +1,11 @@
++#ifndef _IPT_QUOTA_H
++#define _IPT_QUOTA_H
++
++/* print debug info in both kernel/netfilter module & iptable library */
++//#define DEBUG_IPT_QUOTA
++
++struct ipt_quota_info {
++ u_int64_t quota;
++};
++
++#endif /*_IPT_QUOTA_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_random.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_random.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_random.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_random.h 2004-06-08 10:31:56.000000000 +0200
+@@ -0,0 +1,11 @@
++#ifndef _IPT_RAND_H
++#define _IPT_RAND_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++struct ipt_rand_info {
++ u_int8_t average;
++};
++
++#endif /*_IPT_RAND_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_realm.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_realm.h 2004-06-08 10:32:20.000000000 +0200
+@@ -0,0 +1,9 @@
++#ifndef _IPT_REALM_H
++#define _IPT_REALM_H
++
++struct ipt_realm_info {
++ u_int32_t id;
++ u_int32_t mask;
++ u_int8_t invert;
++};
++#endif /*_IPT_REALM_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_sctp.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_sctp.h 2004-06-08 10:32:21.000000000 +0200
+@@ -0,0 +1,107 @@
++#ifndef _IPT_SCTP_H_
++#define _IPT_SCTP_H_
++
++#define IPT_SCTP_SRC_PORTS 0x01
++#define IPT_SCTP_DEST_PORTS 0x02
++#define IPT_SCTP_CHUNK_TYPES 0x04
++
++#define IPT_SCTP_VALID_FLAGS 0x07
++
++#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
++
++
++struct ipt_sctp_flag_info {
++ u_int8_t chunktype;
++ u_int8_t flag;
++ u_int8_t flag_mask;
++};
++
++#define IPT_NUM_SCTP_FLAGS 4
++
++struct ipt_sctp_info {
++ u_int16_t dpts[2]; /* Min, Max */
++ u_int16_t spts[2]; /* Min, Max */
++
++ u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */
++
++#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */
++#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */
++#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */
++
++ u_int32_t chunk_match_type;
++ struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
++ int flag_count;
++
++ u_int32_t flags;
++ u_int32_t invflags;
++};
++
++#define bytes(type) (sizeof(type) * 8)
++
++#define SCTP_CHUNKMAP_SET(chunkmap, type) \
++ do { \
++ chunkmap[type / bytes(u_int32_t)] |= \
++ 1 << (type % bytes(u_int32_t)); \
++ } while (0)
++
++#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
++ do { \
++ chunkmap[type / bytes(u_int32_t)] &= \
++ ~(1 << (type % bytes(u_int32_t))); \
++ } while (0)
++
++#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
++({ \
++ (chunkmap[type / bytes (u_int32_t)] & \
++ (1 << (type % bytes (u_int32_t)))) ? 1: 0; \
++})
++
++#define SCTP_CHUNKMAP_RESET(chunkmap) \
++ do { \
++ int i; \
++ for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
++ chunkmap[i] = 0; \
++ } while (0)
++
++#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
++ do { \
++ int i; \
++ for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
++ chunkmap[i] = ~0; \
++ } while (0)
++
++#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
++ do { \
++ int i; \
++ for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
++ destmap[i] = srcmap[i]; \
++ } while (0)
++
++#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
++({ \
++ int i; \
++ int flag = 1; \
++ for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
++ if (chunkmap[i]) { \
++ flag = 0; \
++ break; \
++ } \
++ } \
++ flag; \
++})
++
++#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
++({ \
++ int i; \
++ int flag = 1; \
++ for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
++ if (chunkmap[i] != ~0) { \
++ flag = 0; \
++ break; \
++ } \
++ } \
++ flag; \
++})
++
++#endif /* _IPT_SCTP_H_ */
++
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_string.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_string.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_string.h 2004-06-08 10:41:24.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IPT_STRING_H
++#define _IPT_STRING_H
++
++/* *** PERFORMANCE TWEAK ***
++ * Packet size and search string threshold,
++ * above which sublinear searches is used. */
++#define IPT_STRING_HAYSTACK_THRESH 100
++#define IPT_STRING_NEEDLE_THRESH 20
++
++#define BM_MAX_NLEN 256
++#define BM_MAX_HLEN 1024
++
++typedef char *(*proc_ipt_search) (char *, char *, int, int);
++
++struct ipt_string_info {
++ char string[BM_MAX_NLEN];
++ u_int16_t invert;
++ u_int16_t len;
++};
++
++#endif /* _IPT_STRING_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_time.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_time.h 2004-06-08 10:32:31.000000000 +0200
+@@ -0,0 +1,15 @@
++#ifndef __ipt_time_h_included__
++#define __ipt_time_h_included__
++
++
++struct ipt_time_info {
++ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
++ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
++ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
++ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
++ time_t date_start;
++ time_t date_stop;
++};
++
++
++#endif /* __ipt_time_h_included__ */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_u32.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4/ipt_u32.h 2004-06-08 10:32:32.000000000 +0200
+@@ -0,0 +1,40 @@
++#ifndef _IPT_U32_H
++#define _IPT_U32_H
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++enum ipt_u32_ops
++{
++ IPT_U32_AND,
++ IPT_U32_LEFTSH,
++ IPT_U32_RIGHTSH,
++ IPT_U32_AT
++};
++
++struct ipt_u32_location_element
++{
++ u_int32_t number;
++ u_int8_t nextop;
++};
++struct ipt_u32_value_element
++{
++ u_int32_t min;
++ u_int32_t max;
++};
++/* *** any way to allow for an arbitrary number of elements?
++ for now I settle for a limit of 10 of each */
++#define U32MAXSIZE 10
++struct ipt_u32_test
++{
++ u_int8_t nnums;
++ struct ipt_u32_location_element location[U32MAXSIZE+1];
++ u_int8_t nvalues;
++ struct ipt_u32_value_element value[U32MAXSIZE+1];
++};
++
++struct ipt_u32
++{
++ u_int8_t ntests;
++ struct ipt_u32_test tests[U32MAXSIZE+1];
++};
++
++#endif /*_IPT_U32_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv4.h linux-2.6.7-rc3/include/linux/netfilter_ipv4.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv4.h 2004-06-07 21:14:57.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv4.h 2004-06-08 10:38:44.000000000 +0200
+@@ -7,6 +7,8 @@
+
+ #include <linux/config.h>
+ #include <linux/netfilter.h>
++#include <linux/netdevice.h>
++#include <net/protocol.h>
+
+ /* IP Cache bits. */
+ /* Src IP address. */
+@@ -85,6 +87,58 @@
+ Returns true or false. */
+ extern int skb_ip_make_writable(struct sk_buff **pskb,
+ unsigned int writable_len);
++
++#if defined(CONFIG_XFRM) && defined(CONFIG_NETFILTER)
++#include <net/route.h>
++#include <net/xfrm.h>
++
++static inline int nf_hook_input_cond(struct sk_buff *skb)
++{
++ return !skb->sp || skb->sp->decap_done;
++}
++
++static inline int
++nf_xfrm_local_done(struct sk_buff *skb, struct inet_protocol *ipprot)
++{
++ return skb->sp && !skb->sp->decap_done
++ && (!ipprot || !ipprot->xfrm_prot);
++}
++
++static inline int nf_xfrm_nonlocal_done(struct sk_buff *skb)
++{
++ return skb->sp && !skb->sp->decap_done
++ && !(((struct rtable *)skb->dst)->rt_flags&RTCF_LOCAL);
++}
++
++extern int nf_rcv_postxfrm_local(struct sk_buff *skb);
++extern int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb);
++#else /* CONFIG_XFRM */
++static inline int nf_hook_input_cond(struct sk_buff *skb)
++{
++ return 1;
++}
++
++static inline int
++nf_xfrm_local_done(struct sk_buff *skb, struct inet_protocol *ipprot)
++{
++ return 0;
++}
++
++static inline int nf_xfrm_nonlocal_done(struct sk_buff *skb)
++{
++ return 0;
++}
++
++static inline int nf_rcv_postxfrm_local(struct sk_buff *skb)
++{
++ return 0;
++}
++
++static inline int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb)
++{
++ return 0;
++}
++#endif /* CONFIG_XFRM */
+ #endif /*__KERNEL__*/
+
+ #endif /*__LINUX_IP_NETFILTER_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6_tables.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6_tables.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6_tables.h 2004-06-07 21:15:11.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6_tables.h 2004-06-08 10:37:30.000000000 +0200
+@@ -142,6 +142,12 @@
+ /* Back pointer */
+ unsigned int comefrom;
+
++ /* Name of the chain */
++ char *chainname;
++
++ /* Rule number in the chain. */
++ u_int32_t rulenum;
++
+ /* Packet and byte counters. */
+ struct ip6t_counters counters;
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_HL.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_HL.h 2004-06-08 10:31:03.000000000 +0200
+@@ -0,0 +1,22 @@
++/* Hop Limit modification module for ip6tables
++ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
++ * Based on HW's TTL module */
++
++#ifndef _IP6T_HL_H
++#define _IP6T_HL_H
++
++enum {
++ IP6T_HL_SET = 0,
++ IP6T_HL_INC,
++ IP6T_HL_DEC
++};
++
++#define IP6T_HL_MAXMODE IP6T_HL_DEC
++
++struct ip6t_HL_info {
++ u_int8_t mode;
++ u_int8_t hop_limit;
++};
++
++
++#endif
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_REJECT.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-06-07 21:13:34.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-06-08 10:31:20.000000000 +0200
+@@ -2,15 +2,17 @@
+ #define _IP6T_REJECT_H
+
+ enum ip6t_reject_with {
+- IP6T_ICMP_NET_UNREACHABLE,
+- IP6T_ICMP_HOST_UNREACHABLE,
+- IP6T_ICMP_PROT_UNREACHABLE,
+- IP6T_ICMP_PORT_UNREACHABLE,
+- IP6T_ICMP_ECHOREPLY
++ IP6T_ICMP6_NO_ROUTE,
++ IP6T_ICMP6_ADM_PROHIBITED,
++ IP6T_ICMP6_NOT_NEIGHBOUR,
++ IP6T_ICMP6_ADDR_UNREACH,
++ IP6T_ICMP6_PORT_UNREACH,
++ IP6T_ICMP6_ECHOREPLY,
++ IP6T_TCP_RESET
+ };
+
+ struct ip6t_reject_info {
+ enum ip6t_reject_with with; /* reject type */
+ };
+
+-#endif /*_IPT_REJECT_H*/
++#endif /*_IP6T_REJECT_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_ROUTE.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2004-06-08 10:37:08.000000000 +0200
+@@ -0,0 +1,22 @@
++/* Header file for iptables ip6t_ROUTE target
++ *
++ * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++#ifndef _IPT_ROUTE_H_target
++#define _IPT_ROUTE_H_target
++
++#define IP6T_ROUTE_IFNAMSIZ 16
++
++struct ip6t_route_target_info {
++ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw[4]; /* IPv6 address of gateway */
++ u_int8_t flags;
++};
++
++/* Values for "flags" field */
++#define IP6T_ROUTE_CONTINUE 0x01
++
++#endif /*_IP6T_ROUTE_H_target*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_fuzzy.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-06-08 10:31:37.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IP6T_FUZZY_H
++#define _IP6T_FUZZY_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#define MAXFUZZYRATE 10000000
++#define MINFUZZYRATE 3
++
++struct ip6t_fuzzy_info {
++ u_int32_t minimum_rate;
++ u_int32_t maximum_rate;
++ u_int32_t packets_total;
++ u_int32_t bytes_total;
++ u_int32_t previous_time;
++ u_int32_t present_time;
++ u_int32_t mean_rate;
++ u_int8_t acceptance_rate;
++};
++
++#endif /*_IP6T_FUZZY_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_nth.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_nth.h 2004-06-08 10:31:42.000000000 +0200
+@@ -0,0 +1,19 @@
++#ifndef _IP6T_NTH_H
++#define _IP6T_NTH_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++#ifndef IP6T_NTH_NUM_COUNTERS
++#define IP6T_NTH_NUM_COUNTERS 16
++#endif
++
++struct ip6t_nth_info {
++ u_int8_t every;
++ u_int8_t not;
++ u_int8_t startat;
++ u_int8_t counter;
++ u_int8_t packet;
++};
++
++#endif /*_IP6T_NTH_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_owner.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_owner.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_owner.h 2004-06-07 21:14:41.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_owner.h 2004-06-08 10:40:01.000000000 +0200
+@@ -6,12 +6,14 @@
+ #define IP6T_OWNER_GID 0x02
+ #define IP6T_OWNER_PID 0x04
+ #define IP6T_OWNER_SID 0x08
++#define IP6T_OWNER_COMM 0x10
+
+ struct ip6t_owner_info {
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ pid_t sid;
++ char comm[16];
+ u_int8_t match, invert; /* flags */
+ };
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_policy.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_policy.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_policy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_policy.h 2004-06-08 10:42:36.000000000 +0200
+@@ -0,0 +1,52 @@
++#ifndef _IP6T_POLICY_H
++#define _IP6T_POLICY_H
++
++#define POLICY_MAX_ELEM 4
++
++enum ip6t_policy_flags
++{
++ POLICY_MATCH_IN = 0x1,
++ POLICY_MATCH_OUT = 0x2,
++ POLICY_MATCH_NONE = 0x4,
++ POLICY_MATCH_STRICT = 0x8,
++};
++
++enum ip6t_policy_modes
++{
++ POLICY_MODE_TRANSPORT,
++ POLICY_MODE_TUNNEL
++};
++
++struct ip6t_policy_spec
++{
++ u_int8_t saddr:1,
++ daddr:1,
++ proto:1,
++ mode:1,
++ spi:1,
++ reqid:1;
++};
++
++struct ip6t_policy_elem
++{
++ struct in6_addr saddr;
++ struct in6_addr smask;
++ struct in6_addr daddr;
++ struct in6_addr dmask;
++ u_int32_t spi;
++ u_int32_t reqid;
++ u_int8_t proto;
++ u_int8_t mode;
++
++ struct ip6t_policy_spec match;
++ struct ip6t_policy_spec invert;
++};
++
++struct ip6t_policy_info
++{
++ struct ip6t_policy_elem pol[POLICY_MAX_ELEM];
++ u_int16_t flags;
++ u_int16_t len;
++};
++
++#endif /* _IP6T_POLICY_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_random.h linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_random.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_ipv6/ip6t_random.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_ipv6/ip6t_random.h 2004-06-08 10:31:56.000000000 +0200
+@@ -0,0 +1,11 @@
++#ifndef _IP6T_RAND_H
++#define _IP6T_RAND_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++struct ip6t_rand_info {
++ u_int8_t average;
++};
++
++#endif /*_IP6T_RAND_H*/
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/netfilter_mime.h linux-2.6.7-rc3/include/linux/netfilter_mime.h
+--- linux-2.6.7-rc3.org/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/include/linux/netfilter_mime.h 2004-06-08 10:40:46.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ * MIME functions for netfilter modules. This file provides implementations
++ * for basic MIME parsing. MIME headers are used in many protocols, such as
++ * HTTP, RTSP, SIP, etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested. The following macros are used:
++ * NF_NEED_MIME_NEXTLINE nf_mime_nextline()
++ */
++#ifndef _NETFILTER_MIME_H
++#define _NETFILTER_MIME_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line. If the current line is empty, *plinelen will be set to zero. If
++ * not, it will be set to the actual line length (including CRLF).
++ *
++ * 'line' in this context means logical line (includes LWS continuations).
++ * Returns 1 on success, 0 on failure.
++ */
++#ifdef NF_NEED_MIME_NEXTLINE
++static int
++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++ uint off = *poff;
++ uint physlen = 0;
++ int is_first_line = 1;
++
++ if (off >= len)
++ {
++ return 0;
++ }
++
++ do
++ {
++ while (p[off] != '\n')
++ {
++ if (len-off <= 1)
++ {
++ return 0;
++ }
++
++ physlen++;
++ off++;
++ }
++
++ /* if we saw a crlf, physlen needs adjusted */
++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++ {
++ physlen--;
++ }
++
++ /* advance past the newline */
++ off++;
++
++ /* check for an empty line */
++ if (physlen == 0)
++ {
++ break;
++ }
++
++ /* check for colon on the first physical line */
++ if (is_first_line)
++ {
++ is_first_line = 0;
++ if (memchr(p+(*poff), ':', physlen) == NULL)
++ {
++ return 0;
++ }
++ }
++ }
++ while (p[off] == ' ' || p[off] == '\t');
++
++ *plineoff = *poff;
++ *plinelen = (physlen == 0) ? 0 : (off - *poff);
++ *poff = off;
++
++ return 1;
++}
++#endif /* NF_NEED_MIME_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_MIME_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/linux/skbuff.h linux-2.6.7-rc3/include/linux/skbuff.h
+--- linux-2.6.7-rc3.org/include/linux/skbuff.h 2004-06-07 21:14:33.000000000 +0200
++++ linux-2.6.7-rc3/include/linux/skbuff.h 2004-06-08 10:30:55.000000000 +0200
+@@ -1049,6 +1049,14 @@
+ if (nfct)
+ atomic_inc(&nfct->master->use);
+ }
++static inline void nf_reset(struct sk_buff *skb)
++{
++ nf_conntrack_put(skb->nfct);
++ skb->nfct = NULL;
++#ifdef CONFIG_NETFILTER_DEBUG
++ skb->nf_debug = 0;
++#endif
++}
+
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
+@@ -1061,9 +1069,10 @@
+ if (nf_bridge)
+ atomic_inc(&nf_bridge->use);
+ }
+-#endif
+-
+-#endif
++#endif /* CONFIG_BRIDGE_NETFILTER */
++#else /* CONFIG_NETFILTER */
++static inline void nf_reset(struct sk_buff *skb) {}
++#endif /* CONFIG_NETFILTER */
+
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_SKBUFF_H */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/net/ip.h linux-2.6.7-rc3/include/net/ip.h
+--- linux-2.6.7-rc3.org/include/net/ip.h 2004-06-07 21:14:42.000000000 +0200
++++ linux-2.6.7-rc3/include/net/ip.h 2004-06-08 10:38:43.000000000 +0200
+@@ -30,6 +30,8 @@
+ #include <linux/netdevice.h>
+ #include <linux/inetdevice.h>
+ #include <linux/in_route.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
+ #include <net/route.h>
+ #include <net/arp.h>
+
+@@ -48,6 +50,7 @@
+ #define IPSKB_TRANSLATED 2
+ #define IPSKB_FORWARDED 4
+ #define IPSKB_XFRM_TUNNEL_SIZE 8
++#define IPSKB_XFRM_TRANSFORMED 16
+ };
+
+ struct ipcm_cookie
+@@ -212,6 +215,12 @@
+ __ip_select_ident(iph, dst, more);
+ }
+
++extern inline int ip_dst_output(struct sk_buff *skb)
++{
++ return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
++ skb->dst->dev, dst_output, skb->dst->xfrm != NULL);
++}
++
+ /*
+ * Map a multicast IP onto multicast MAC for type ethernet.
+ */
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/net/protocol.h linux-2.6.7-rc3/include/net/protocol.h
+--- linux-2.6.7-rc3.org/include/net/protocol.h 2004-06-07 21:14:10.000000000 +0200
++++ linux-2.6.7-rc3/include/net/protocol.h 2004-06-08 10:38:44.000000000 +0200
+@@ -39,6 +39,7 @@
+ int (*handler)(struct sk_buff *skb);
+ void (*err_handler)(struct sk_buff *skb, u32 info);
+ int no_policy;
++ int xfrm_prot;
+ };
+
+ #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/net/tcp.h linux-2.6.7-rc3/include/net/tcp.h
+--- linux-2.6.7-rc3.org/include/net/tcp.h 2004-06-07 21:13:39.000000000 +0200
++++ linux-2.6.7-rc3/include/net/tcp.h 2004-06-08 10:39:56.000000000 +0200
+@@ -162,6 +162,7 @@
+ extern void tcp_bucket_unlock(struct sock *sk);
+ extern int tcp_port_rover;
+ extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif);
++extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 hnum, int dif);
+
+ /* These are AF independent. */
+ static __inline__ int tcp_bhashfn(__u16 lport)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/net/udp.h linux-2.6.7-rc3/include/net/udp.h
+--- linux-2.6.7-rc3.org/include/net/udp.h 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/include/net/udp.h 2004-06-08 10:39:56.000000000 +0200
+@@ -74,6 +74,8 @@
+ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
+ extern int udp_disconnect(struct sock *sk, int flags);
+
++extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
++
+ DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
+ #define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field)
+ #define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/include/net/xfrm.h linux-2.6.7-rc3/include/net/xfrm.h
+--- linux-2.6.7-rc3.org/include/net/xfrm.h 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/include/net/xfrm.h 2004-06-08 10:38:44.000000000 +0200
+@@ -540,6 +540,9 @@
+ {
+ atomic_t refcnt;
+ int len;
++#ifdef CONFIG_NETFILTER
++ int decap_done;
++#endif
+ struct sec_decap_state x[XFRM_MAX_DEPTH];
+ };
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/core/netfilter.c linux-2.6.7-rc3/net/core/netfilter.c
+--- linux-2.6.7-rc3.org/net/core/netfilter.c 2004-06-07 21:14:11.000000000 +0200
++++ linux-2.6.7-rc3/net/core/netfilter.c 2004-06-08 10:38:46.000000000 +0200
+@@ -27,6 +27,8 @@
+ #include <linux/icmp.h>
+ #include <net/sock.h>
+ #include <net/route.h>
++#include <net/xfrm.h>
++#include <net/ip.h>
+ #include <linux/ip.h>
+
+ /* In this code, we can be waiting indefinitely for userspace to
+@@ -630,7 +632,6 @@
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
+ #endif
+- fl.proto = iph->protocol;
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return -1;
+
+@@ -657,6 +658,20 @@
+ if ((*pskb)->dst->error)
+ return -1;
+
++#ifdef CONFIG_XFRM
++ if (!(IPCB(*pskb)->flags & IPSKB_XFRM_TRANSFORMED)) {
++ struct xfrm_policy_afinfo *afinfo;
++
++ afinfo = xfrm_policy_get_afinfo(AF_INET);
++ if (afinfo != NULL) {
++ afinfo->decode_session(*pskb, &fl);
++ xfrm_policy_put_afinfo(afinfo);
++ if (xfrm_lookup(&(*pskb)->dst, &fl, (*pskb)->sk, 0) != 0)
++ return -1;
++ }
++ }
++#endif
++
+ /* Change in oif may mean change in hh_len. */
+ hh_len = (*pskb)->dst->dev->hard_header_len;
+ if (skb_headroom(*pskb) < hh_len) {
+@@ -674,6 +689,71 @@
+ return 0;
+ }
+
++#ifdef CONFIG_XFRM
++inline int nf_rcv_postxfrm_nonlocal(struct sk_buff *skb)
++{
++ skb->sp->decap_done = 1;
++ dst_release(skb->dst);
++ skb->dst = NULL;
++ nf_reset(skb);
++ return netif_rx(skb);
++}
++
++int nf_rcv_postxfrm_local(struct sk_buff *skb)
++{
++ __skb_push(skb, skb->data - skb->nh.raw);
++ /* Fix header len and checksum if last xfrm was transport mode */
++ if (!skb->sp->x[skb->sp->len - 1].xvec->props.mode) {
++ skb->nh.iph->tot_len = htons(skb->len);
++ ip_send_check(skb->nh.iph);
++ }
++ return nf_rcv_postxfrm_nonlocal(skb);
++}
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++
++void nf_nat_decode_session4(struct sk_buff *skb, struct flowi *fl)
++{
++ struct ip_conntrack *ct;
++ struct ip_conntrack_tuple *t;
++ struct ip_nat_info_manip *m;
++ unsigned int i;
++
++ if (skb->nfct == NULL)
++ return;
++ ct = (struct ip_conntrack *)skb->nfct->master;
++
++ for (i = 0; i < ct->nat.info.num_manips; i++) {
++ m = &ct->nat.info.manips[i];
++ t = &ct->tuplehash[m->direction].tuple;
++
++ switch (m->hooknum) {
++ case NF_IP_PRE_ROUTING:
++ if (m->maniptype != IP_NAT_MANIP_DST)
++ break;
++ fl->fl4_dst = t->dst.ip;
++ if (t->dst.protonum == IPPROTO_TCP ||
++ t->dst.protonum == IPPROTO_UDP)
++ fl->fl_ip_dport = t->dst.u.tcp.port;
++ break;
++#ifdef CONFIG_IP_NF_NAT_LOCAL
++ case NF_IP_LOCAL_IN:
++ if (m->maniptype != IP_NAT_MANIP_SRC)
++ break;
++ fl->fl4_src = t->src.ip;
++ if (t->dst.protonum == IPPROTO_TCP ||
++ t->dst.protonum == IPPROTO_UDP)
++ fl->fl_ip_sport = t->src.u.tcp.port;
++ break;
++#endif
++ }
++ }
++}
++#endif /* CONFIG_IP_NF_NAT_NEEDED */
++#endif
++
+ int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+ {
+ struct sk_buff *nskb;
+@@ -831,3 +911,4 @@
+ EXPORT_SYMBOL(nf_unregister_hook);
+ EXPORT_SYMBOL(nf_unregister_queue_handler);
+ EXPORT_SYMBOL(nf_unregister_sockopt);
++EXPORT_SYMBOL(nf_rcv_postxfrm_local);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ah4.c linux-2.6.7-rc3/net/ipv4/ah4.c
+--- linux-2.6.7-rc3.org/net/ipv4/ah4.c 2004-06-07 21:14:58.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ah4.c 2004-06-08 10:38:44.000000000 +0200
+@@ -146,6 +146,7 @@
+ err = -EHOSTUNREACH;
+ goto error_nolock;
+ }
++ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+ return NET_XMIT_BYPASS;
+
+ error:
+@@ -344,6 +345,7 @@
+ .handler = xfrm4_rcv,
+ .err_handler = ah4_err,
+ .no_policy = 1,
++ .xfrm_prot = 1,
+ };
+
+ static int __init ah4_init(void)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/esp4.c linux-2.6.7-rc3/net/ipv4/esp4.c
+--- linux-2.6.7-rc3.org/net/ipv4/esp4.c 2004-06-07 21:14:33.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/esp4.c 2004-06-08 10:38:44.000000000 +0200
+@@ -216,6 +216,7 @@
+ err = -EHOSTUNREACH;
+ goto error_nolock;
+ }
++ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+ return NET_XMIT_BYPASS;
+
+ error:
+@@ -598,6 +599,7 @@
+ .handler = xfrm4_rcv,
+ .err_handler = esp4_err,
+ .no_policy = 1,
++ .xfrm_prot = 1,
+ };
+
+ static int __init esp4_init(void)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/igmp.c linux-2.6.7-rc3/net/ipv4/igmp.c
+--- linux-2.6.7-rc3.org/net/ipv4/igmp.c 2004-06-07 21:15:12.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/igmp.c 2004-06-08 10:38:43.000000000 +0200
+@@ -343,7 +343,7 @@
+ pig->csum = ip_compute_csum((void *)skb->h.igmph, igmplen);
+
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev,
+- dst_output);
++ ip_dst_output);
+ }
+
+ static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
+@@ -673,7 +673,7 @@
+ ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
+
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+- dst_output);
++ ip_dst_output);
+ }
+
+ static void igmp_gq_timer_expire(unsigned long data)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ip_forward.c linux-2.6.7-rc3/net/ipv4/ip_forward.c
+--- linux-2.6.7-rc3.org/net/ipv4/ip_forward.c 2004-06-07 21:13:35.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ip_forward.c 2004-06-08 10:38:43.000000000 +0200
+@@ -51,7 +51,7 @@
+ if (unlikely(opt->optlen))
+ ip_forward_options(skb);
+
+- return dst_output(skb);
++ return ip_dst_output(skb);
+ }
+
+ int ip_forward(struct sk_buff *skb)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ip_gre.c linux-2.6.7-rc3/net/ipv4/ip_gre.c
+--- linux-2.6.7-rc3.org/net/ipv4/ip_gre.c 2004-06-07 21:14:55.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ip_gre.c 2004-06-08 10:30:55.000000000 +0200
+@@ -643,13 +643,7 @@
+ skb->dev = tunnel->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+ ipgre_ecn_decapsulate(iph, skb);
+ netif_rx(skb);
+ read_unlock(&ipgre_lock);
+@@ -877,13 +871,7 @@
+ }
+ }
+
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+
+ IPTUNNEL_XMIT();
+ tunnel->recursion--;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ip_input.c linux-2.6.7-rc3/net/ipv4/ip_input.c
+--- linux-2.6.7-rc3.org/net/ipv4/ip_input.c 2004-06-07 21:13:37.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ip_input.c 2004-06-08 10:38:46.000000000 +0200
+@@ -202,18 +202,10 @@
+
+ #ifdef CONFIG_NETFILTER_DEBUG
+ nf_debug_ip_local_deliver(skb);
+- skb->nf_debug = 0;
+ #endif /*CONFIG_NETFILTER_DEBUG*/
+
+ __skb_pull(skb, ihl);
+
+-#ifdef CONFIG_NETFILTER
+- /* Free reference early: we don't need it any more, and it may
+- hold ip_conntrack module loaded indefinitely. */
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#endif /*CONFIG_NETFILTER*/
+-
+ /* Point into the IP datagram, just past the header. */
+ skb->h.raw = skb->data;
+
+@@ -228,6 +220,13 @@
+ resubmit:
+ hash = protocol & (MAX_INET_PROTOS - 1);
+ raw_sk = sk_head(&raw_v4_htable[hash]);
++ ipprot = inet_protos[hash];
++ smp_read_barrier_depends();
++
++ if (nf_xfrm_local_done(skb, ipprot)) {
++ nf_rcv_postxfrm_local(skb);
++ goto out;
++ }
+
+ /* If there maybe a raw socket we must check - if not we
+ * don't care less
+@@ -235,14 +234,15 @@
+ if (raw_sk)
+ raw_v4_input(skb, skb->nh.iph, hash);
+
+- if ((ipprot = inet_protos[hash]) != NULL) {
++ if (ipprot != NULL) {
+ int ret;
+
+- smp_read_barrier_depends();
+- if (!ipprot->no_policy &&
+- !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+- kfree_skb(skb);
+- goto out;
++ if (!ipprot->no_policy) {
++ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
++ kfree_skb(skb);
++ goto out;
++ }
++ nf_reset(skb);
+ }
+ ret = ipprot->handler(skb);
+ if (ret < 0) {
+@@ -283,8 +283,8 @@
+ return 0;
+ }
+
+- return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,
+- ip_local_deliver_finish);
++ return NF_HOOK_COND(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,
++ ip_local_deliver_finish, nf_hook_input_cond(skb));
+ }
+
+ static inline int ip_rcv_finish(struct sk_buff *skb)
+@@ -301,6 +301,9 @@
+ goto drop;
+ }
+
++ if (nf_xfrm_nonlocal_done(skb))
++ return nf_rcv_postxfrm_nonlocal(skb);
++
+ #ifdef CONFIG_NET_CLS_ROUTE
+ if (skb->dst->tclassid) {
+ struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
+@@ -422,8 +425,8 @@
+ }
+ }
+
+- return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
+- ip_rcv_finish);
++ return NF_HOOK_COND(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
++ ip_rcv_finish, nf_hook_input_cond(skb));
+
+ inhdr_error:
+ IP_INC_STATS_BH(InHdrErrors);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ip_output.c linux-2.6.7-rc3/net/ipv4/ip_output.c
+--- linux-2.6.7-rc3.org/net/ipv4/ip_output.c 2004-06-07 21:15:12.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ip_output.c 2004-06-08 10:38:43.000000000 +0200
+@@ -123,6 +123,15 @@
+ return ttl;
+ }
+
++#ifdef CONFIG_NETFILTER
++/* out-of-line copy is only required with netfilter */
++int ip_dst_output(struct sk_buff *skb)
++{
++ return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
++ skb->dst->dev, dst_output, skb->dst->xfrm != NULL);
++}
++#endif
++
+ /*
+ * Add an ip header to a skbuff and send it out.
+ *
+@@ -165,7 +174,7 @@
+
+ /* Send it out. */
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+- dst_output);
++ ip_dst_output);
+ }
+
+ static inline int ip_finish_output2(struct sk_buff *skb)
+@@ -284,7 +293,7 @@
+ return ip_finish_output(skb);
+ }
+
+-int ip_output(struct sk_buff **pskb)
++static inline int ip_output2(struct sk_buff **pskb)
+ {
+ struct sk_buff *skb = *pskb;
+
+@@ -297,6 +306,16 @@
+ return ip_finish_output(skb);
+ }
+
++int ip_output(struct sk_buff *skb)
++{
++ int transformed = IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED;
++
++ if (transformed)
++ nf_reset(skb);
++ return NF_HOOK_COND(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
++ skb->dst->dev, ip_output2, transformed);
++}
++
+ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+ {
+ struct sock *sk = skb->sk;
+@@ -390,7 +409,7 @@
+ skb->priority = sk->sk_priority;
+
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+- dst_output);
++ ip_dst_output);
+
+ no_route:
+ IP_INC_STATS(OutNoRoutes);
+@@ -1180,7 +1199,7 @@
+
+ /* Netfilter gets whole the not fragmented skb. */
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
+- skb->dst->dev, dst_output);
++ skb->dst->dev, ip_dst_output);
+ if (err) {
+ if (err > 0)
+ err = inet->recverr ? net_xmit_errno(err) : 0;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ipcomp.c linux-2.6.7-rc3/net/ipv4/ipcomp.c
+--- linux-2.6.7-rc3.org/net/ipv4/ipcomp.c 2004-06-07 21:14:58.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ipcomp.c 2004-06-08 10:38:44.000000000 +0200
+@@ -232,6 +232,7 @@
+ err = -EHOSTUNREACH;
+ goto error_nolock;
+ }
++ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+ err = NET_XMIT_BYPASS;
+
+ out_exit:
+@@ -409,6 +410,7 @@
+ .handler = xfrm4_rcv,
+ .err_handler = ipcomp4_err,
+ .no_policy = 1,
++ .xfrm_prot = 1,
+ };
+
+ static int __init ipcomp4_init(void)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ipip.c linux-2.6.7-rc3/net/ipv4/ipip.c
+--- linux-2.6.7-rc3.org/net/ipv4/ipip.c 2004-06-07 21:15:21.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ipip.c 2004-06-08 10:38:44.000000000 +0200
+@@ -478,6 +478,11 @@
+
+ read_lock(&ipip_lock);
+ if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
++ /* IPIP packets decapsulated by IPsec missed netfilter hooks */
++ if (nf_xfrm_local_done(skb, NULL)) {
++ nf_rcv_postxfrm_local(skb);
++ return 0;
++ }
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+ read_unlock(&ipip_lock);
+ kfree_skb(skb);
+@@ -497,13 +502,7 @@
+ skb->dev = tunnel->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+ ipip_ecn_decapsulate(iph, skb);
+ netif_rx(skb);
+ read_unlock(&ipip_lock);
+@@ -648,13 +647,7 @@
+ if ((iph->ttl = tiph->ttl) == 0)
+ iph->ttl = old_iph->ttl;
+
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+
+ IPTUNNEL_XMIT();
+ tunnel->recursion--;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/ipmr.c linux-2.6.7-rc3/net/ipv4/ipmr.c
+--- linux-2.6.7-rc3.org/net/ipv4/ipmr.c 2004-06-07 21:14:12.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/ipmr.c 2004-06-08 10:38:43.000000000 +0200
+@@ -1105,10 +1105,7 @@
+ skb->h.ipiph = skb->nh.iph;
+ skb->nh.iph = iph;
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#endif
++ nf_reset(skb);
+ }
+
+ static inline int ipmr_forward_finish(struct sk_buff *skb)
+@@ -1120,7 +1117,7 @@
+ if (unlikely(opt->optlen))
+ ip_forward_options(skb);
+
+- return dst_output(skb);
++ return ip_dst_output(skb);
+ }
+
+ /*
+@@ -1461,10 +1458,7 @@
+ skb->dst = NULL;
+ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len;
+ ((struct net_device_stats*)reg_dev->priv)->rx_packets++;
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#endif
++ nf_reset(skb);
+ netif_rx(skb);
+ dev_put(reg_dev);
+ return 0;
+@@ -1520,10 +1514,7 @@
+ ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len;
+ ((struct net_device_stats*)reg_dev->priv)->rx_packets++;
+ skb->dst = NULL;
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#endif
++ nf_reset(skb);
+ netif_rx(skb);
+ dev_put(reg_dev);
+ return 0;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/Kconfig linux-2.6.7-rc3/net/ipv4/netfilter/Kconfig
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/Kconfig 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/Kconfig 2004-06-08 10:42:36.000000000 +0200
+@@ -206,6 +206,11 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP_NF_MATCH_UNCLEAN
++ tristate 'unclean match support (EXPERIMENTAL)'
++ depends on EXPERIMENTAL && IP_NF_IPTABLES
++ help
++
+ config IP_NF_MATCH_TTL
+ tristate "TTL match support"
+ depends on IP_NF_IPTABLES
+@@ -603,5 +608,492 @@
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+ help
+
++config IP_NF_TARGET_IPV4OPTSSTRIP
++ tristate 'IPV4OPTSSTRIP target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds an IPV4OPTSSTRIP target.
++ This target allows you to strip all IP options in a packet.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_TARGET_NETLINK
++ tristate 'NETLINK target support'
++ depends on IP_NF_FILTER
++ help
++ The NETLINK target allows you to recieve packets in userspace via
++ the kernel firewall netlink socket. Apps such as fwmon
++ (http://firestorm.geek-ware.co.uk) can then recieve and dislpay
++ these packets. This option is basically a re-implementation of the
++ ipchains -o option.
++
++config IP_NF_TARGET_TTL
++ tristate 'TTL target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `TTL' target, which enables the user to set
++ the TTL value or increment / decrement the TTL value by a given
++ amount.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_CONNLIMIT
++ tristate 'Connections/IP limit match support'
++ depends on IP_NF_IPTABLES
++ help
++ This match allows you to restrict the number of parallel TCP
++ connections to a server per client IP address (or address block).
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_DSTLIMIT
++ tristate 'dstlimit match support'
++ depends on IP_NF_IPTABLES
++
++config IP_NF_MATCH_FUZZY
++ tristate 'fuzzy match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `fuzzy' match, which allows you to match
++ packets according to a fuzzy logic based law.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_IPV4OPTIONS
++ tristate 'IPV4OPTIONS match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a IPV4OPTIONS match.
++ It allows you to filter options like source routing,
++ record route, timestamp and router-altert.
++
++ If you say Y here, try iptables -m ipv4options --help for more information.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_MPORT
++ tristate 'Multiple port with ranges match support'
++ depends on IP_NF_IPTABLES
++ help
++ This is an enhanced multiport match which supports port
++ ranges as well as single ports.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_NTH
++ tristate 'Nth match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `Nth' match, which allow you to make
++ rules that match every Nth packet. By default there are
++ 16 different counters.
++
++ [options]
++ --every Nth Match every Nth packet
++ [--counter] num Use counter 0-15 (default:0)
++ [--start] num Initialize the counter at the number 'num'
++ instead of 0. Must be between 0 and Nth-1
++ [--packet] num Match on 'num' packet. Must be between 0
++ and Nth-1.
++
++ If --packet is used for a counter than
++ there must be Nth number of --packet
++ rules, covering all values between 0 and
++ Nth-1 inclusively.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_OSF
++ tristate 'OSF match support'
++ depends on IP_NF_IPTABLES
++ help
++
++ The idea of passive OS fingerprint matching exists for quite a long time,
++ but was created as extension fo OpenBSD pf only some weeks ago.
++ Original idea was lurked in some OpenBSD mailing list (thanks
++ grange@open...) and than adopted for Linux netfilter in form of this code.
++
++ Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
++ his excellent p0f and than changed a bit for more convenience.
++
++ This module compares some data(WS, MSS, options and it's order, ttl,
++ df and others) from first SYN packet (actually from packets with SYN
++ bit set) with hardcoded in fingers[] table ones.
++
++ If you say Y here, try iptables -m osf --help for more information.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_POOL_STATISTICS
++ bool 'enable statistics on pool usage'
++ depends on IP_NF_POOL!=n
++ help
++ This option controls whether usage gathering code is compiled into the
++ ip_pool module. Disabling statistics may be substantially faster.
++
++config IP_NF_POOL
++ tristate 'IP address pool support'
++ depends on IP_NF_IPTABLES
++ help
++ Pool matching lets you use bitmaps with one bit per address from some
++ range of IP addresses; the match depends on whether a checked source
++ or destination address has its bit set in the pool.
++
++ There is also a POOL netfilter target, which can be used to set or remove
++ the addresses of a packet from a pool.
++
++ To define and use pools, you need userlevel utilities: a patched iptables,
++ and the program ippool(8), which defines the pools and their bounds.
++ The current release of pool matching is ippool-0.0.2, and can be found
++ in the archives of the netfilter mailing list at
++ http://lists.samba.org/netfilter/.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_PSD
++ tristate 'psd match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `psd' match, which allows you to create rules in
++ any iptables table wich will detect TCP and UDP port scans.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_QUOTA
++ tristate 'quota match support'
++ depends on IP_NF_IPTABLES
++ help
++ This match implements network quotas.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++
++config IP_NF_MATCH_RANDOM
++ tristate 'random match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `random' match,
++ which allow you to match packets randomly
++ following a given probability.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_REALM
++ tristate 'realm match support'
++ depends on IP_NF_IPTABLES && NET_CLS_ROUTE
++ help
++ This option adds a `realm' match, which allows you to use the realm
++ key from the routing subsytem inside iptables.
++
++ This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option
++ in tc world.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_SCTP
++ tristate 'SCTP protocol match support'
++ depends on IP_NF_IPTABLES
++
++config IP_NF_MATCH_TIME
++ tristate 'TIME match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `time' match, which allows you
++ to match based on the packet arrival time/date
++ (arrival time/date at the machine which netfilter is running on) or
++ departure time/date (for locally generated packets).
++
++ If you say Y here, try iptables -m time --help for more information.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_U32
++ tristate 'U32 match support'
++ depends on IP_NF_IPTABLES
++ help
++ U32 allows you to extract quantities of up to 4 bytes from a packet,
++ AND them with specified masks, shift them by specified amounts and
++ test whether the results are in any of a set of specified ranges.
++ The specification of what to extract is general enough to skip over
++ headers with lengths stored in the packet, as in IP or TCP header
++ lengths.
++
++ Details and examples are in the kernel module source.
++
++config IP_NF_CONNTRACK_MARK
++ bool 'Connection mark tracking support'
++ help
++ This option enables support for connection marks, used by the
++ `CONNMARK' target and `connmark' match. Similar to the mark value
++ of packets, but this mark value is kept in the conntrack session
++ instead of the individual packets.
++
++config IP_NF_TARGET_CONNMARK
++ tristate 'CONNMARK target support'
++ depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
++ help
++ This option adds a `CONNMARK' target, which allows one to manipulate
++ the connection mark value. Similar to the MARK target, but
++ affects the connection mark value rather than the packet mark value.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called
++ ipt_CONNMARK.o. If unsure, say `N'.
++
++config IP_NF_MATCH_CONNMARK
++ tristate ' Connection mark match support'
++ depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
++ help
++ This option adds a `connmark' match, which allows you to match the
++ connection mark value previously set for the session by `CONNMARK'.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called
++ ipt_connmark.o. If unsure, say `N'.
++
++config IP_NF_TARGET_IPMARK
++ tristate 'IPMARK target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `IPMARK' target, which allows you to create rules
++ in the `mangle' table which alter the netfilter mark (nfmark) field
++ basing on the source or destination ip address of the packet.
++ This is very useful for very fast massive mangling and marking.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++config IP_NF_TARGET_ROUTE
++ tristate 'ROUTE target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. For example, the ROUTE lets you route a received packet through
++ an interface or towards a host, even if the regular destination of the
++ packet is the router itself. The ROUTE target is also able to change the
++ incoming interface of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called ipt_ROUTE.o.
++ If unsure, say `N'.
++
++config IP_NF_TARGET_TARPIT
++ tristate 'TARPIT target support'
++ depends on IP_NF_FILTER
++ help
++ Adds a TARPIT target to iptables, which captures and holds
++ incoming TCP connections using no local per-connection resources.
++ Connections are accepted, but immediately switched to the persist
++ state (0 byte window), in which the remote side stops sending data
++ and asks to continue every 60-240 seconds. Attempts to close the
++ connection are ignored, forcing the remote side to time out the
++ connection in 12-24 minutes.
++
++ This offers similar functionality to LaBrea
++ <http://www.hackbusters.net/LaBrea/> but doesn't require dedicated
++ hardware or IPs. Any TCP port that you would normally DROP or REJECT
++ can instead become a tarpit.
++
++config IP_NF_TARGET_TRACE
++ tristate 'TRACE target support'
++ depends on IP_NF_RAW
++ help
++ The TRACE target allows packets to be traced as those
++ matches any subsequent rule in any table/rule. The matched
++ rule and the packet is logged with the prefix
++
++ TRACE: tablename/chainname/rulenum
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++config IP_NF_TARGET_XOR
++ tristate 'XOR target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `XOR' target, which can encrypt TCP and
++ UDP traffic using a simple XOR encryption.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_MATCH_ADDRTYPE
++ tristate 'address type match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option allows you to match what routing thinks of an address,
++ eg. UNICAST, LOCAL, BROADCAST, ...
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_EGG
++ tristate 'Eggdrop bot support'
++ depends on IP_NF_CONNTRACK
++ help
++ If you are running an eggdrop hub bot on this machine, then you
++ may want to enable this feature. This enables eggdrop bots to share
++ their user file to other eggdrop bots.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_NAT_H323
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++ default IP_NF_NAT if IP_NF_H323=y
++ default m if IP_NF_H323=m
++
++config IP_NF_H323
++ tristate 'H.323 (netmeeting) support'
++ depends on IP_NF_CONNTRACK
++ help
++ H.323 is a standard signalling protocol used by teleconferencing
++ softwares like netmeeting. With the ip_conntrack_h323 and
++ the ip_nat_h323 modules you can support the protocol on a connection
++ tracking/NATing firewall.
++
++ If you want to compile it as a module, say 'M' here and read
++ Documentation/modules.txt. If unsure, say 'N'.
++
++config IP_NF_NAT_MMS
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++ default IP_NF_NAT if IP_NF_MMS=y
++ default m if IP_NF_MMS=m
++
++config IP_NF_MMS
++ tristate 'MMS protocol support'
++ depends on IP_NF_CONNTRACK
++ help
++ Tracking MMS (Microsoft Windows Media Services) connections
++ could be problematic if random ports are used to send the
++ streaming content. This option allows users to track streaming
++ connections over random UDP or TCP ports.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `Y'.
++
++config IP_NF_NAT_QUAKE3
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT !=n
++ default IP_NF_NAT if IP_NF_QUAKE3=y
++ default m if IP_NF_QUAKE3=m
++
++config IP_NF_QUAKE3
++ tristate "Quake3 protocol support"
++ depends on IP_NF_CONNTRACK
++ help
++ Quake III Arena connection tracking helper. This module allows for a
++ stricter firewall rulebase if one only allows traffic to a master
++ server. Connections to Quake III server IP addresses and ports returned
++ by the master server will be tracked automatically.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `Y'.
++
++config IP_NF_RSH
++ tristate 'RSH protocol support'
++ depends on IP_NF_CONNTRACK
++ help
++ The RSH connection tracker is required if the dynamic
++ stderr "Server to Client" connection is to occur during a
++ normal RSH session. This typically operates as follows;
++
++ Client 0:1023 --> Server 514 (stream 1 - stdin/stdout)
++ Client 0:1023 <-- Server 0:1023 (stream 2 - stderr)
++
++ This connection tracker will identify new RSH sessions,
++ extract the outbound session details, and notify netfilter
++ of pending "related" sessions.
++
++ Warning: This module could be dangerous. It is not "best
++ practice" to use RSH, use SSH in all instances.
++ (see rfc1244, rfc1948, rfc2179, etc ad-nauseum)
++
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++config IP_NF_NAT_RTSP
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++ default IP_NF_NAT if IP_NF_RTSP=y
++ default m if IP_NF_RTSP=m
++
++config IP_NF_RTSP
++ tristate ' RTSP protocol support'
++ depends on IP_NF_CONNTRACK
++ help
++ Support the RTSP protocol. This allows UDP transports to be setup
++ properly, including RTP and RDT.
++
++ If you want to compile it as a module, say 'M' here and read
++ Documentation/modules.txt. If unsure, say 'Y'.
++
++config IP_NF_CT_PROTO_SCTP
++ tristate 'SCTP protocol connection tracking support'
++ depends on IP_NF_CONNTRACK
++
++config IP_NF_MATCH_STRING
++ tristate 'String match support'
++ depends on IP_NF_IPTABLES
++ help
++ String matching alows you to match packets which contain a
++ specified string of characters.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP_NF_NAT_TALK
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++ default IP_NF_NAT if IP_NF_TALK=y
++ default m if IP_NF_TALK=m
++
++config IP_NF_TALK
++ tristate 'talk protocol support'
++ depends on IP_NF_CONNTRACK
++ help
++ The talk protocols (both otalk/talk - or talk/ntalk, to confuse
++ you by the different namings about which is old or which is new :-)
++ use an additional channel to setup the talk session and a separated
++ data channel for the actual conversation (like in FTP). Both the
++ initiating and the setup channels are over UDP, while the data channel
++ is over TCP, on a random port. The conntrack part of this extension
++ will enable you to let in/out talk sessions easily by matching these
++ connections as RELATED by the state match, while the NAT part helps
++ you to let talk sessions trough a NAT machine.
++
++ If you want to compile it as a module, say 'M' here and read
++ Documentation/modules.txt. If unsure, say 'N'.
++
++config IP_NF_MATCH_POLICY
++ tristate "IPsec policy match support"
++ depends on IP_NF_IPTABLES && XFRM
++ help
++ Policy matching allows you to match packets based on the
++ IPsec policy that was used during decapsulation/will
++ be used during encapsulation.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ endmenu
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/Makefile linux-2.6.7-rc3/net/ipv4/netfilter/Makefile
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/Makefile 2004-06-07 21:14:01.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/Makefile 2004-06-08 10:42:36.000000000 +0200
+@@ -19,10 +19,49 @@
+ # connection tracking
+ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
+
++# talk protocol support
++obj-$(CONFIG_IP_NF_TALK) += ip_conntrack_talk.o
++ifdef CONFIG_IP_NF_TALK
++ export-objs += ip_conntrack_talk.o
++endif
++obj-$(CONFIG_IP_NF_NAT_TALK) += ip_nat_talk.o
++
++
++# SCTP protocol connection tracking
++obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
++
++# H.323 support
++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
++ifdef CONFIG_IP_NF_H323
++ export-objs += ip_conntrack_h323.o
++endif
++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
++
++
+ # connection tracking helpers
++
++# rtsp protocol support
++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o
++ifdef CONFIG_IP_NF_NAT_RTSP
++ export-objs += ip_conntrack_rtsp.o
++endif
++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
++
++obj-$(CONFIG_IP_NF_QUAKE3) += ip_conntrack_quake3.o
++ifdef CONFIG_IP_NF_NAT_QUAKE3
++ export-objs += ip_conntrack_quake3.o
++endif
++obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o
++ifdef CONFIG_IP_NF_MMS
++ export-objs += ip_conntrack_mms.o
++endif
+ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
+ obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
+ obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
++obj-$(CONFIG_IP_NF_RSH) += ip_conntrack_rsh.o
++
++obj-$(CONFIG_IP_NF_EGG) += ip_conntrack_egg.o
++
+ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+
+ # NAT helpers
+@@ -30,6 +69,8 @@
+ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
+ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
++obj-$(CONFIG_IP_NF_NAT_QUAKE3) += ip_nat_quake3.o
++obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+@@ -43,15 +84,39 @@
+ # 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_POOL) += ipt_pool.o ipt_POOL.o ip_pool.o
+ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+ obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
+
+ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
++
++obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
++
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+
++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o
++
++obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o
++
++obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
++
++obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
++
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+
+ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+@@ -60,28 +125,47 @@
+
+ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
+
++obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
++
++
++obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
++obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
++obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
++obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
++obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
++obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
+
+ obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
++obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
+
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
++obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o
+ obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+ obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
+ obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
++obj-$(CONFIG_IP_NF_TARGET_IPMARK) += ipt_IPMARK.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
++obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
+ obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+ obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_XOR) += ipt_XOR.o
++obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
++obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
++obj-$(CONFIG_IP_NF_TARGET_NETLINK) += ipt_NETLINK.o
++obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
++obj-$(CONFIG_IP_NF_TARGET_TRACE) += ipt_TRACE.o
+ obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
+
+ # generic ARP tables
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-06-07 21:13:34.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_core.c 2004-06-08 10:36:58.000000000 +0200
+@@ -67,6 +67,7 @@
+ static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
+ struct list_head *ip_conntrack_hash;
+ static kmem_cache_t *ip_conntrack_cachep;
++static kmem_cache_t *ip_conntrack_expect_cachep;
+ struct ip_conntrack ip_conntrack_untracked;
+
+ extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
+@@ -176,7 +177,7 @@
+ IP_NF_ASSERT(atomic_read(&exp->use));
+ IP_NF_ASSERT(!timer_pending(&exp->timeout));
+
+- kfree(exp);
++ kmem_cache_free(ip_conntrack_expect_cachep, exp);
+ }
+
+
+@@ -324,8 +325,9 @@
+ ip_conntrack_destroyed(ct);
+
+ WRITE_LOCK(&ip_conntrack_lock);
+- /* Delete us from our own list to prevent corruption later */
+- list_del(&ct->sibling_list);
++ /* Make sure don't leave any orphaned expectations lying around */
++ if (ct->expecting)
++ remove_expectations(ct, 1);
+
+ /* Delete our master expectation */
+ if (ct->master) {
+@@ -335,7 +337,7 @@
+ list_del(&ct->master->expected_list);
+ master = ct->master->expectant;
+ }
+- kfree(ct->master);
++ kmem_cache_free(ip_conntrack_expect_cachep, ct->master);
+ }
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+@@ -692,25 +694,22 @@
+ struct ip_conntrack_expect *, tuple);
+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+
+- /* If master is not in hash table yet (ie. packet hasn't left
+- this machine yet), how can other end know about expected?
+- Hence these are not the droids you are looking for (if
+- master ct never got confirmed, we'd hold a reference to it
+- and weird things would happen to future packets). */
+- if (expected && !is_confirmed(expected->expectant))
+- expected = NULL;
+-
+- /* Look up the conntrack helper for master connections only */
+- if (!expected)
+- conntrack->helper = ip_ct_find_helper(&repl_tuple);
++ if (expected) {
++ /* If master is not in hash table yet (ie. packet hasn't left
++ this machine yet), how can other end know about expected?
++ Hence these are not the droids you are looking for (if
++ master ct never got confirmed, we'd hold a reference to it
++ and weird things would happen to future packets). */
++ if (!is_confirmed(expected->expectant)) {
++ conntrack->helper = ip_ct_find_helper(&repl_tuple);
++ goto end;
++ }
+
+- /* If the expectation is dying, then this is a loser. */
+- if (expected
+- && expected->expectant->helper->timeout
+- && ! del_timer(&expected->timeout))
+- expected = NULL;
++ /* Expectation is dying... */
++ if (expected->expectant->helper->timeout
++ && !del_timer(&expected->timeout))
++ goto end;
+
+- if (expected) {
+ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+ conntrack, expected);
+ /* Welcome, Mr. Bond. We've been expecting you... */
+@@ -718,16 +717,28 @@
+ __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+ conntrack->master = expected;
+ expected->sibling = conntrack;
++#if CONFIG_IP_NF_CONNTRACK_MARK
++ conntrack->mark = expected->expectant->mark;
++#endif
+ LIST_DELETE(&ip_conntrack_expect_list, expected);
+ expected->expectant->expecting--;
+ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
+- }
+- atomic_inc(&ip_conntrack_count);
++
++ /* this is a braindead... --pablo */
++ atomic_inc(&ip_conntrack_count);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ if (expected->expectfn)
++ expected->expectfn(conntrack);
++
++ goto ret;
++ } else
++ conntrack->helper = ip_ct_find_helper(&repl_tuple);
++
++end: atomic_inc(&ip_conntrack_count);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+- if (expected && expected->expectfn)
+- expected->expectfn(conntrack);
+- return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
++ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
+ }
+
+ /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+@@ -923,9 +934,8 @@
+ ip_conntrack_expect_alloc(void)
+ {
+ struct ip_conntrack_expect *new;
+-
+- new = (struct ip_conntrack_expect *)
+- kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
++
++ new = kmem_cache_alloc(ip_conntrack_expect_cachep, GFP_ATOMIC);
+ if (!new) {
+ DEBUGP("expect_related: OOM allocating expect\n");
+ return NULL;
+@@ -933,6 +943,7 @@
+
+ /* tuple_cmp compares whole union, we have to initialized cleanly */
+ memset(new, 0, sizeof(struct ip_conntrack_expect));
++ atomic_set(&new->use, 1);
+
+ return new;
+ }
+@@ -944,12 +955,10 @@
+ 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);
++ list_add_tail(&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) {
+@@ -998,12 +1007,12 @@
+ }
+
+ WRITE_UNLOCK(&ip_conntrack_lock);
+- kfree(expect);
++ /* This expectation is not inserted so no need to lock */
++ kmem_cache_free(ip_conntrack_expect_cachep, expect);
+ return -EEXIST;
+
+ } else if (related_to->helper->max_expected &&
+ related_to->expecting >= related_to->helper->max_expected) {
+- struct list_head *cur_item;
+ /* old == NULL */
+ if (!(related_to->helper->flags &
+ IP_CT_HELPER_F_REUSE_EXPECT)) {
+@@ -1017,7 +1026,7 @@
+ related_to->helper->name,
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
+- kfree(expect);
++ kmem_cache_free(ip_conntrack_expect_cachep, expect);
+ return -EPERM;
+ }
+ DEBUGP("ip_conntrack: max number of expected "
+@@ -1029,21 +1038,14 @@
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
+
+ /* choose the the oldest expectation to evict */
+- list_for_each(cur_item, &related_to->sibling_list) {
+- struct ip_conntrack_expect *cur;
+-
+- cur = list_entry(cur_item,
+- struct ip_conntrack_expect,
+- expected_list);
+- if (cur->sibling == NULL) {
+- old = cur;
++ list_for_each_entry(old, &related_to->sibling_list,
++ expected_list)
++ if (old->sibling == NULL)
+ break;
+- }
+- }
+
+- /* (!old) cannot happen, since related_to->expecting is the
+- * number of unconfirmed expects */
+- IP_NF_ASSERT(old);
++ /* We cannot fail since related_to->expecting is the number
++ * of unconfirmed expectations */
++ IP_NF_ASSERT(old && old->sibling == NULL);
+
+ /* newnat14 does not reuse the real allocated memory
+ * structures but rather unexpects the old and
+@@ -1058,7 +1060,7 @@
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_related: busy!\n");
+
+- kfree(expect);
++ kmem_cache_free(ip_conntrack_expect_cachep, expect);
+ return -EBUSY;
+ }
+
+@@ -1127,10 +1129,8 @@
+ DUMP_TUPLE(newreply);
+
+ conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
+- if (!conntrack->master)
+- conntrack->helper = LIST_FIND(&helpers, helper_cmp,
+- struct ip_conntrack_helper *,
+- newreply);
++ if (!conntrack->master && list_empty(&conntrack->sibling_list))
++ conntrack->helper = ip_ct_find_helper(newreply);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+ return 1;
+@@ -1379,6 +1379,7 @@
+ }
+
+ kmem_cache_destroy(ip_conntrack_cachep);
++ kmem_cache_destroy(ip_conntrack_expect_cachep);
+ vfree(ip_conntrack_hash);
+ nf_unregister_sockopt(&so_getorigdst);
+ }
+@@ -1431,6 +1432,15 @@
+ printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
+ goto err_free_hash;
+ }
++
++ ip_conntrack_expect_cachep = kmem_cache_create("ip_conntrack_expect",
++ sizeof(struct ip_conntrack_expect),
++ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (!ip_conntrack_expect_cachep) {
++ printk(KERN_ERR "Unable to create ip_expect slab cache\n");
++ goto err_free_conntrack_slab;
++ }
++
+ /* Don't NEED lock here, but good form anyway. */
+ WRITE_LOCK(&ip_conntrack_lock);
+ /* Sew in builtin protocols. */
+@@ -1458,6 +1468,8 @@
+
+ return ret;
+
++err_free_conntrack_slab:
++ kmem_cache_destroy(ip_conntrack_cachep);
+ err_free_hash:
+ vfree(ip_conntrack_hash);
+ err_unreg_sockopt:
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_egg.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_egg.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_egg.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_egg.c 2004-06-08 10:38:25.000000000 +0200
+@@ -0,0 +1,237 @@
++/* Eggdrop extension for IP connection tracking, Version 0.0.5
++ * based on ip_conntrack_irc.c
++ *
++ * This module only supports the share userfile-send command,
++ * used by eggdrops to share it's userfile.
++ *
++ * There are no support for NAT at the moment.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ *
++ * please give the ports of all Eggdrops You have running
++ * on your system, the default port is 3333.
++ *
++ * 2001-04-19: Security update. IP addresses are now compared
++ * to prevent unauthorized "related" access.
++ *
++ * 2002-03-25: Harald Welte <laforge@gnumonks.org>:
++ * Port to netfilter 'newnat' API.
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c = 0;
++static unsigned int egg_timeout = 300;
++
++MODULE_AUTHOR("Magnus Sandin <magnus@sandin.cx>");
++MODULE_DESCRIPTION("Eggdrop (userfile-sharing) connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of eggdrop servers");
++#endif
++
++DECLARE_LOCK(ip_egg_lock);
++struct module *ip_conntrack_egg = THIS_MODULE;
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++int parse_command(char *data, char *data_end, u_int32_t * ip, u_int16_t * port)
++/* tries to get the ip_addr and port out of a eggdrop command
++ return value: -1 on failure, 0 on success
++ data pointer to first byte of DCC command data
++ data_end pointer to last byte of dcc command data
++ ip returns parsed ip of dcc command
++ port returns parsed port of dcc command */
++{
++ if (data > data_end)
++ return -1;
++
++ *ip = simple_strtoul(data, &data, 10);
++
++ /* skip blanks between ip and port */
++ while (*data == ' ' && data < data_end)
++ data++;
++
++ *port = simple_strtoul(data, &data, 10);
++ return 0;
++}
++
++
++static int help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ char *data = (char *) tcph + tcph->doff * 4;
++ char *data_limit;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ int bytes_scanned = 0;
++ struct ip_conntrack_expect exp;
++
++ u_int32_t egg_ip;
++ u_int16_t egg_port;
++
++ DEBUGP("entered\n");
++
++ /* If packet is coming from IRC server */
++ if (dir != IP_CT_DIR_REPLY)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
++ DEBUGP("tcplen = %u\n", (unsigned) tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *) tcph, tcplen, 0))) {
++ DEBUGP("bad csum: %p %u %u.%u.%u.%u -> %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ data_limit = (char *) data + datalen;
++ while (datalen > 5 && bytes_scanned < 128) {
++ if (memcmp(data, "s us ", 5)) {
++ data++;
++ datalen--;
++ bytes_scanned++;
++ continue;
++ }
++
++ data += 5;
++
++ DEBUGP("Userfile-share found in connection "
++ "%u.%u.%u.%u -> %u.%u.%u.%u\n",
++ NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++
++ if (parse_command((char *) data, data_limit, &egg_ip,
++ &egg_port)) {
++ DEBUGP("no data in userfile-share pkt\n");
++ return NF_ACCEPT;
++ }
++
++ memset(&exp, 0, sizeof(exp));
++
++ if (ct->tuplehash[dir].tuple.src.ip != htonl(egg_ip)) {
++ if (net_ratelimit())
++ printk("Forged Eggdrop command from "
++ "%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
++ HIPQUAD(egg_ip), egg_port);
++ return NF_ACCEPT;
++ }
++
++ exp.tuple.src.ip = iph->daddr;
++ exp.tuple.src.u.tcp.port = 0;
++ exp.tuple.dst.ip = htonl(egg_ip);
++ exp.tuple.dst.u.tcp.port = htons(egg_port);
++ exp.tuple.dst.protonum = IPPROTO_TCP;
++
++ exp.mask.dst.u.tcp.port = 0xffff;
++ exp.mask.dst.protonum = 0xffff;
++
++ DEBUGP("expect_related %u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n",
++ NIPQUAD(t.src.ip), ntohs(t.src.u.tcp.port),
++ NIPQUAD(t.dst.ip), ntohs(t.dst.u.tcp.port));
++
++ ip_conntrack_expect_related(ct, &exp);
++ break;
++ }
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper egg_helpers[MAX_PORTS];
++static char egg_names[MAX_PORTS][14]; /* eggdrop-65535 */
++
++static void deregister_helpers(void) {
++ int i;
++
++ for (i = 0; i < ports_c; i++) {
++ DEBUGP("unregistering helper for port %d\n", ports[i]);
++ ip_conntrack_helper_unregister(&egg_helpers[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret;
++ char *tmpname;
++
++ /* If no port given, default to standard eggdrop port */
++ if (ports[0] == 0)
++ ports[0] = 3333;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ memset(&egg_helpers[i], 0,
++ sizeof(struct ip_conntrack_helper));
++ egg_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
++ egg_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
++ egg_helpers[i].mask.src.u.tcp.port = 0xFFFF;
++ egg_helpers[i].mask.dst.protonum = 0xFFFF;
++ egg_helpers[i].max_expected = 1;
++ egg_helpers[i].timeout = egg_timeout;
++ egg_helpers[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ egg_helpers[i].me = THIS_MODULE;
++ egg_helpers[i].help = help;
++
++ tmpname = &egg_names[i][0];
++ if (ports[i] == 3333)
++ sprintf(tmpname, "eggdrop");
++ else
++ sprintf(tmpname, "eggdrop-%d", ports[i]);
++ egg_helpers[i].name = tmpname;
++
++ DEBUGP("port #%d: %d\n", i, ports[i]);
++
++ ret = ip_conntrack_helper_register(&egg_helpers[i]);
++
++ if (ret) {
++ printk("ip_conntrack_egg: ERROR registering helper "
++ "for port %d\n", ports[i]);
++ deregister_helpers();
++ return 1;
++ }
++ ports_c++;
++ }
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ deregister_helpers();
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_h323.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_h323.c 2004-06-08 10:38:40.000000000 +0200
+@@ -0,0 +1,308 @@
++/*
++ * H.323 'brute force' extension for H.323 connection tracking.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
++ * (http://www.coritel.it/projects/sofia/nat/)
++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
++ * the unregistered helpers to the conntrack entries.
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
++
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK(ip_h323_lock);
++struct module *ip_conntrack_h323 = THIS_MODULE;
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++/* FIXME: This should be in userspace. Later. */
++static int h245_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
++ unsigned char *data_limit;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
++ u_int16_t data_port;
++ u_int32_t data_ip;
++ unsigned int i;
++
++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(tcph->source),
++ NIPQUAD(iph->daddr), ntohs(tcph->dest));
++
++ /* Can't track connections formed before we registered */
++ if (!info)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header or too short packet? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
++ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ data_limit = (unsigned char *) data + datalen;
++ /* bytes: 0123 45
++ ipadrr port */
++ for (i = 0; data < (data_limit - 5); data++, i++) {
++ data_ip = *((u_int32_t *)data);
++ if (data_ip == iph->saddr) {
++ data_port = *((u_int16_t *)(data + 4));
++ memset(&expect, 0, sizeof(expect));
++ /* update the H.225 info */
++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(iph->saddr), ntohs(data_port));
++ LOCK_BH(&ip_h323_lock);
++ info->is_h225 = H225_PORT + 1;
++ exp_info->port = data_port;
++ exp_info->dir = dir;
++ exp_info->offset = i;
++
++ exp->seq = ntohl(tcph->seq) + i;
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip,
++ { 0 } },
++ { data_ip,
++ { .tcp = { data_port } },
++ IPPROTO_UDP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
++
++ exp->expectfn = NULL;
++
++ /* Ignore failure; should only happen with NAT */
++ ip_conntrack_expect_related(ct, exp);
++
++ UNLOCK_BH(&ip_h323_lock);
++ }
++ }
++
++ return NF_ACCEPT;
++
++}
++
++/* H.245 helper is not registered! */
++static struct ip_conntrack_helper h245 =
++ { { NULL, NULL },
++ "H.245", /* name */
++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
++ NULL, /* module */
++ 8, /* max_ expected */
++ 240, /* timeout */
++ { { 0, { 0 } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h245_help /* helper */
++ };
++
++static int h225_expect(struct ip_conntrack *ct)
++{
++ WRITE_LOCK(&ip_conntrack_lock);
++ ct->helper = &h245;
++ DEBUGP("h225_expect: helper for %p added\n", ct);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return NF_ACCEPT; /* unused */
++}
++
++/* FIXME: This should be in userspace. Later. */
++static int h225_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
++ unsigned char *data_limit;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
++ u_int16_t data_port;
++ u_int32_t data_ip;
++ unsigned int i;
++
++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(tcph->source),
++ NIPQUAD(iph->daddr), ntohs(tcph->dest));
++
++ /* Can't track connections formed before we registered */
++ if (!info)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header or too short packet? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
++ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ data_limit = (unsigned char *) data + datalen;
++ /* bytes: 0123 45
++ ipadrr port */
++ for (i = 0; data < (data_limit - 5); data++, i++) {
++ data_ip = *((u_int32_t *)data);
++ if (data_ip == iph->saddr) {
++ data_port = *((u_int16_t *)(data + 4));
++ if (data_port == tcph->source) {
++ /* Signal address */
++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
++ NIPQUAD(iph->saddr));
++ /* Update the H.225 info so that NAT can mangle the address/port
++ even when we have no expected connection! */
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ LOCK_BH(&ip_h323_lock);
++ info->dir = dir;
++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
++ info->offset[IP_CT_DIR_ORIGINAL] = i;
++ UNLOCK_BH(&ip_h323_lock);
++#endif
++ } else {
++ memset(&expect, 0, sizeof(expect));
++
++ /* update the H.225 info */
++ LOCK_BH(&ip_h323_lock);
++ info->is_h225 = H225_PORT;
++ exp_info->port = data_port;
++ exp_info->dir = dir;
++ exp_info->offset = i;
++
++ exp->seq = ntohl(tcph->seq) + i;
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip,
++ { 0 } },
++ { data_ip,
++ { .tcp = { data_port } },
++ IPPROTO_TCP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
++
++ exp->expectfn = h225_expect;
++
++ /* Ignore failure */
++ ip_conntrack_expect_related(ct, exp);
++
++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(iph->saddr), ntohs(data_port));
++
++ UNLOCK_BH(&ip_h323_lock);
++ }
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ } else if (data_ip == iph->daddr) {
++ data_port = *((u_int16_t *)(data + 4));
++ if (data_port == tcph->dest) {
++ /* Signal address */
++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
++ NIPQUAD(iph->daddr));
++ /* Update the H.225 info so that NAT can mangle the address/port
++ even when we have no expected connection! */
++ LOCK_BH(&ip_h323_lock);
++ info->dir = dir;
++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
++ info->offset[IP_CT_DIR_REPLY] = i;
++ UNLOCK_BH(&ip_h323_lock);
++ }
++#endif
++ }
++ }
++
++ return NF_ACCEPT;
++
++}
++
++static struct ip_conntrack_helper h225 =
++ { { NULL, NULL },
++ "H.225", /* name */
++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
++ THIS_MODULE, /* module */
++ 2, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_help /* helper */
++ };
++
++static int __init init(void)
++{
++ return ip_conntrack_helper_register(&h225);
++}
++
++static void __exit fini(void)
++{
++ /* Unregister H.225 helper */
++ ip_conntrack_helper_unregister(&h225);
++}
++
++EXPORT_SYMBOL(ip_h323_lock);
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_mms.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_mms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_mms.c 2004-06-08 10:39:44.000000000 +0200
+@@ -0,0 +1,308 @@
++/* MMS extension for IP connection tracking
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_conntrack_ftp.c and ip_conntrack_irc.c
++ *
++ * ip_conntrack_mms.c v0.3 2002-09-22
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * Please give the ports of all MMS servers You wish to connect to.
++ * If you don't specify ports, the default will be TCP port 1755.
++ *
++ * More info on MMS protocol, firewalls and NAT:
++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
++ *
++ * The SDP project people are reverse-engineering MMS:
++ * http://get.to/sdp
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/ctype.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
++
++DECLARE_LOCK(ip_mms_lock);
++struct module *ip_conntrack_mms = THIS_MODULE;
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c;
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++#endif
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++EXPORT_SYMBOL(ip_mms_lock);
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module");
++MODULE_LICENSE("GPL");
++
++/* #define isdigit(c) (c >= '0' && c <= '9') */
++
++/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */
++static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
++{
++ int i;
++ for (i = 0; i < unicode_size; ++i) {
++ string[i] = (char)(unicode[i]);
++ }
++ string[unicode_size] = 0x00;
++}
++
++__inline static int atoi(char *s)
++{
++ int i=0;
++ while (isdigit(*s)) {
++ i = i*10 + *(s++) - '0';
++ }
++ return i;
++}
++
++/* convert ip address string like "192.168.0.10" to unsigned int */
++__inline static u_int32_t asciiiptoi(char *s)
++{
++ unsigned int i, j, k;
++
++ for(i=k=0; k<3; ++k, ++s, i<<=8) {
++ i+=atoi(s);
++ for(j=0; (*(++s) != '.') && (j<3); ++j)
++ ;
++ }
++ i+=atoi(s);
++ return ntohl(i);
++}
++
++int parse_mms(const char *data,
++ const unsigned int datalen,
++ u_int32_t *mms_ip,
++ u_int16_t *mms_proto,
++ u_int16_t *mms_port,
++ char **mms_string_b,
++ char **mms_string_e,
++ char **mms_padding_e)
++{
++ int unicode_size, i;
++ char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */
++ char getlengthstring[28];
++
++ for(unicode_size=0;
++ (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0;
++ unicode_size++)
++ if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen))
++ return -1; /* out of bounds - incomplete packet */
++
++ unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size);
++ DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring));
++
++ /* IP address ? */
++ *mms_ip = asciiiptoi(tempstring+2);
++
++ i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip));
++
++ /* protocol ? */
++ if(strncmp(tempstring+3+i, "TCP", 3)==0)
++ *mms_proto = IPPROTO_TCP;
++ else if(strncmp(tempstring+3+i, "UDP", 3)==0)
++ *mms_proto = IPPROTO_UDP;
++
++ /* port ? */
++ *mms_port = atoi(tempstring+7+i);
++
++ /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port"
++ unicode string, one to the end of the string, and one to the end
++ of the packet, since we must keep track of the number of bytes
++ between end of the unicode string and the end of packet (padding) */
++ *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET);
++ *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2);
++ *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */
++ return 0;
++}
++
++
++/* FIXME: This should be in userspace. Later. */
++static int help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guaranteed by ip_conntrack_tcp.c */
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ const char *data = (const char *)tcph + tcph->doff * 4;
++ unsigned int tcplen = len - iph->ihl * 4;
++ unsigned int datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info;
++
++ u_int32_t mms_ip;
++ u_int16_t mms_proto;
++ char mms_proto_string[8];
++ u_int16_t mms_port;
++ char *mms_string_b, *mms_string_e, *mms_padding_e;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
++ DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
++ DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */
++ /* FIXME: There is an issue with only looking at this packet: before this packet,
++ the client has already sent a packet to the server with the server's hostname
++ according to the client (think of it as the "Host: " header in HTTP/1.1). The
++ server will break the connection if this doesn't correspond to its own host
++ header. The client can also connect to an IP address; if it's the server's IP
++ address, it will not break the connection. When doing DNAT on a connection
++ where the client uses a server's IP address, the nat module should detect
++ this and change this string accordingly to the DNATed address. This should
++ probably be done by checking for an IP address, then storing it as a member
++ of struct ip_ct_mms_expect and checking for it in ip_nat_mms...
++ */
++ if( (MMS_SRV_MSG_OFFSET < datalen) &&
++ ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
++ DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n",
++ (u8)*(data+36), (u8)*(data+37),
++ (u8)*(data+38), (u8)*(data+39),
++ datalen);
++ if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
++ &mms_string_b, &mms_string_e, &mms_padding_e))
++ if(net_ratelimit())
++ /* FIXME: more verbose debugging ? */
++ printk(KERN_WARNING
++ "ip_conntrack_mms: Unable to parse data payload\n");
++
++ memset(&expect, 0, sizeof(expect));
++
++ sprintf(mms_proto_string, "(%u)", mms_proto);
++ DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
++ mms_proto == IPPROTO_TCP ? "TCP"
++ : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(mms_ip),
++ mms_port);
++
++ /* it's possible that the client will just ask the server to tunnel
++ the stream over the same TCP session (from port 1755): there's
++ shouldn't be a need to add an expectation in that case, but it
++ makes NAT packet mangling so much easier */
++ LOCK_BH(&ip_mms_lock);
++
++ DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);
++
++ exp->seq = ntohl(tcph->seq) + (mms_string_b - data);
++ exp_mms_info->len = (mms_string_e - mms_string_b);
++ exp_mms_info->padding = (mms_padding_e - mms_string_e);
++ exp_mms_info->port = mms_port;
++
++ DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n",
++ exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding);
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
++ { mms_ip,
++ { .tcp = { (__u16) ntohs(mms_port) } },
++ mms_proto } }
++ );
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
++ exp->expectfn = NULL;
++ ip_conntrack_expect_related(ct, &expect);
++ UNLOCK_BH(&ip_mms_lock);
++ }
++
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper mms[MAX_PORTS];
++static char mms_names[MAX_PORTS][10];
++
++/* Not __exit: called from init() */
++static void fini(void)
++{
++ int i;
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n",
++ ports[i]);
++ ip_conntrack_helper_unregister(&mms[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret;
++ char *tmpname;
++
++ if (ports[0] == 0)
++ ports[0] = MMS_PORT;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ memset(&mms[i], 0, sizeof(struct ip_conntrack_helper));
++ mms[i].tuple.src.u.tcp.port = htons(ports[i]);
++ mms[i].tuple.dst.protonum = IPPROTO_TCP;
++ mms[i].mask.src.u.tcp.port = 0xFFFF;
++ mms[i].mask.dst.protonum = 0xFFFF;
++ mms[i].max_expected = 1;
++ mms[i].timeout = 0;
++ mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ mms[i].me = THIS_MODULE;
++ mms[i].help = help;
++
++ tmpname = &mms_names[i][0];
++ if (ports[i] == MMS_PORT)
++ sprintf(tmpname, "mms");
++ else
++ sprintf(tmpname, "mms-%d", ports[i]);
++ mms[i].name = tmpname;
++
++ DEBUGP("ip_conntrack_mms: registering helper for port %d\n",
++ ports[i]);
++ ret = ip_conntrack_helper_register(&mms[i]);
++
++ if (ret) {
++ fini();
++ return ret;
++ }
++ ports_c++;
++ }
++ return 0;
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_proto_sctp.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_proto_sctp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_proto_sctp.c 2004-06-08 10:40:55.000000000 +0200
+@@ -0,0 +1,529 @@
++/*
++ * Connection tracking protocol helper module for SCTP.
++ *
++ * SCTP is defined in RFC 2960. References to various sections in this code
++ * are to this RFC.
++ *
++ * 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/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/netfilter.h>
++#include <linux/module.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/sctp.h>
++#include <linux/string.h>
++
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++#if 0
++#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++/* Protects conntrack->proto.sctp */
++static DECLARE_RWLOCK(sctp_lock);
++
++/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
++ closely. They're more complex. --RR
++
++ And so for me for SCTP :D -Kiran */
++
++static const char *sctp_conntrack_names[] = {
++ "NONE",
++ "CLOSED",
++ "COOKIE_WAIT",
++ "COOKIE_ECHOED",
++ "ESTABLISHED",
++ "SHUTDOWN_SENT",
++ "SHUTDOWN_RECD",
++ "SHUTDOWN_ACK_SENT",
++};
++
++#define SECS * HZ
++#define MINS * 60 SECS
++#define HOURS * 60 MINS
++#define DAYS * 24 HOURS
++
++unsigned long ip_ct_sctp_timeout_closed = 10 SECS;
++unsigned long ip_ct_sctp_timeout_cookie_wait = 3 SECS;
++unsigned long ip_ct_sctp_timeout_cookie_echoed = 3 SECS;
++unsigned long ip_ct_sctp_timeout_established = 5 DAYS;
++unsigned long ip_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000;
++unsigned long ip_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;
++unsigned long ip_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;
++
++static unsigned long * sctp_timeouts[]
++= { 0, /* SCTP_CONNTRACK_NONE */
++ &ip_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */
++ &ip_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */
++ &ip_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */
++ &ip_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */
++ &ip_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */
++ &ip_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */
++ &ip_ct_sctp_timeout_shutdown_ack_sent /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */
++ };
++
++#define sNO SCTP_CONNTRACK_NONE
++#define sCL SCTP_CONNTRACK_CLOSED
++#define sCW SCTP_CONNTRACK_COOKIE_WAIT
++#define sCE SCTP_CONNTRACK_COOKIE_ECHOED
++#define sES SCTP_CONNTRACK_ESTABLISHED
++#define sSS SCTP_CONNTRACK_SHUTDOWN_SENT
++#define sSR SCTP_CONNTRACK_SHUTDOWN_RECD
++#define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
++#define sIV SCTP_CONNTRACK_MAX
++
++/*
++ These are the descriptions of the states:
++
++NOTE: These state names are tantalizingly similar to the states of an
++SCTP endpoint. But the interpretation of the states is a little different,
++considering that these are the states of the connection and not of an end
++point. Please note the subtleties. -Kiran
++
++NONE - Nothing so far.
++COOKIE WAIT - We have seen an INIT chunk in the original direction, or also
++ an INIT_ACK chunk in the reply direction.
++COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction.
++ESTABLISHED - We have seen a COOKIE_ACK in the reply direction.
++SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction.
++SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin.
++SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
++ to that of the SHUTDOWN chunk.
++CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of
++ the SHUTDOWN chunk. Connection is closed.
++*/
++
++/* TODO
++ - I have assumed that the first INIT is in the original direction.
++ This messes things when an INIT comes in the reply direction in CLOSED
++ state.
++ - Check the error type in the reply dir before transitioning from
++cookie echoed to closed.
++ - Sec 5.2.4 of RFC 2960
++ - Multi Homing support.
++*/
++
++/* SCTP conntrack state transitions */
++static enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
++ {
++/* ORIGINAL */
++/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
++/* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},
++/* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},
++/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
++/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
++/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
++/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
++/* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
++/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
++/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
++ },
++ {
++/* REPLY */
++/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
++/* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */
++/* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},
++/* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
++/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
++/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
++/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
++/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
++/* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
++/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
++ }
++};
++
++static int sctp_pkt_to_tuple(const struct sk_buff *skb,
++ unsigned int dataoff,
++ struct ip_conntrack_tuple *tuple)
++{
++ sctp_sctphdr_t hdr;
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ /* Actually only need first 8 bytes. */
++ if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
++ return 0;
++
++ tuple->src.u.sctp.port = hdr.source;
++ tuple->dst.u.sctp.port = hdr.dest;
++
++ return 1;
++}
++
++static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *orig)
++{
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ tuple->src.u.sctp.port = orig->dst.u.sctp.port;
++ tuple->dst.u.sctp.port = orig->src.u.sctp.port;
++ return 1;
++}
++
++/* Print out the per-protocol part of the tuple. */
++static unsigned int sctp_print_tuple(char *buffer,
++ const struct ip_conntrack_tuple *tuple)
++{
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ return sprintf(buffer, "sport=%hu dport=%hu ",
++ ntohs(tuple->src.u.sctp.port),
++ ntohs(tuple->dst.u.sctp.port));
++}
++
++/* Print out the private part of the conntrack. */
++static unsigned int sctp_print_conntrack(char *buffer,
++ const struct ip_conntrack *conntrack)
++{
++ enum sctp_conntrack state;
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ READ_LOCK(&sctp_lock);
++ state = conntrack->proto.sctp.state;
++ READ_UNLOCK(&sctp_lock);
++
++ return sprintf(buffer, "%s ", sctp_conntrack_names[state]);
++}
++
++#define for_each_sctp_chunk(skb, sch, offset, count) \
++for (offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t), count = 0; \
++ offset < skb->len && !skb_copy_bits(skb, offset, &sch, sizeof(sch)); \
++ offset += (htons(sch.length) + 3) & ~3, count++)
++
++/* Some validity checks to make sure the chunks are fine */
++static int do_basic_checks(struct ip_conntrack *conntrack,
++ const struct sk_buff *skb,
++ char *map)
++{
++ u_int32_t offset, count;
++ sctp_chunkhdr_t sch;
++ int flag;
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ flag = 0;
++
++ for_each_sctp_chunk (skb, sch, offset, count) {
++ DEBUGP("Chunk Num: %d Type: %d\n", count, sch.type);
++
++ if (sch.type == SCTP_CID_INIT
++ || sch.type == SCTP_CID_INIT_ACK
++ || sch.type == SCTP_CID_SHUTDOWN_COMPLETE) {
++ flag = 1;
++ }
++
++ /* Cookie Ack/Echo chunks not the first OR
++ Init / Init Ack / Shutdown compl chunks not the only chunks */
++ if ((sch.type == SCTP_CID_COOKIE_ACK
++ || sch.type == SCTP_CID_COOKIE_ECHO
++ || flag)
++ && count !=0 ) {
++ DEBUGP("Basic checks failed\n");
++ return 1;
++ }
++
++ if (map) {
++ set_bit (sch.type, (void *)map);
++ }
++ }
++
++ DEBUGP("Basic checks passed\n");
++ return 0;
++}
++
++static int new_state(enum ip_conntrack_dir dir,
++ enum sctp_conntrack cur_state,
++ int chunk_type)
++{
++ int i;
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ DEBUGP("Chunk type: %d\n", chunk_type);
++
++ switch (chunk_type) {
++ case SCTP_CID_INIT:
++ DEBUGP("SCTP_CID_INIT\n");
++ i = 0; break;
++ case SCTP_CID_INIT_ACK:
++ DEBUGP("SCTP_CID_INIT_ACK\n");
++ i = 1; break;
++ case SCTP_CID_ABORT:
++ DEBUGP("SCTP_CID_ABORT\n");
++ i = 2; break;
++ case SCTP_CID_SHUTDOWN:
++ DEBUGP("SCTP_CID_SHUTDOWN\n");
++ i = 3; break;
++ case SCTP_CID_SHUTDOWN_ACK:
++ DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
++ i = 4; break;
++ case SCTP_CID_ERROR:
++ DEBUGP("SCTP_CID_ERROR\n");
++ i = 5; break;
++ case SCTP_CID_COOKIE_ECHO:
++ DEBUGP("SCTP_CID_COOKIE_ECHO\n");
++ i = 6; break;
++ case SCTP_CID_COOKIE_ACK:
++ DEBUGP("SCTP_CID_COOKIE_ACK\n");
++ i = 7; break;
++ case SCTP_CID_SHUTDOWN_COMPLETE:
++ DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
++ i = 8; break;
++ default:
++ /* Other chunks like DATA, SACK, HEARTBEAT and
++ its ACK do not cause a change in state */
++ DEBUGP("Unknown chunk type, Will stay in %s\n",
++ sctp_conntrack_names[cur_state]);
++ return cur_state;
++ }
++
++ DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n",
++ dir, sctp_conntrack_names[cur_state], chunk_type,
++ sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
++
++ return sctp_conntracks[dir][i][cur_state];
++}
++
++/* Returns verdict for packet, or -1 for invalid. */
++static int sctp_packet(struct ip_conntrack *conntrack,
++ const struct sk_buff *skb,
++ enum ip_conntrack_info ctinfo)
++{
++ enum sctp_conntrack newconntrack, oldsctpstate;
++ sctp_sctphdr_t sctph;
++ sctp_chunkhdr_t sch;
++ u_int32_t offset, count;
++ char map[256 / sizeof (char)] = {0};
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &sctph, sizeof(sctph)) != 0)
++ return -1;
++
++ if (do_basic_checks(conntrack, skb, map) != 0)
++ return -1;
++
++ /* Check the verification tag (Sec 8.5) */
++ if (!test_bit(SCTP_CID_INIT, (void *)map)
++ && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)
++ && !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
++ && !test_bit(SCTP_CID_ABORT, (void *)map)
++ && !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
++ && (sctph.vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
++ DEBUGP("Verification tag check failed\n");
++ return -1;
++ }
++
++ oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
++ for_each_sctp_chunk (skb, sch, offset, count) {
++ WRITE_LOCK(&sctp_lock);
++
++ /* Special cases of Verification tag check (Sec 8.5.1) */
++ if (sch.type == SCTP_CID_INIT) {
++ /* Sec 8.5.1 (A) */
++ if (sctph.vtag != 0) {
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++ } else if (sch.type == SCTP_CID_ABORT) {
++ /* Sec 8.5.1 (B) */
++ if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
++ && !(sctph.vtag == conntrack->proto.sctp.vtag
++ [1 - CTINFO2DIR(ctinfo)])) {
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++ } else if (sch.type == SCTP_CID_SHUTDOWN_COMPLETE) {
++ /* Sec 8.5.1 (C) */
++ if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
++ && !(sctph.vtag == conntrack->proto.sctp.vtag
++ [1 - CTINFO2DIR(ctinfo)]
++ && (sch.flags & 1))) {
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++ } else if (sch.type == SCTP_CID_COOKIE_ECHO) {
++ /* Sec 8.5.1 (D) */
++ if (!(sctph.vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++ }
++
++ oldsctpstate = conntrack->proto.sctp.state;
++ newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch.type);
++
++ /* Invalid */
++ if (newconntrack == SCTP_CONNTRACK_MAX) {
++ DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
++ CTINFO2DIR(ctinfo), sch.type, oldsctpstate);
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++
++ /* If it is an INIT or an INIT ACK note down the vtag */
++ if (sch.type == SCTP_CID_INIT
++ || sch.type == SCTP_CID_INIT_ACK) {
++ sctp_inithdr_t inithdr;
++
++ if (skb_copy_bits(skb, offset + sizeof (sctp_chunkhdr_t),
++ &inithdr, sizeof(inithdr)) != 0) {
++ WRITE_UNLOCK(&sctp_lock);
++ return -1;
++ }
++ DEBUGP("Setting vtag %x for dir %d\n",
++ inithdr.init_tag, CTINFO2DIR(ctinfo));
++ conntrack->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = inithdr.init_tag;
++ }
++
++ conntrack->proto.sctp.state = newconntrack;
++ WRITE_UNLOCK(&sctp_lock);
++ }
++
++ ip_ct_refresh(conntrack, *sctp_timeouts[newconntrack]);
++
++ if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
++ && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
++ && newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
++ DEBUGP("Setting assured bit\n");
++ set_bit(IPS_ASSURED_BIT, &conntrack->status);
++ }
++
++ return NF_ACCEPT;
++}
++
++/* Called when a new connection for this protocol found. */
++static int sctp_new(struct ip_conntrack *conntrack,
++ const struct sk_buff *skb)
++{
++ enum sctp_conntrack newconntrack;
++ sctp_sctphdr_t sctph;
++ sctp_chunkhdr_t sch;
++ u_int32_t offset, count;
++ char map[256 / sizeof (char)] = {0};
++
++ DEBUGP(__FUNCTION__);
++ DEBUGP("\n");
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &sctph, sizeof(sctph)) != 0)
++ return -1;
++
++ if (do_basic_checks(conntrack, skb, map) != 0)
++ return -1;
++
++ /* If an OOTB packet has any of these chunks discard (Sec 8.4) */
++ if ((test_bit (SCTP_CID_ABORT, (void *)map))
++ || (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map))
++ || (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) {
++ return -1;
++ }
++
++ newconntrack = SCTP_CONNTRACK_MAX;
++ for_each_sctp_chunk (skb, sch, offset, count) {
++ /* Don't need lock here: this conntrack not in circulation yet */
++ newconntrack = new_state (IP_CT_DIR_ORIGINAL,
++ SCTP_CONNTRACK_NONE, sch.type);
++
++ /* Invalid: delete conntrack */
++ if (newconntrack == SCTP_CONNTRACK_MAX) {
++ DEBUGP("ip_conntrack_sctp: invalid new deleting.\n");
++ return 0;
++ }
++
++ /* Copy the vtag into the state info */
++ if (sch.type == SCTP_CID_INIT) {
++ if (sctph.vtag == 0) {
++ sctp_inithdr_t inithdr;
++
++ if (skb_copy_bits(skb, offset + sizeof (sctp_chunkhdr_t),
++ &inithdr, sizeof(inithdr)) != 0) {
++ return -1;
++ }
++
++ DEBUGP("Setting vtag %x for new conn\n",
++ inithdr.init_tag);
++
++ conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] =
++ inithdr.init_tag;
++ } else {
++ /* Sec 8.5.1 (A) */
++ return -1;
++ }
++ }
++ /* If it is a shutdown ack OOTB packet, we expect a return
++ shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
++ else {
++ DEBUGP("Setting vtag %x for new conn OOTB\n",
++ sctph.vtag);
++ conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sctph.vtag;
++ }
++
++ conntrack->proto.sctp.state = newconntrack;
++ }
++
++ return 1;
++}
++
++static int sctp_exp_matches_pkt(struct ip_conntrack_expect *exp,
++ const struct sk_buff *skb)
++{
++ /* To be implemented */
++ return 0;
++}
++
++struct ip_conntrack_protocol ip_conntrack_protocol_sctp = {
++ .list = { NULL, NULL },
++ .proto = IPPROTO_SCTP,
++ .name = "sctp",
++ .pkt_to_tuple = sctp_pkt_to_tuple,
++ .invert_tuple = sctp_invert_tuple,
++ .print_tuple = sctp_print_tuple,
++ .print_conntrack = sctp_print_conntrack,
++ .packet = sctp_packet,
++ .new = sctp_new,
++ .destroy = NULL,
++ .exp_matches_pkt = sctp_exp_matches_pkt,
++ .me = THIS_MODULE
++};
++
++int __init init(void)
++{
++ int ret;
++
++ ret = ip_conntrack_protocol_register(&ip_conntrack_protocol_sctp);
++ DEBUGP("SCTP conntrack module loading %s\n",
++ ret ? "failed": "succeeded");
++ return ret;
++}
++
++void __exit fini(void)
++{
++ ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
++ DEBUGP("SCTP conntrack module unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Kiran Kumar Immidi");
++MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP");
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_quake3.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_quake3.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_quake3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_quake3.c 2004-06-08 10:40:36.000000000 +0200
+@@ -0,0 +1,156 @@
++/* Quake3 extension for IP connection tracking
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_conntrack_ftp.c and ip_conntrack_tftp.c
++ *
++ * ip_conntrack_quake3.c v0.04 2002-08-31
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_conntrack_quake3.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * please give the ports of all Quake3 master servers You wish to
++ * connect to. If you don't specify ports, the default will be UDP
++ * port 27950.
++ *
++ * Thanks to the Ethereal folks for their analysis of the Quake3 protocol.
++ */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/udp.h>
++
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_quake3.h>
++
++struct module *ip_conntrack_quake3 = THIS_MODULE;
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Netfilter connection tracking module for Quake III Arena");
++MODULE_LICENSE("GPL");
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c = 0;
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of Quake III master servers");
++#endif
++
++/* Quake3 master server reply will add > 100 expectations per reply packet; when
++ doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++struct quake3_search quake3s_conntrack = { "****", "getserversResponse", sizeof("getserversResponse") - 1 };
++
++static int quake3_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_conntrack_expect exp;
++ int i;
++
++ /* Until there's been traffic both ways, don't look in packets. note: it's UDP ! */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_IS_REPLY) {
++ DEBUGP("ip_conntrack_quake3: not ok ! Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ } else { DEBUGP("ip_conntrack_quake3: it's ok ! Conntrackinfo = %u\n", ctinfo); }
++
++ if (strnicmp((const char *)udph + 12, quake3s_conntrack.pattern, quake3s_conntrack.plen) == 0) {
++ for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */
++ i+6 < ntohs(udph->len);
++ i+=7) {
++ DEBUGP("ip_conntrack_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n",
++ i, ntohs(udph->len),
++ NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ),
++ ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) );
++
++ memset(&exp, 0, sizeof(exp));
++
++ exp.tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
++ { (u_int32_t) *((u_int32_t *)((int)udph + i)),
++ { .udp = { (__u16) *((__u16 *)((int)udph+i+4)) } },
++ IPPROTO_UDP } }
++ );
++ exp.mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 0xFFFF }});
++ exp.expectfn = NULL;
++
++ ip_conntrack_expect_related(ct, &exp);
++ }
++
++ }
++
++ return(NF_ACCEPT);
++}
++
++static struct ip_conntrack_helper quake3[MAX_PORTS];
++static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */
++
++static void fini(void)
++{
++ int i;
++
++ for(i = 0 ; (i < ports_c); i++) {
++ DEBUGP("ip_conntrack_quake3: unregistering helper for port %d\n",
++ ports[i]);
++ ip_conntrack_helper_unregister(&quake3[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret;
++ char *tmpname;
++
++ if(!ports[0])
++ ports[0]=QUAKE3_MASTER_PORT;
++
++ for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
++ /* Create helper structure */
++ memset(&quake3[i], 0, sizeof(struct ip_conntrack_helper));
++
++ quake3[i].tuple.dst.protonum = IPPROTO_UDP;
++ quake3[i].tuple.src.u.udp.port = htons(ports[i]);
++ quake3[i].mask.dst.protonum = 0xFFFF;
++ quake3[i].mask.src.u.udp.port = 0xFFFF;
++ quake3[i].help = quake3_help;
++ quake3[i].me = THIS_MODULE;
++
++ tmpname = &quake3_names[i][0];
++ if (ports[i] == QUAKE3_MASTER_PORT)
++ sprintf(tmpname, "quake3");
++ else
++ sprintf(tmpname, "quake3-%d", i);
++ quake3[i].name = tmpname;
++
++ DEBUGP("ip_conntrack_quake3: registering helper for port %d\n",
++ ports[i]);
++
++ ret=ip_conntrack_helper_register(&quake3[i]);
++ if(ret) {
++ fini();
++ return(ret);
++ }
++ ports_c++;
++ }
++
++ return(0);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_rsh.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_rsh.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_rsh.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_rsh.c 2004-06-08 10:40:43.000000000 +0200
+@@ -0,0 +1,331 @@
++/* RSH extension for IP connection tracking, Version 1.0
++ * (C) 2002 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
++ * based on HW's ip_conntrack_irc.c
++ *
++ * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ **
++ * Module load syntax:
++ * insmod ip_conntrack_rsh.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * please give the ports of all RSH servers You wish to connect to.
++ * If You don't specify ports, the default will be port 514
++ **
++ * Note to all:
++ * RSH blows ... you should use SSH (openssh.org) to replace it,
++ * unfortunately I babysit some sysadmins that won't migrate
++ * their legacy crap, in our second tier.
++ */
++
++
++/*
++ * Some docco ripped from the net to teach me all there is to know about
++ * RSH, in 16.5 seconds (ie, all of the non-netfilter docco used to write
++ * this module).
++ *
++ * I have no idea what "unix rshd man pages" these guys have .. but that
++ * is some pretty detailed docco!
++ **
++ *
++ * 4. Of the rsh protocol.
++ * -----------------------
++ *
++ * The rshd listens on TCP port #514. The following info is from the unix
++ * rshd man pages :
++ *
++ * "Service Request Protocol
++ *
++ * When the rshd daemon receives a service request, it initiates the
++ * following protocol:
++ *
++ * 1. The rshd daemon checks the source port number for the request.
++ * If the port number is not in the range 0 through 1023, the rshd daemon
++ * terminates the connection.
++ *
++ * 2. The rshd daemon reads characters from the socket up to a null byte.
++ * The string read is interpreted as an ASCII number (base 10). If this
++ * number is nonzero, the rshd daemon interprets it as the port number
++ * of a secondary stream to be used as standard error. A second connection
++ * is created to the specified port on the client host. The source port
++ * on the local host is in the range 0 through 1023.
++ *
++ * 3. The rshd daemon uses the source address of the initial connection
++ * request to determine the name of the client host. If the name cannot
++ * be determined, the rshd daemon uses the dotted decimal representation
++ * of the client host's address.
++ *
++ * 4. The rshd daemon retrieves the following information from the initial
++ * socket:
++ *
++ * * A null-terminated string of at most 16 bytes interpreted as
++ * the user name of the user on the client host.
++ *
++ * * A null-terminated string of at most 16 bytes interpreted as
++ * the user name to be used on the local server host.
++ *
++ * * Another null-terminated string interpreted as a command line
++ * to be passed to a shell on the local server host.
++ *
++ * 5. The rshd daemon attempts to validate the user using the following steps:
++ *
++ * a. The rshd daemon looks up the local user name in the /etc/passwd
++ * file and tries to switch to the home directory (using the chdir
++ * subroutine). If either the lookup or the directory change fails,
++ * the rshd daemon terminates the connection.
++ *
++ * b. If the local user ID is a nonzero value, the rshd daemon searches
++ * the /etc/hosts.equiv file to see if the name of the client
++ * workstation is listed. If the client workstation is listed as an
++ * equivalent host, the rshd daemon validates the user.
++ *
++ * c. If the $HOME/.rhosts file exists, the rshd daemon tries to
++ * authenticate the user by checking the .rhosts file.
++ *
++ * d. If either the $HOME/.rhosts authentication fails or the
++ * client host is not an equivalent host, the rshd daemon
++ * terminates the connection.
++ *
++ * 6. Once rshd validates the user, the rshd daemon returns a null byte
++ * on the initial connection and passes the command line to the user's
++ * local login shell. The shell then inherits the network connections
++ * established by the rshd daemon."
++ *
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rsh.h>
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_n_c = 0;
++
++MODULE_AUTHOR("Ian (Larry) Latter <Ian.Latter@mq.edu.au>");
++MODULE_DESCRIPTION("RSH connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RSH servers");
++#endif
++
++DECLARE_LOCK(ip_rsh_lock);
++struct module *ip_conntrack_rsh = THIS_MODULE;
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rsh: " \
++ format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++
++
++/* FIXME: This should be in userspace. Later. */
++static int help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ const char *data = (const char *) tcph + tcph->doff * 4;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info;
++ u_int16_t port;
++ int maxoctet;
++
++ /* note that "maxoctet" is used to maintain sanity (8 was the
++ * original array size used in rshd/glibc) -- is there a
++ * vulnerability in rshd.c in the looped port *= 10?
++ */
++
++
++ DEBUGP("entered\n");
++
++ /* bail if packet is not from RSH client */
++ if (dir == IP_CT_DIR_REPLY)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
++ DEBUGP("tcplen = %u\n", (unsigned) tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *) tcph, tcplen, 0))) {
++ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ /* find the rsh stderr port */
++ maxoctet = 4;
++ port = 0;
++ for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) {
++ if (*data < 0)
++ return(1);
++ if (*data == 0)
++ break;
++ if (*data < 48 || *data > 57) {
++ DEBUGP("these aren't the packets you're looking for ..\n");
++ return NF_ACCEPT;
++ }
++ port = port * 10 + ( *data - 48 );
++ }
++
++ /* dont relate sessions that try to expose the client */
++ DEBUGP("found port %u\n", port);
++ if (port > 1023) {
++ DEBUGP("skipping, expected port size is greater than 1023!\n");
++ return NF_ACCEPT;
++ }
++
++
++ LOCK_BH(&ip_rsh_lock);
++
++ /* new(,related) connection is;
++ * reply + dst (uint)port + src port (0:1023)
++ */
++ memset(&expect, 0, sizeof(expect));
++
++ /* save some discovered data, in case someone ever wants to write
++ * a NAT module for this bastard ..
++ */
++ exp_rsh_info->port = port;
++
++ DEBUGP("wrote info port=%u\n", exp_rsh_info->port);
++
++
++ /* Watch out, Radioactive-Man! */
++ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++ exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
++ exp->tuple.src.u.tcp.port = 0;
++ exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port);
++ exp->tuple.dst.protonum = IPPROTO_TCP;
++
++ exp->mask.src.ip = 0xffffffff;
++ exp->mask.dst.ip = 0xffffffff;
++
++ exp->mask.src.u.tcp.port = htons(0xfc00);
++ exp->mask.dst.u.tcp.port = htons(0xfc00);
++ exp->mask.dst.protonum = 0xffff;
++
++ exp->expectfn = NULL;
++
++ ip_conntrack_expect_related(ct, &expect);
++
++ DEBUGP("expect related ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(exp->tuple.src.ip),
++ ntohs(exp->tuple.src.u.tcp.port),
++ NIPQUAD(exp->tuple.dst.ip),
++ ntohs(exp->tuple.dst.u.tcp.port));
++
++ DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(exp->mask.src.ip),
++ ntohs(exp->mask.src.u.tcp.port),
++ NIPQUAD(exp->mask.dst.ip),
++ ntohs(exp->mask.dst.u.tcp.port));
++ UNLOCK_BH(&ip_rsh_lock);
++
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper rsh_helpers[MAX_PORTS];
++
++static void fini(void);
++
++static int __init init(void)
++{
++ int port, ret;
++ static char name[10];
++
++
++ /* If no port given, default to standard RSH port */
++ if (ports[0] == 0)
++ ports[0] = RSH_PORT;
++
++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
++ memset(&rsh_helpers[port], 0, sizeof(struct ip_conntrack_helper));
++
++ if (ports[port] == RSH_PORT)
++ sprintf(name, "rsh");
++ else
++ sprintf(name, "rsh-%d", port);
++
++ rsh_helpers[port].name = name;
++ rsh_helpers[port].me = THIS_MODULE;
++ rsh_helpers[port].max_expected = 1;
++ rsh_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ rsh_helpers[port].timeout = 0;
++
++ rsh_helpers[port].tuple.dst.protonum = IPPROTO_TCP;
++ rsh_helpers[port].mask.dst.protonum = 0xffff;
++
++ /* RSH must come from ports 0:1023 to ports[port] (514) */
++ rsh_helpers[port].tuple.src.u.tcp.port = htons(ports[port]);
++ rsh_helpers[port].mask.src.u.tcp.port = htons(0xfc00);
++ rsh_helpers[port].mask.dst.u.tcp.port = htons(0xfc00);
++
++ rsh_helpers[port].help = help;
++
++ DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]);
++ DEBUGP("helper match ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(rsh_helpers[port].tuple.src.ip),
++ ntohs(rsh_helpers[port].tuple.src.u.tcp.port),
++ NIPQUAD(rsh_helpers[port].tuple.dst.ip),
++ ntohs(rsh_helpers[port].tuple.dst.u.tcp.port));
++ DEBUGP("helper match mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(rsh_helpers[port].mask.src.ip),
++ ntohs(rsh_helpers[port].mask.src.u.tcp.port),
++ NIPQUAD(rsh_helpers[port].mask.dst.ip),
++ ntohs(rsh_helpers[port].mask.dst.u.tcp.port));
++
++ ret = ip_conntrack_helper_register(&rsh_helpers[port]);
++
++ if (ret) {
++ printk("ERROR registering port %d\n",
++ ports[port]);
++ fini();
++ return -EBUSY;
++ }
++ ports_n_c++;
++ }
++ return 0;
++}
++
++/* This function is intentionally _NOT_ defined as __exit, because
++ * it is needed by the init function */
++static void fini(void)
++{
++ int port;
++ for (port = 0; (port < MAX_PORTS) && ports[port]; port++) {
++ DEBUGP("unregistering port %d\n", ports[port]);
++ ip_conntrack_helper_unregister(&rsh_helpers[port]);
++ }
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_rtsp.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_rtsp.c 2004-06-08 10:40:46.000000000 +0200
+@@ -0,0 +1,507 @@
++/*
++ * RTSP extension for IP connection tracking
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ * max_outstanding=n setup_timeout=secs
++ *
++ * If no ports are specified, the default will be port 554.
++ *
++ * With max_outstanding you can define the maximum number of not yet
++ * answered SETUP requests per RTSP session (default 8).
++ * With setup_timeout you can specify how long the system waits for
++ * an expected data channel (default 300 seconds).
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#define NF_NEED_STRTOU32
++#define NF_NEED_NEXTLINE
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
++
++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#else
++#define DEBUGP(fmt, args...)
++#endif
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int num_ports = 0;
++static int max_outstanding = 8;
++static unsigned int setup_timeout = 300;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(max_outstanding, "i");
++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
++MODULE_PARM(setup_timeout, "i");
++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
++#endif
++
++DECLARE_LOCK(ip_rtsp_lock);
++struct module* ip_conntrack_rtsp = THIS_MODULE;
++
++/*
++ * Max mappings we will allow for one RTSP connection (for RTP, the number
++ * of allocated ports is twice this value). Note that SMIL burns a lot of
++ * ports so keep this reasonably high. If this is too low, you will see a
++ * lot of "no free client map entries" messages.
++ */
++#define MAX_PORT_MAPS 16
++
++/*** default port list was here in the masq code: 554, 3030, 4040 ***/
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*
++ * Parse an RTSP packet.
++ *
++ * Returns zero if parsing failed.
++ *
++ * Parameters:
++ * IN ptcp tcp data pointer
++ * IN tcplen tcp data len
++ * IN/OUT ptcpoff points to current tcp offset
++ * OUT phdrsoff set to offset of rtsp headers
++ * OUT phdrslen set to length of rtsp headers
++ * OUT pcseqoff set to offset of CSeq header
++ * OUT pcseqlen set to length of CSeq header
++ */
++static int
++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
++ uint* phdrsoff, uint* phdrslen,
++ uint* pcseqoff, uint* pcseqlen)
++{
++ uint entitylen = 0;
++ uint lineoff;
++ uint linelen;
++
++ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++ {
++ return 0;
++ }
++
++ *phdrsoff = *ptcpoff;
++ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ if (entitylen > 0)
++ {
++ *ptcpoff += min(entitylen, tcplen - *ptcpoff);
++ }
++ break;
++ }
++ if (lineoff+linelen > tcplen)
++ {
++ INFOP("!! overrun !!\n");
++ break;
++ }
++
++ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
++ {
++ *pcseqoff = lineoff;
++ *pcseqlen = linelen;
++ }
++ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
++ {
++ uint off = lineoff+15;
++ SKIP_WSPACE(ptcp+lineoff, linelen, off);
++ nf_strtou32(ptcp+off, &entitylen);
++ }
++ }
++ *phdrslen = (*ptcpoff) - (*phdrsoff);
++
++ return 1;
++}
++
++/*
++ * Find lo/hi client ports (if any) in transport header
++ * In:
++ * ptcp, tcplen = packet
++ * tranoff, tranlen = buffer to search
++ *
++ * Out:
++ * pport_lo, pport_hi = lo/hi ports (host endian)
++ *
++ * Returns nonzero if any client ports found
++ *
++ * Note: it is valid (and expected) for the client to request multiple
++ * transports, so we need to parse the entire line.
++ */
++static int
++rtsp_parse_transport(char* ptran, uint tranlen,
++ struct ip_ct_rtsp_expect* prtspexp)
++{
++ int rc = 0;
++ uint off = 0;
++
++ if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++ nf_strncasecmp(ptran, "Transport:", 10) != 0)
++ {
++ INFOP("sanity check failed\n");
++ return 0;
++ }
++ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
++ off += 10;
++ SKIP_WSPACE(ptran, tranlen, off);
++
++ /* Transport: tran;field;field=val,tran;field;field=val,... */
++ while (off < tranlen)
++ {
++ const char* pparamend;
++ uint nextparamoff;
++
++ pparamend = memchr(ptran+off, ',', tranlen-off);
++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++ nextparamoff = pparamend-ptran;
++
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (strncmp(ptran+off, "client_port=", 12) == 0)
++ {
++ u_int16_t port;
++ uint numlen;
++
++ off += 12;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ if (prtspexp->loport != 0 && prtspexp->loport != port)
++ {
++ DEBUGP("multiple ports found, port %hu ignored\n", port);
++ }
++ else
++ {
++ prtspexp->loport = prtspexp->hiport = port;
++ if (ptran[off] == '-')
++ {
++ off++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ prtspexp->pbtype = pb_range;
++ prtspexp->hiport = port;
++
++ // If we have a range, assume rtp:
++ // loport must be even, hiport must be loport+1
++ if ((prtspexp->loport & 0x0001) != 0 ||
++ prtspexp->hiport != prtspexp->loport+1)
++ {
++ DEBUGP("incorrect range: %hu-%hu, correcting\n",
++ prtspexp->loport, prtspexp->hiport);
++ prtspexp->loport &= 0xfffe;
++ prtspexp->hiport = prtspexp->loport+1;
++ }
++ }
++ else if (ptran[off] == '/')
++ {
++ off++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ prtspexp->pbtype = pb_discon;
++ prtspexp->hiport = port;
++ }
++ rc = 1;
++ }
++ }
++
++ /*
++ * Note we don't look for the destination parameter here.
++ * If we are using NAT, the NAT module will handle it. If not,
++ * and the client is sending packets elsewhere, the expectation
++ * will quietly time out.
++ */
++
++ off = nextfieldoff;
++ }
++
++ off = nextparamoff;
++ }
++
++ return rc;
++}
++
++/*** conntrack functions ***/
++
++/* outbound packet: client->server */
++static int
++help_out(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
++ uint tcplen = pktlen - iph->ihl * 4;
++ char* pdata = (char*)tcph + tcph->doff * 4;
++ uint datalen = tcplen - tcph->doff * 4;
++ uint dataoff = 0;
++
++ struct ip_conntrack_expect exp;
++
++ while (dataoff < datalen)
++ {
++ uint cmdoff = dataoff;
++ uint hdrsoff = 0;
++ uint hdrslen = 0;
++ uint cseqoff = 0;
++ uint cseqlen = 0;
++ uint lineoff = 0;
++ uint linelen = 0;
++ uint off;
++ int rc;
++
++ if (!rtsp_parse_message(pdata, datalen, &dataoff,
++ &hdrsoff, &hdrslen,
++ &cseqoff, &cseqlen))
++ {
++ break; /* not a valid message */
++ }
++
++ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
++ {
++ continue; /* not a SETUP message */
++ }
++ DEBUGP("found a setup message\n");
++
++ memset(&exp, 0, sizeof(exp));
++
++ off = 0;
++ while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
++ &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ break;
++ }
++ if (off > hdrsoff+hdrslen)
++ {
++ INFOP("!! overrun !!");
++ break;
++ }
++
++ if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
++ {
++ rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
++ &exp.help.exp_rtsp_info);
++ }
++ }
++
++ if (exp.help.exp_rtsp_info.loport == 0)
++ {
++ DEBUGP("no udp transports found\n");
++ continue; /* no udp transports found */
++ }
++
++ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
++ (int)exp.help.exp_rtsp_info.pbtype,
++ exp.help.exp_rtsp_info.loport,
++ exp.help.exp_rtsp_info.hiport);
++
++ LOCK_BH(&ip_rtsp_lock);
++ exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
++ exp.help.exp_rtsp_info.len = hdrslen;
++
++ exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++ exp.mask.src.ip = 0xffffffff;
++ exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip;
++ exp.mask.dst.ip = 0xffffffff;
++ exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport;
++ exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
++ exp.tuple.dst.protonum = IPPROTO_UDP;
++ exp.mask.dst.protonum = 0xffff;
++
++ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(exp.tuple.src.ip),
++ ntohs(exp.tuple.src.u.tcp.port),
++ NIPQUAD(exp.tuple.dst.ip),
++ ntohs(exp.tuple.dst.u.tcp.port));
++
++ /* pass the request off to the nat helper */
++ rc = ip_conntrack_expect_related(ct, &exp);
++ UNLOCK_BH(&ip_rtsp_lock);
++ if (rc == 0)
++ {
++ DEBUGP("ip_conntrack_expect_related succeeded\n");
++ }
++ else
++ {
++ INFOP("ip_conntrack_expect_related failed (%d)\n", rc);
++ }
++ }
++
++ return NF_ACCEPT;
++}
++
++/* inbound packet: server->client */
++static int
++help_in(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ return NF_ACCEPT;
++}
++
++static int
++help(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
++ u_int32_t tcplen = pktlen - iph->ihl * 4;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
++ {
++ DEBUGP("conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4)
++ {
++ DEBUGP("tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char*)tcph, tcplen, 0)))
++ {
++ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ switch (CTINFO2DIR(ctinfo))
++ {
++ case IP_CT_DIR_ORIGINAL:
++ help_out(iph, pktlen, ct, ctinfo);
++ break;
++ case IP_CT_DIR_REPLY:
++ help_in(iph, pktlen, ct, ctinfo);
++ break;
++ }
++
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++ int i;
++ for (i = 0; i < num_ports; i++)
++ {
++ DEBUGP("unregistering port %d\n", ports[i]);
++ ip_conntrack_helper_unregister(&rtsp_helpers[i]);
++ }
++}
++
++static int __init
++init(void)
++{
++ int i, ret;
++ struct ip_conntrack_helper *hlpr;
++ char *tmpname;
++
++ printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++ if (max_outstanding < 1)
++ {
++ printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
++ return -EBUSY;
++ }
++ if (setup_timeout < 0)
++ {
++ printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
++ return -EBUSY;
++ }
++
++ /* If no port given, default to standard rtsp port */
++ if (ports[0] == 0)
++ {
++ ports[0] = RTSP_PORT;
++ }
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
++ {
++ hlpr = &rtsp_helpers[i];
++ memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
++ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++ hlpr->tuple.dst.protonum = IPPROTO_TCP;
++ hlpr->mask.src.u.tcp.port = 0xFFFF;
++ hlpr->mask.dst.protonum = 0xFFFF;
++ hlpr->max_expected = max_outstanding;
++ hlpr->timeout = setup_timeout;
++ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ hlpr->me = ip_conntrack_rtsp;
++ hlpr->help = help;
++
++ tmpname = &rtsp_names[i][0];
++ if (ports[i] == RTSP_PORT)
++ {
++ sprintf(tmpname, "rtsp");
++ }
++ else
++ {
++ sprintf(tmpname, "rtsp-%d", i);
++ }
++ hlpr->name = tmpname;
++
++ DEBUGP("port #%d: %d\n", i, ports[i]);
++
++ ret = ip_conntrack_helper_register(hlpr);
++
++ if (ret)
++ {
++ printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
++ fini();
++ return -EBUSY;
++ }
++ num_ports++;
++ }
++ return 0;
++}
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++EXPORT_SYMBOL(ip_rtsp_lock);
++#endif
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-06-07 21:14:11.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-06-08 10:38:45.000000000 +0200
+@@ -110,6 +110,9 @@
+ len += sprintf(buffer + len, "[ASSURED] ");
+ len += sprintf(buffer + len, "use=%u ",
+ atomic_read(&conntrack->ct_general.use));
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++ len += sprintf(buffer + len, "mark=%ld ", conntrack->mark);
++#endif
+ len += sprintf(buffer + len, "\n");
+
+ return len;
+@@ -502,7 +505,7 @@
+ if (ret < 0)
+ goto cleanup_nothing;
+
+- proc = proc_net_create("ip_conntrack",0,list_conntracks);
++ proc = proc_net_create("ip_conntrack", 0440, list_conntracks);
+ if (!proc) goto cleanup_init;
+ proc->owner = THIS_MODULE;
+
+@@ -633,6 +636,7 @@
+ EXPORT_SYMBOL(ip_conntrack_alter_reply);
+ EXPORT_SYMBOL(ip_conntrack_destroyed);
+ EXPORT_SYMBOL(ip_conntrack_get);
++EXPORT_SYMBOL(__ip_conntrack_confirm);
+ EXPORT_SYMBOL(need_ip_conntrack);
+ EXPORT_SYMBOL(ip_conntrack_helper_register);
+ EXPORT_SYMBOL(ip_conntrack_helper_unregister);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_talk.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_talk.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_conntrack_talk.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_conntrack_talk.c 2004-06-08 10:41:27.000000000 +0200
+@@ -0,0 +1,360 @@
++/*
++ * talk extension for IP connection tracking.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ **
++ * Module load syntax:
++ * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[01]
++ *
++ * talk=[0|1] disable|enable old talk support
++ * ntalk=[0|1] disable|enable ntalk support
++ * ntalk2=[0|1] disable|enable ntalk2 support
++ *
++ * The default is talk=1 ntalk=1 ntalk2=1
++ *
++ * The helper does not support simultaneous talk requests.
++ **
++ *
++ * ASCII art on talk protocols
++ *
++ *
++ * caller server callee server
++ * | \ /
++ * | \ /
++ * | \ /
++ * | /
++ * | / \
++ * 2 | 1 / \ 3
++ * caller client ----------- callee client
++ * 4
++ *
++ * 1. caller client <-> callee server: LOOK_UP, then ANNOUNCE invitation
++ * ( 2. caller client <-> caller server: LEAVE_INVITE to server )
++ * 3. callee client <-> caller server: LOOK_UP invitation
++ * 4. callee client <-> caller client: talk data channel
++ *
++ * [1]: M. Hunter, talk: a historical protocol for interactive communication
++ * draft-hunter-talk-00.txt
++ * [2]: D.B. Chapman, E.D. Zwicky: Building Internet Firewalls (O'Reilly)
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/udp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_talk.h>
++
++/* Default all talk protocols are supported */
++static int talk = 1;
++static int ntalk = 1;
++static int ntalk2 = 1;
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("talk connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(talk, "i");
++MODULE_PARM_DESC(talk, "support (old) talk protocol");
++MODULE_PARM(ntalk, "i");
++MODULE_PARM_DESC(ntalk, "support ntalk protocol");
++MODULE_PARM(ntalk2, "i");
++MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol");
++#endif
++
++DECLARE_LOCK(ip_talk_lock);
++struct module *ip_conntrack_talk = THIS_MODULE;
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static int talk_expect(struct ip_conntrack *ct);
++static int ntalk_expect(struct ip_conntrack *ct);
++
++static int (*talk_expectfn[2])(struct ip_conntrack *ct) = {talk_expect, ntalk_expect};
++
++static int talk_help_response(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ int talk_port,
++ u_char mode,
++ u_char type,
++ u_char answer,
++ struct talk_addr *addr)
++{
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_talk_expect *exp_talk_info = &exp->help.exp_talk_info;
++
++ DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n",
++ NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
++ type, answer);
++
++ if (!(answer == SUCCESS && type == mode))
++ return NF_ACCEPT;
++
++ memset(&expect, 0, sizeof(expect));
++
++ if (type == ANNOUNCE) {
++
++ DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n");
++
++ /* update the talk info */
++ LOCK_BH(&ip_talk_lock);
++ exp_talk_info->port = htons(talk_port);
++
++ /* expect callee client -> caller server message */
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[dir].tuple.src.ip,
++ { 0 } },
++ { ct->tuplehash[dir].tuple.dst.ip,
++ { .tcp = { htons(talk_port) } },
++ IPPROTO_UDP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
++
++ exp->expectfn = talk_expectfn[talk_port - TALK_PORT];
++
++ DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller daemon %u.%u.%u.%u:%u!\n",
++ NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.udp.port),
++ NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.udp.port));
++
++ /* Ignore failure; should only happen with NAT */
++ ip_conntrack_expect_related(ct, &expect);
++ UNLOCK_BH(&ip_talk_lock);
++ }
++ if (type == LOOK_UP) {
++
++ DEBUGP("ip_ct_talk_help_response: LOOK_UP\n");
++
++ /* update the talk info */
++ LOCK_BH(&ip_talk_lock);
++ exp_talk_info->port = addr->ta_port;
++
++ /* expect callee client -> caller client connection */
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip,
++ { 0 } },
++ { addr->ta_addr,
++ { addr->ta_port },
++ IPPROTO_TCP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
++
++ exp->expectfn = NULL;
++
++ DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller client %u.%u.%u.%u:%u!\n",
++ NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
++ NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
++
++ /* Ignore failure; should only happen with NAT */
++ ip_conntrack_expect_related(ct, &expect);
++ UNLOCK_BH(&ip_talk_lock);
++ }
++
++ return NF_ACCEPT;
++}
++
++/* FIXME: This should be in userspace. Later. */
++static int talk_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ int talk_port,
++ u_char mode)
++{
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++ const char *data = (const char *)udph + sizeof(struct udphdr);
++ int dir = CTINFO2DIR(ctinfo);
++ size_t udplen;
++
++ DEBUGP("ip_ct_talk_help: help entered\n");
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("ip_ct_talk_help: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole UDP header? */
++ udplen = len - iph->ihl * 4;
++ if (udplen < sizeof(struct udphdr)) {
++ DEBUGP("ip_ct_talk_help: too short for udph, udplen = %u\n", (unsigned)udplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
++ csum_partial((char *)udph, udplen, 0))) {
++ DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ udph, udplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ DEBUGP("ip_ct_talk_help: %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(udph->source), NIPQUAD(iph->daddr), ntohs(udph->dest));
++
++ if (dir == IP_CT_DIR_ORIGINAL)
++ return NF_ACCEPT;
++
++ if (talk_port == TALK_PORT
++ && udplen == sizeof(struct udphdr) + sizeof(struct talk_response))
++ return talk_help_response(iph, len, ct, ctinfo, talk_port, mode,
++ ((struct talk_response *)data)->type,
++ ((struct talk_response *)data)->answer,
++ &(((struct talk_response *)data)->addr));
++ else if (talk_port == NTALK_PORT
++ && ntalk
++ && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response)
++ && ((struct ntalk_response *)data)->vers == NTALK_VERSION)
++ return talk_help_response(iph, len, ct, ctinfo, talk_port, mode,
++ ((struct ntalk_response *)data)->type,
++ ((struct ntalk_response *)data)->answer,
++ &(((struct ntalk_response *)data)->addr));
++ else if (talk_port == NTALK_PORT
++ && ntalk2
++ && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response)
++ && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION)
++ return talk_help_response(iph, len, ct, ctinfo, talk_port, mode,
++ ((struct ntalk2_response *)data)->type,
++ ((struct ntalk2_response *)data)->answer,
++ &(((struct ntalk2_response *)data)->addr));
++ else {
++ DEBUGP("ip_ct_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n",
++ (unsigned)udplen - sizeof(struct udphdr),
++ sizeof(struct ntalk_response), sizeof(struct ntalk2_response));
++ return NF_ACCEPT;
++ }
++}
++
++static int lookup_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ return talk_help(iph, len, ct, ctinfo, TALK_PORT, LOOK_UP);
++}
++
++static int lookup_nhelp(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ return talk_help(iph, len, ct, ctinfo, NTALK_PORT, LOOK_UP);
++}
++
++static struct ip_conntrack_helper lookup_helpers[2] =
++ { { { NULL, NULL },
++ "talk", /* name */
++ 0, /* flags */
++ NULL, /* module */
++ 1, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ lookup_help }, /* helper */
++ { { NULL, NULL },
++ "ntalk", /* name */
++ 0, /* flags */
++ NULL, /* module */
++ 1, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ lookup_nhelp } /* helper */
++ };
++
++static int talk_expect(struct ip_conntrack *ct)
++{
++ DEBUGP("ip_conntrack_talk: calling talk_expectfn for ct %p\n", ct);
++ WRITE_LOCK(&ip_conntrack_lock);
++ ct->helper = &lookup_helpers[0];
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return NF_ACCEPT; /* unused */
++}
++
++static int ntalk_expect(struct ip_conntrack *ct)
++{
++ DEBUGP("ip_conntrack_talk: calling ntalk_expectfn for ct %p\n", ct);
++ WRITE_LOCK(&ip_conntrack_lock);
++ ct->helper = &lookup_helpers[1];
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return NF_ACCEPT; /* unused */
++}
++
++static int help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ return talk_help(iph, len, ct, ctinfo, TALK_PORT, ANNOUNCE);
++}
++
++static int nhelp(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++{
++ return talk_help(iph, len, ct, ctinfo, NTALK_PORT, ANNOUNCE);
++}
++
++static struct ip_conntrack_helper talk_helpers[2] =
++ { { { NULL, NULL },
++ "talk", /* name */
++ 0, /* flags */
++ THIS_MODULE, /* module */
++ 1, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ help }, /* helper */
++ { { NULL, NULL },
++ "ntalk", /* name */
++ 0, /* flags */
++ THIS_MODULE, /* module */
++ 1, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ nhelp } /* helper */
++ };
++
++static int __init init(void)
++{
++ if (talk > 0)
++ ip_conntrack_helper_register(&talk_helpers[0]);
++ if (ntalk > 0 || ntalk2 > 0)
++ ip_conntrack_helper_register(&talk_helpers[1]);
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ if (talk > 0)
++ ip_conntrack_helper_unregister(&talk_helpers[0]);
++ if (ntalk > 0 || ntalk2 > 0)
++ ip_conntrack_helper_unregister(&talk_helpers[1]);
++}
++
++EXPORT_SYMBOL(ip_talk_lock);
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_core.c 2004-06-07 21:13:39.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_core.c 2004-06-08 10:30:32.000000000 +0200
+@@ -816,7 +816,7 @@
+
+ /* Have to grab read lock before sibling_list traversal */
+ READ_LOCK(&ip_conntrack_lock);
+- list_for_each(cur_item, &ct->sibling_list) {
++ list_for_each_prev(cur_item, &ct->sibling_list) {
+ exp = list_entry(cur_item, struct ip_conntrack_expect,
+ expected_list);
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_h323.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_h323.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_h323.c 2004-06-08 10:38:40.000000000 +0200
+@@ -0,0 +1,419 @@
++/*
++ * H.323 'brute force' extension for NAT alteration.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
++ * (http://www.coritel.it/projects/sofia/nat.html)
++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
++ * the unregistered helpers to the conntrack entries.
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
++
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK_EXTERN(ip_h323_lock);
++struct module *ip_nat_h323 = THIS_MODULE;
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++/* FIXME: Time out? --RR */
++
++static unsigned int
++h225_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info);
++
++static unsigned int h225_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb);
++
++static struct ip_nat_helper h245 =
++ { { NULL, NULL },
++ "H.245", /* name */
++ 0, /* flags */
++ NULL, /* module */
++ { { 0, { 0 } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_nat_help, /* helper */
++ h225_nat_expected /* expectfn */
++ };
++
++static unsigned int
++h225_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++ u_int16_t port;
++ struct ip_ct_h225_expect *exp_info;
++ struct ip_ct_h225_master *master_info;
++ struct ip_conntrack *master = master_ct(ct);
++ unsigned int is_h225, ret;
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
++
++ DEBUGP("h225_nat_expected: We have a connection!\n");
++ master_info = &ct->master->expectant->help.ct_h225_info;
++ exp_info = &ct->master->help.exp_h225_info;
++
++ LOCK_BH(&ip_h323_lock);
++
++ DEBUGP("master: ");
++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
++ DEBUGP("conntrack: ");
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
++ /* Make connection go to the client. */
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ } else {
++ /* Make the connection go to the server */
++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ }
++ port = exp_info->port;
++ is_h225 = master_info->is_h225 == H225_PORT;
++ UNLOCK_BH(&ip_h323_lock);
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ newip = newsrcip;
++ else
++ newip = newdstip;
++
++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs... */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ /* ... unless we're doing a MANIP_DST, in which case, make
++ sure we map to the correct port */
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
++ mr.range[0].min = mr.range[0].max
++ = ((union ip_conntrack_manip_proto)
++ { .tcp = { port } });
++ }
++
++ ret = ip_nat_setup_info(ct, &mr, hooknum);
++
++ if (is_h225) {
++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
++ /* NAT expectfn called with ip_nat_lock write-locked */
++ info->helper = &h245;
++ }
++ return ret;
++}
++
++static int h323_signal_address_fixup(struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *)iph + iph->ihl*4;
++ char *data = (char *) tcph + tcph->doff * 4;
++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
++ u_int32_t datalen = tcplen - tcph->doff*4;
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ u_int32_t newip;
++ u_int16_t port;
++ int i;
++
++ MUST_BE_LOCKED(&ip_h323_lock);
++
++ DEBUGP("h323_signal_address_fixup: %s %s\n",
++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ ? "yes" : "no",
++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ ? "yes" : "no");
++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
++ return 1;
++
++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
++ info->offset[IP_CT_DIR_ORIGINAL],
++ info->offset[IP_CT_DIR_REPLY],
++ tcplen);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ for (i = 0; i < IP_CT_DIR_MAX; i++) {
++ DEBUGP("h323_signal_address_fixup: %s %s\n",
++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
++ if (!between(info->seq[i], ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen))
++ continue;
++ if (!between(info->seq[i] + 6, ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen)) {
++ /* Partial retransmisison. It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
++ info->seq[i],
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++ }
++ return 0;
++ }
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ if (i == IP_CT_DIR_ORIGINAL) {
++ newip = ct->tuplehash[!info->dir].tuple.dst.ip;
++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
++ } else {
++ newip = ct->tuplehash[!info->dir].tuple.src.ip;
++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
++ }
++
++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
++ NIPQUAD(*((u_int32_t *)(data + info->offset[i]))),
++ ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
++
++ /* Modify the packet */
++ *(u_int32_t *)(data + info->offset[i]) = newip;
++ *(u_int16_t *)(data + info->offset[i] + 4) = port;
++
++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
++ NIPQUAD(*((u_int32_t *)(data + info->offset[i]))),
++ ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
++ }
++
++ /* fix checksum information */
++
++ (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
++ datalen, 0);
++
++ tcph->check = 0;
++ tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcph->doff*4,
++ (*pskb)->csum));
++ ip_send_check(iph);
++
++ return 1;
++}
++
++static int h323_data_fixup(struct ip_ct_h225_expect *info,
++ struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *expect)
++{
++ u_int32_t newip;
++ u_int16_t port;
++ struct ip_conntrack_tuple newtuple;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *)iph + iph->ihl*4;
++ char *data = (char *) tcph + tcph->doff * 4;
++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
++ int is_h225;
++
++ MUST_BE_LOCKED(&ip_h323_lock);
++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ if (!between(expect->seq + 6, ntohl(tcph->seq),
++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
++ /* Partial retransmisison. It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
++ expect->seq,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + tcplen - tcph->doff * 4);
++ }
++ return 0;
++ }
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ if (info->dir == IP_CT_DIR_REPLY) {
++ /* Must be where client thinks server is */
++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ /* Expect something from client->server */
++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ } else {
++ /* Must be where server thinks client is */
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ /* Expect something from server->client */
++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ }
++
++ is_h225 = (master_info->is_h225 == H225_PORT);
++
++ if (is_h225) {
++ newtuple.dst.protonum = IPPROTO_TCP;
++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
++ } else {
++ newtuple.dst.protonum = IPPROTO_UDP;
++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
++ }
++
++ /* Try to get same port: if not, try to change it. */
++ for (port = ntohs(info->port); port != 0; port++) {
++ if (is_h225)
++ newtuple.dst.u.tcp.port = htons(port);
++ else
++ newtuple.dst.u.udp.port = htons(port);
++
++ if (ip_conntrack_change_expect(expect, &newtuple) == 0)
++ break;
++ }
++ if (port == 0) {
++ DEBUGP("h323_data_fixup: no free port found!\n");
++ return 0;
++ }
++
++ port = htons(port);
++
++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
++ NIPQUAD(*((u_int32_t *)(data + info->offset))),
++ ntohs(*((u_int16_t *)(data + info->offset + 4))));
++
++ /* Modify the packet */
++ *(u_int32_t *)(data + info->offset) = newip;
++ *(u_int16_t *)(data + info->offset + 4) = port;
++
++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
++ NIPQUAD(*((u_int32_t *)(data + info->offset))),
++ ntohs(*((u_int16_t *)(data + info->offset + 4))));
++
++ /* fix checksum information */
++ /* FIXME: usually repeated multiple times in the case of H.245! */
++
++ (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
++ tcplen - tcph->doff*4, 0);
++
++ tcph->check = 0;
++ tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcph->doff*4,
++ (*pskb)->csum));
++ ip_send_check(iph);
++
++ return 1;
++}
++
++static unsigned int h225_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ int dir;
++ struct ip_ct_h225_expect *exp_info;
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ dir = CTINFO2DIR(ctinfo);
++ DEBUGP("nat_h323: dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++
++ if (!exp) {
++ LOCK_BH(&ip_h323_lock);
++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_ACCEPT;
++ }
++
++ exp_info = &exp->help.exp_h225_info;
++
++ LOCK_BH(&ip_h323_lock);
++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_h323_lock);
++
++ return NF_ACCEPT;
++}
++
++static struct ip_nat_helper h225 =
++ { { NULL, NULL },
++ "H.225", /* name */
++ IP_NAT_HELPER_F_ALWAYS, /* flags */
++ THIS_MODULE, /* module */
++ { { 0, { .tcp = { __constant_htons(H225_PORT) } } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { .tcp = { 0xFFFF } } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_nat_help, /* helper */
++ h225_nat_expected /* expectfn */
++ };
++
++static int __init init(void)
++{
++ int ret;
++
++ ret = ip_nat_helper_register(&h225);
++
++ if (ret != 0)
++ printk("ip_nat_h323: cannot initialize the module!\n");
++
++ return ret;
++}
++
++static void __exit fini(void)
++{
++ ip_nat_helper_unregister(&h225);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_mms.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_mms.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_mms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_mms.c 2004-06-08 10:39:44.000000000 +0200
+@@ -0,0 +1,350 @@
++/* MMS extension for TCP NAT alteration.
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_nat_ftp.c and ip_nat_irc.c
++ *
++ * ip_nat_mms.c v0.3 2002-09-22
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * Please give the ports of all MMS servers You wish to connect to.
++ * If you don't specify ports, the default will be TCP port 1755.
++ *
++ * More info on MMS protocol, firewalls and NAT:
++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
++ *
++ * The SDP project people are reverse-engineering MMS:
++ * http://get.to/sdp
++ */
++
++/* FIXME: issue with UDP & fragmentation with this URL:
++ http://www.cnn.com/video/world/2002/01/21/jb.shoe.bomb.cafe.cnn.low.asx
++ may be related to out-of-order first packets:
++ basically the expectation is set up correctly, then the server sends
++ a first UDP packet which is fragmented plus arrives out-of-order.
++ the MASQUERADING firewall with ip_nat_mms loaded responds with
++ an ICMP unreachable back to the server */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#if 0
++#define DEBUGP printk
++#define DUMP_BYTES(address, counter) \
++({ \
++ int temp_counter; \
++ for(temp_counter=0; temp_counter<counter; ++temp_counter) { \
++ DEBUGP("%u ", (u8)*(address+temp_counter)); \
++ }; \
++ DEBUGP("\n"); \
++})
++#else
++#define DEBUGP(format, args...)
++#define DUMP_BYTES(address, counter)
++#endif
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c = 0;
++
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++#endif
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK_EXTERN(ip_mms_lock);
++
++/* FIXME: Time out? --RR */
++
++static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info,
++ struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *expect)
++{
++ u_int32_t newip;
++ struct ip_conntrack_tuple t;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ char *data = (char *)tcph + tcph->doff * 4;
++ int i, j, k, port;
++ u_int16_t mms_proto;
++
++ u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET);
++ u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET);
++ u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET);
++
++ int zero_padding;
++
++ char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */
++ char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */
++ char proto_string[6];
++
++ MUST_BE_LOCKED(&ip_mms_lock);
++
++ /* what was the protocol again ? */
++ mms_proto = expect->tuple.dst.protonum;
++ sprintf(proto_string, "%u", mms_proto);
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n",
++ expect->seq, ct_mms_info->len, ntohl(tcph->seq),
++ mms_proto == IPPROTO_UDP ? "UDP"
++ : mms_proto == IPPROTO_TCP ? "TCP":proto_string);
++
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++
++ /* Alter conntrack's expectations. */
++ t = expect->tuple;
++ t.dst.ip = newip;
++ for (port = ct_mms_info->port; port != 0; port++) {
++ t.dst.u.tcp.port = htons(port);
++ if (ip_conntrack_change_expect(expect, &t) == 0) {
++ DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port);
++ break;
++ }
++ }
++
++ if(port == 0)
++ return 0;
++
++ sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u",
++ NIPQUAD(newip),
++ expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP"
++ : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string,
++ port);
++ DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer);
++
++ memset(unicode_buffer, 0, sizeof(char)*75);
++
++ for (i=0; i<strlen(buffer); ++i)
++ *(unicode_buffer+i*2)=*(buffer+i);
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len);
++ DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len);
++ DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60);
++
++ /* add end of packet to it */
++ for (j=0; j<ct_mms_info->padding; ++j) {
++ DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n",
++ i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j));
++ *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j);
++ }
++
++ /* pad with zeroes at the end ? see explanation of weird math below */
++ zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8;
++ for (k=0; k<zero_padding; ++k)
++ *(unicode_buffer+i*2+j+k)= (char)0;
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding);
++ DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
++
++ /* explanation, before I forget what I did:
++ strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8;
++ divide by 8 and add 3 to compute the mms_chunkLenLM field,
++ but note that things may have to be padded with zeroes to align by 8
++ bytes, hence we add 7 and divide by 8 to get the correct length */
++ *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8);
++ *mms_chunkLenLV = *mms_chunkLenLM+2;
++ *mms_messageLength = *mms_chunkLenLV*8;
++
++ DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
++
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ expect->seq - ntohl(tcph->seq),
++ ct_mms_info->len + ct_mms_info->padding, unicode_buffer,
++ strlen(buffer)*2 + ct_mms_info->padding + zero_padding);
++ DUMP_BYTES(unicode_buffer, 60);
++
++ return 1;
++}
++
++static unsigned int
++mms_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++
++ struct ip_conntrack *master = master_ct(ct);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n");
++
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ newip = newsrcip;
++ else
++ newip = newdstip;
++
++ DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs. */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ return ip_nat_setup_info(ct, &mr, hooknum);
++}
++
++
++static unsigned int mms_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ unsigned int datalen;
++ int dir;
++ struct ip_ct_mms_expect *ct_mms_info;
++
++ if (!exp)
++ DEBUGP("ip_nat_mms: no exp!!");
++
++ ct_mms_info = &exp->help.exp_mms_info;
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++ DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++
++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
++
++ DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len,
++ exp->seq + ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++
++ LOCK_BH(&ip_mms_lock);
++ /* Check wether the whole IP/proto/port pattern is carried in the payload */
++ if (between(exp->seq + ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen)) {
++ if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) {
++ UNLOCK_BH(&ip_mms_lock);
++ return NF_DROP;
++ }
++ } else {
++ /* Half a match? This means a partial retransmisison.
++ It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("ip_nat_mms: partial packet %u/%u in %u/%u\n",
++ exp->seq, ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++ }
++ UNLOCK_BH(&ip_mms_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_mms_lock);
++
++ return NF_ACCEPT;
++}
++
++static struct ip_nat_helper mms[MAX_PORTS];
++static char mms_names[MAX_PORTS][10];
++
++/* Not __exit: called from init() */
++static void fini(void)
++{
++ int i;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]);
++ ip_nat_helper_unregister(&mms[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret = 0;
++ char *tmpname;
++
++ if (ports[0] == 0)
++ ports[0] = MMS_PORT;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++
++ memset(&mms[i], 0, sizeof(struct ip_nat_helper));
++
++ mms[i].tuple.dst.protonum = IPPROTO_TCP;
++ mms[i].tuple.src.u.tcp.port = htons(ports[i]);
++ mms[i].mask.dst.protonum = 0xFFFF;
++ mms[i].mask.src.u.tcp.port = 0xFFFF;
++ mms[i].help = mms_nat_help;
++ mms[i].me = THIS_MODULE;
++ mms[i].flags = 0;
++ mms[i].expect = mms_nat_expected;
++
++ tmpname = &mms_names[i][0];
++ if (ports[i] == MMS_PORT)
++ sprintf(tmpname, "mms");
++ else
++ sprintf(tmpname, "mms-%d", i);
++ mms[i].name = tmpname;
++
++ DEBUGP("ip_nat_mms: register helper for port %d\n",
++ ports[i]);
++ ret = ip_nat_helper_register(&mms[i]);
++
++ if (ret) {
++ printk("ip_nat_mms: error registering "
++ "helper for port %d\n", ports[i]);
++ fini();
++ return ret;
++ }
++ ports_c++;
++ }
++
++ return ret;
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_quake3.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_quake3.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_quake3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_quake3.c 2004-06-08 10:40:36.000000000 +0200
+@@ -0,0 +1,249 @@
++/* Quake3 extension for UDP NAT alteration.
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_nat_ftp.c and ip_nat_tftp.c
++ *
++ * ip_nat_quake3.c v0.0.3 2002-08-31
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_nat_quake3.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * please give the ports of all Quake3 master servers You wish to
++ * connect to. If you don't specify ports, the default will be UDP
++ * port 27950.
++ *
++ * Thanks to the Ethereal folks for their analysis of the Quake3 protocol.
++ *
++ * Notes:
++ * - If you're one of those people who would try anything to lower
++ * latency while playing Quake (and who isn't :-) ), you may want to
++ * consider not loading ip_nat_quake3 at all and just MASQUERADE all
++ * outgoing UDP traffic.
++ * This will make ip_conntrack_quake3 add the necessary expectations,
++ * but there will be no overhead for client->server UDP streams. If
++ * ip_nat_quake3 is loaded, quake3_nat_expected will be called per NAT
++ * hook for every packet in the client->server UDP stream.
++ * - Only SNAT/MASQUEARDE targets are useful for ip_nat_quake3.
++ * The IP addresses in the master connection payload (=IP addresses
++ * of Quake servers) have no relation with the master server so
++ * DNAT'ing the master connection to a server should not change the
++ * expected connections.
++ * - Not tested due to lack of equipment:
++ * - multiple Quake3 clients behind one MASQUERADE gateway
++ * - what if Quake3 client is running on router too
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/udp.h>
++
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_quake3.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Netfilter NAT helper for Quake III Arena");
++MODULE_LICENSE("GPL");
++
++#define MAX_PORTS 8
++
++static int ports[MAX_PORTS];
++static int ports_c = 0;
++#ifdef MODULE_PARM
++MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of Quake III master servers");
++#endif
++
++/* Quake3 master server reply will add > 100 expectations per reply packet; when
++ doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static struct quake3_search quake3s_nat = { "****", "getserversResponse", sizeof("getserversResponse") - 1 };
++
++static unsigned int
++quake3_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++ struct ip_conntrack_tuple repl;
++ int dir = CTINFO2DIR(ctinfo);
++ int i;
++
++ DEBUGP("ip_nat_quake3: quake3_nat_help, direction: %s hook: %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"
++ );
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("ip_nat_quake3: Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????");
++ return NF_ACCEPT;
++ }
++
++ if (!exp) {
++ DEBUGP("no conntrack expectation to modify\n");
++ return NF_ACCEPT;
++ }
++
++ if (strnicmp((const char *)udph + 12, quake3s_nat.pattern, quake3s_nat.plen) == 0) {
++ for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */
++ i+6 < ntohs(udph->len);
++ i+=7) {
++ DEBUGP("ip_nat_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n",
++ i, ntohs(udph->len),
++ NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ),
++ ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) );
++
++ memset(&repl, 0, sizeof(repl));
++
++ repl.dst.protonum = IPPROTO_UDP;
++ repl.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ repl.dst.ip = *( (u_int32_t *)( (int)udph + i ) );
++ repl.dst.u.udp.port = (__u16) *( (__u16 *)( (int)udph + i + 4 ) );
++
++ ip_conntrack_change_expect(exp, &repl);
++ }
++ }
++ return NF_ACCEPT;
++}
++
++static unsigned int
++quake3_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ const struct ip_conntrack *master = ct->master->expectant;
++ struct ip_nat_multi_range mr;
++ u_int32_t newsrcip, newdstip, newip;
++#if 0
++ const struct ip_conntrack_tuple *repl =
++ &master->tuplehash[IP_CT_DIR_REPLY].tuple;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct udphdr *udph = (void *)iph + iph->ihl*4;
++#endif
++
++ DEBUGP("ip_nat_quake3: quake3_nat_expected: here we are\n");
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ newdstip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
++ newip = newsrcip;
++ DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
++ "newsrc: %u.%u.%u.%u\n",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????",
++ NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
++ NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
++ NIPQUAD(newip));
++
++ } else {
++ newip = newdstip;
++ DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
++ "newdst: %u.%u.%u.%u\n",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????",
++ NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
++ NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
++ NIPQUAD(newip));
++ }
++
++ mr.rangesize = 1;
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ return ip_nat_setup_info(ct,&mr,hooknum);
++}
++
++static struct ip_nat_helper quake3[MAX_PORTS];
++static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */
++
++static void fini(void)
++{
++ int i;
++
++ for (i = 0 ; i < ports_c; i++) {
++ DEBUGP("ip_nat_quake3: unregistering helper for port %d\n", ports[i]);
++ ip_nat_helper_unregister(&quake3[i]);
++ }
++}
++
++static int __init init(void)
++ {
++ int i, ret = 0;
++ char *tmpname;
++
++ if (!ports[0])
++ ports[0] = QUAKE3_MASTER_PORT;
++
++ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
++ memset(&quake3[i], 0, sizeof(struct ip_nat_helper));
++
++ quake3[i].tuple.dst.protonum = IPPROTO_UDP;
++ quake3[i].tuple.src.u.udp.port = htons(ports[i]);
++ quake3[i].mask.dst.protonum = 0xFFFF;
++ quake3[i].mask.src.u.udp.port = 0xFFFF;
++ quake3[i].help = quake3_nat_help;
++ quake3[i].flags = 0;
++ quake3[i].me = THIS_MODULE;
++ quake3[i].expect = quake3_nat_expected;
++
++ tmpname = &quake3_names[i][0];
++ if (ports[i] == QUAKE3_MASTER_PORT)
++ sprintf(tmpname, "quake3");
++ else
++ sprintf(tmpname, "quake3-%d", i);
++ quake3[i].name = tmpname;
++
++ DEBUGP("ip_nat_quake3: registering helper for port %d: name %s\n",
++ ports[i], quake3[i].name);
++ ret = ip_nat_helper_register(&quake3[i]);
++
++ if (ret) {
++ printk("ip_nat_quake3: unable to register helper for port %d\n",
++ ports[i]);
++ fini();
++ return ret;
++ }
++ ports_c++;
++ }
++ return ret;
++ }
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_rtsp.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_rtsp.c 2004-06-08 10:40:46.000000000 +0200
+@@ -0,0 +1,621 @@
++/*
++ * RTSP extension for TCP NAT alteration
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_nat_irc.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ * stunaddr=<address>
++ * destaction=[auto|strip|none]
++ *
++ * If no ports are specified, the default will be port 554 only.
++ *
++ * stunaddr specifies the address used to detect that a client is using STUN.
++ * If this address is seen in the destination parameter, it is assumed that
++ * the client has already punched a UDP hole in the firewall, so we don't
++ * mangle the client_port. If none is specified, it is autodetected. It
++ * only needs to be set if you have multiple levels of NAT. It should be
++ * set to the external address that the STUN clients detect. Note that in
++ * this case, it will not be possible for clients to use UDP with servers
++ * between the NATs.
++ *
++ * If no destaction is specified, auto is used.
++ * destaction=auto: strip destination parameter if it is not stunaddr.
++ * destaction=strip: always strip destination parameter (not recommended).
++ * destaction=none: do not touch destination parameter (not recommended).
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/kernel.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#include <linux/inet.h>
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#else
++#define DEBUGP(fmt, args...)
++#endif
++
++#define MAX_PORTS 8
++#define DSTACT_AUTO 0
++#define DSTACT_STRIP 1
++#define DSTACT_NONE 2
++
++static int ports[MAX_PORTS];
++static char* stunaddr = NULL;
++static char* destaction = NULL;
++
++static int num_ports = 0;
++static u_int32_t extip = 0;
++static int dstact = 0;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP network address translation module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(stunaddr, "s");
++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
++MODULE_PARM(destaction, "s");
++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
++#endif
++
++/* protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*** helper functions ***/
++
++static void
++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
++{
++ struct iphdr* iph = (struct iphdr*)skb->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
++
++ *pptcpdata = (char*)tcph + tcph->doff*4;
++ *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
++}
++
++/*** nat functions ***/
++
++/*
++ * Mangle the "Transport:" header:
++ * - Replace all occurences of "client_port=<spec>"
++ * - Handle destination parameter
++ *
++ * In:
++ * ct, ctinfo = conntrack context
++ * pskb = packet
++ * tranoff = Transport header offset from TCP data
++ * tranlen = Transport header length (incl. CRLF)
++ * rport_lo = replacement low port (host endian)
++ * rport_hi = replacement high port (host endian)
++ *
++ * Returns packet size difference.
++ *
++ * Assumes that a complete transport header is present, ending with CR or LF
++ */
++static int
++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp,
++ struct sk_buff** pskb, uint tranoff, uint tranlen)
++{
++ char* ptcp;
++ uint tcplen;
++ char* ptran;
++ char rbuf1[16]; /* Replacement buffer (one port) */
++ uint rbuf1len; /* Replacement len (one port) */
++ char rbufa[16]; /* Replacement buffer (all ports) */
++ uint rbufalen; /* Replacement len (all ports) */
++ u_int32_t newip;
++ u_int16_t loport, hiport;
++ uint off = 0;
++ uint diff; /* Number of bytes we removed */
++
++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++ struct ip_conntrack_tuple t;
++
++ char szextaddr[15+1];
++ uint extaddrlen;
++ int is_stun;
++
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++
++ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++ tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++ nf_strncasecmp(ptran, "Transport:", 10) != 0)
++ {
++ INFOP("sanity check failed\n");
++ return 0;
++ }
++ off += 10;
++ SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ t = exp->tuple;
++ t.dst.ip = newip;
++
++ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
++ : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
++ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++
++ rbuf1len = rbufalen = 0;
++ switch (prtspexp->pbtype)
++ {
++ case pb_single:
++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu\n", loport);
++ break;
++ }
++ }
++ if (loport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ rbufalen = sprintf(rbufa, "%hu", loport);
++ }
++ break;
++ case pb_range:
++ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ hiport = loport + ~exp->mask.dst.u.udp.port;
++ DEBUGP("using ports %hu-%hu\n", loport, hiport);
++ break;
++ }
++ }
++ if (loport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
++ }
++ break;
++ case pb_discon:
++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu (1 of 2)\n", loport);
++ break;
++ }
++ }
++ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(hiport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu (2 of 2)\n", hiport);
++ break;
++ }
++ }
++ if (loport != 0 && hiport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ if (hiport == loport+1)
++ {
++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++ }
++ else
++ {
++ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
++ }
++ }
++ break;
++ }
++
++ if (rbuf1len == 0)
++ {
++ return 0; /* cannot get replacement port(s) */
++ }
++
++ /* Transport: tran;field;field=val,tran;field;field=val,... */
++ while (off < tranlen)
++ {
++ uint saveoff;
++ const char* pparamend;
++ uint nextparamoff;
++
++ pparamend = memchr(ptran+off, ',', tranlen-off);
++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++ nextparamoff = pparamend-ptcp;
++
++ /*
++ * We pass over each param twice. On the first pass, we look for a
++ * destination= field. It is handled by the security policy. If it
++ * is present, allowed, and equal to our external address, we assume
++ * that STUN is being used and we leave the client_port= field alone.
++ */
++ is_stun = 0;
++ saveoff = off;
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
++ {
++ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
++ {
++ is_stun = 1;
++ }
++ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
++ {
++ diff = nextfieldoff-off;
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ off, diff, NULL, 0))
++ {
++ /* mangle failed, all we can do is bail */
++ return 0;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++ tranlen -= diff;
++ nextparamoff -= diff;
++ nextfieldoff -= diff;
++ }
++ }
++
++ off = nextfieldoff;
++ }
++ if (is_stun)
++ {
++ continue;
++ }
++ off = saveoff;
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (strncmp(ptran+off, "client_port=", 12) == 0)
++ {
++ u_int16_t port;
++ uint numlen;
++ uint origoff;
++ uint origlen;
++ char* rbuf = rbuf1;
++ uint rbuflen = rbuf1len;
++
++ off += 12;
++ origoff = (ptran-ptcp)+off;
++ origlen = 0;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ origlen += numlen;
++ if (port != prtspexp->loport)
++ {
++ DEBUGP("multiple ports found, port %hu ignored\n", port);
++ }
++ else
++ {
++ if (ptran[off] == '-' || ptran[off] == '/')
++ {
++ off++;
++ origlen++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ origlen += numlen;
++ rbuf = rbufa;
++ rbuflen = rbufalen;
++ }
++
++ /*
++ * note we cannot just memcpy() if the sizes are the same.
++ * the mangle function does skb resizing, checks for a
++ * cloned skb, and updates the checksums.
++ *
++ * parameter 4 below is offset from start of tcp data.
++ */
++ diff = origlen-rbuflen;
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ origoff, origlen, rbuf, rbuflen))
++ {
++ /* mangle failed, all we can do is bail */
++ return 0;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++ tranlen -= diff;
++ nextparamoff -= diff;
++ nextfieldoff -= diff;
++ }
++ }
++
++ off = nextfieldoff;
++ }
++
++ off = nextparamoff;
++ }
++
++ return 1;
++}
++
++static unsigned int
++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++
++ struct ip_conntrack *master = master_ct(ct);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
++
++ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs. */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ return ip_nat_setup_info(ct, &mr, hooknum);
++}
++
++static uint
++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++ char* ptcp;
++ uint tcplen;
++ uint hdrsoff;
++ uint hdrslen;
++ uint lineoff;
++ uint linelen;
++ uint off;
++
++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
++
++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++
++ hdrsoff = exp->seq - ntohl(tcph->seq);
++ hdrslen = prtspexp->len;
++ off = hdrsoff;
++
++ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ break;
++ }
++ if (off > hdrsoff+hdrslen)
++ {
++ INFOP("!! overrun !!");
++ break;
++ }
++ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
++ {
++ uint oldtcplen = tcplen;
++ if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
++ {
++ break;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ hdrslen -= (oldtcplen-tcplen);
++ off -= (oldtcplen-tcplen);
++ lineoff -= (oldtcplen-tcplen);
++ linelen -= (oldtcplen-tcplen);
++ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++ }
++ }
++
++ return NF_ACCEPT;
++}
++
++static uint
++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++ /* XXX: unmangle */
++ return NF_ACCEPT;
++}
++
++static uint
++help(struct ip_conntrack* ct,
++ struct ip_conntrack_expect* exp,
++ struct ip_nat_info* info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff** pskb)
++{
++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
++ uint datalen;
++ int dir;
++ struct ip_ct_rtsp_expect* ct_rtsp_info;
++ int rc = NF_ACCEPT;
++
++ if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
++ {
++ DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb);
++ return NF_ACCEPT;
++ }
++
++ ct_rtsp_info = &exp->help.exp_rtsp_info;
++
++ /*
++ * Only mangle things once: original direction in POST_ROUTING
++ * and reply direction on PRE_ROUTING.
++ */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
++ {
++ DEBUGP("Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++ DEBUGP("got beyond not touching\n");
++
++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
++
++ LOCK_BH(&ip_rtsp_lock);
++ /* Ensure the packet contains all of the marked data */
++ if (!between(exp->seq + ct_rtsp_info->len,
++ ntohl(tcph->seq), ntohl(tcph->seq) + datalen))
++ {
++ /* Partial retransmission? Probably a hacker. */
++ if (net_ratelimit())
++ {
++ INFOP("partial packet %u/%u in %u/%u\n",
++ exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
++ }
++ UNLOCK_BH(&ip_rtsp_lock);
++ return NF_DROP;
++ }
++
++ switch (dir)
++ {
++ case IP_CT_DIR_ORIGINAL:
++ rc = help_out(ct, ctinfo, exp, pskb);
++ break;
++ case IP_CT_DIR_REPLY:
++ rc = help_in(ct, ctinfo, exp, pskb);
++ break;
++ }
++ UNLOCK_BH(&ip_rtsp_lock);
++
++ return rc;
++}
++
++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++ int i;
++
++ for (i = 0; i < num_ports; i++)
++ {
++ DEBUGP("unregistering helper for port %d\n", ports[i]);
++ ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
++ }
++}
++
++static int __init
++init(void)
++{
++ int ret = 0;
++ int i;
++ struct ip_nat_helper* hlpr;
++ char* tmpname;
++
++ printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++ if (ports[0] == 0)
++ {
++ ports[0] = RTSP_PORT;
++ }
++
++ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
++ {
++ hlpr = &ip_nat_rtsp_helpers[i];
++ memset(hlpr, 0, sizeof(struct ip_nat_helper));
++
++ hlpr->tuple.dst.protonum = IPPROTO_TCP;
++ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++ hlpr->mask.src.u.tcp.port = 0xFFFF;
++ hlpr->mask.dst.protonum = 0xFFFF;
++ hlpr->help = help;
++ hlpr->flags = 0;
++ hlpr->me = THIS_MODULE;
++ hlpr->expect = expected;
++
++ tmpname = &rtsp_names[i][0];
++ if (ports[i] == RTSP_PORT)
++ {
++ sprintf(tmpname, "rtsp");
++ }
++ else
++ {
++ sprintf(tmpname, "rtsp-%d", i);
++ }
++ hlpr->name = tmpname;
++
++ DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
++ ret = ip_nat_helper_register(hlpr);
++
++ if (ret)
++ {
++ printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
++ fini();
++ return 1;
++ }
++ num_ports++;
++ }
++ if (stunaddr != NULL)
++ {
++ extip = in_aton(stunaddr);
++ }
++ if (destaction != NULL)
++ {
++ if (strcmp(destaction, "auto") == 0)
++ {
++ dstact = DSTACT_AUTO;
++ }
++ if (strcmp(destaction, "strip") == 0)
++ {
++ dstact = DSTACT_STRIP;
++ }
++ if (strcmp(destaction, "none") == 0)
++ {
++ dstact = DSTACT_NONE;
++ }
++ }
++ return ret;
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_rule.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_rule.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_rule.c 2004-06-07 21:14:10.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_rule.c 2004-06-08 10:37:30.000000000 +0200
+@@ -75,7 +75,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* POST_ROUTING */
+@@ -83,7 +83,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -91,7 +91,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } }
+ },
+@@ -100,7 +100,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_standalone.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_standalone.c 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_standalone.c 2004-06-08 10:38:45.000000000 +0200
+@@ -176,6 +176,45 @@
+ return do_bindings(ct, ctinfo, info, hooknum, pskb);
+ }
+
++struct nat_route_key
++{
++ u_int32_t addr;
++#ifdef CONFIG_XFRM
++ u_int16_t port;
++#endif
++};
++
++static inline void
++nat_route_key_get(struct sk_buff *skb, struct nat_route_key *key, int which)
++{
++ struct iphdr *iph = skb->nh.iph;
++
++ key->addr = which ? iph->daddr : iph->saddr;
++#ifdef CONFIG_XFRM
++ key->port = 0;
++ if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) {
++ u_int16_t *ports = (u_int16_t *)(skb->nh.raw + iph->ihl*4);
++ key->port = ports[which];
++ }
++#endif
++}
++
++static inline int
++nat_route_key_compare(struct sk_buff *skb, struct nat_route_key *key, int which)
++{
++ struct iphdr *iph = skb->nh.iph;
++
++ if (key->addr != (which ? iph->daddr : iph->saddr))
++ return 1;
++#ifdef CONFIG_XFRM
++ if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) {
++ u_int16_t *ports = (u_int16_t *)(skb->nh.raw + iph->ihl*4);
++ if (key->port != ports[which])
++ return 1;
++ }
++#endif
++}
++
+ static unsigned int
+ ip_nat_out(unsigned int hooknum,
+ struct sk_buff **pskb,
+@@ -183,6 +222,9 @@
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
++ struct nat_route_key key;
++ unsigned int ret;
++
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct iphdr)
+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+@@ -205,7 +247,29 @@
+ return NF_STOLEN;
+ }
+
+- return ip_nat_fn(hooknum, pskb, in, out, okfn);
++ nat_route_key_get(*pskb, &key, 0);
++ ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
++
++ if (ret != NF_DROP && ret != NF_STOLEN
++ && nat_route_key_compare(*pskb, &key, 0)) {
++ if (ip_route_me_harder(pskb) != 0)
++ ret = NF_DROP;
++#ifdef CONFIG_XFRM
++ /*
++ * POST_ROUTING hook is called with fixed outfn, we need
++ * to manually confirm the packet and direct it to the
++ * transformers if a policy matches.
++ */
++ else if ((*pskb)->dst->xfrm != NULL) {
++ ret = ip_conntrack_confirm(*pskb);
++ if (ret != NF_DROP) {
++ dst_output(*pskb);
++ ret = NF_STOLEN;
++ }
++ }
++#endif
++ }
++ return ret;
+ }
+
+ #ifdef CONFIG_IP_NF_NAT_LOCAL
+@@ -216,7 +280,7 @@
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+ {
+- u_int32_t saddr, daddr;
++ struct nat_route_key key;
+ unsigned int ret;
+
+ /* root is playing with raw sockets. */
+@@ -224,14 +288,14 @@
+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+ return NF_ACCEPT;
+
+- saddr = (*pskb)->nh.iph->saddr;
+- daddr = (*pskb)->nh.iph->daddr;
+-
++ nat_route_key_get(*pskb, &key, 1);
+ ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
++
+ if (ret != NF_DROP && ret != NF_STOLEN
+- && ((*pskb)->nh.iph->saddr != saddr
+- || (*pskb)->nh.iph->daddr != daddr))
+- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
++ && nat_route_key_compare(*pskb, &key, 1)) {
++ if (ip_route_me_harder(pskb) != 0)
++ ret = NF_DROP;
++ }
+ return ret;
+ }
+ #endif
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_talk.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_talk.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_nat_talk.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_nat_talk.c 2004-06-08 10:41:27.000000000 +0200
+@@ -0,0 +1,473 @@
++/*
++ * talk extension for UDP NAT alteration.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ **
++ * Module load syntax:
++ * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[0|1]
++ *
++ * talk=[0|1] disable|enable old talk support
++ * ntalk=[0|1] disable|enable ntalk support
++ * ntalk2=[0|1] disable|enable ntalk2 support
++ *
++ * The default is talk=1 ntalk=1 ntalk2=1
++ *
++ *
++ */
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/udp.h>
++#include <linux/kernel.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_talk.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++/* Default all talk protocols are supported */
++static int talk = 1;
++static int ntalk = 1;
++static int ntalk2 = 1;
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("talk network address translation module");
++#ifdef MODULE_PARM
++MODULE_PARM(talk, "i");
++MODULE_PARM_DESC(talk, "support (old) talk protocol");
++MODULE_PARM(ntalk, "i");
++MODULE_PARM_DESC(ntalk, "support ntalk protocol");
++MODULE_PARM(ntalk2, "i");
++MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol");
++#endif
++
++#if 0
++#define DEBUGP printk
++#define IP_NAT_TALK_DEBUG
++#else
++#define DEBUGP(format, args...)
++#endif
++
++/* FIXME: Time out? --RR */
++
++static int
++mangle_packet(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ u_int32_t newip,
++ u_int16_t port,
++ struct talk_addr *addr,
++ struct talk_addr *ctl_addr)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++ size_t udplen = (*pskb)->len - iph->ihl * 4;
++
++ /* Fortunately talk sends a structure with the address and
++ port in it. The size of the packet won't change. */
++
++ if (ctl_addr == NULL) {
++ /* response */
++ if (addr->ta_addr == INADDR_ANY)
++ return 1;
++ DEBUGP("ip_nat_talk_mangle_packet: response orig %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n",
++ NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
++ NIPQUAD(newip), ntohs(port));
++ addr->ta_addr = newip;
++ addr->ta_port = port;
++ } else {
++ /* message */
++ if (addr->ta_addr != INADDR_ANY) {
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ DEBUGP("ip_nat_talk_mangle_packet: message orig addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n",
++ NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
++ NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip),
++ ntohs(addr->ta_port));
++ addr->ta_addr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ }
++ DEBUGP("ip_nat_talk_mangle_packet: message orig ctl_addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n",
++ NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port),
++ NIPQUAD(newip), ntohs(port));
++ ctl_addr->ta_addr = newip;
++ ctl_addr->ta_port = port;
++ }
++
++ /* Fix checksums */
++ (*pskb)->csum = csum_partial((char *)udph + sizeof(struct udphdr), udplen - sizeof(struct udphdr), 0);
++ udph->check = 0;
++ udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
++ csum_partial((char *)udph, sizeof(struct udphdr), (*pskb)->csum));
++
++ ip_send_check(iph);
++ return 1;
++}
++
++static int talk_help_msg(struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ u_char type,
++ struct talk_addr *addr,
++ struct talk_addr *ctl_addr)
++{
++ u_int32_t newip;
++ u_int16_t port;
++
++ unsigned int verdict = NF_ACCEPT;
++
++ DEBUGP("ip_nat_talk_help_msg: addr: %u.%u.%u.%u:%u, ctl_addr: %u.%u.%u.%u:%u, type %d\n",
++ NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
++ NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port),
++ type);
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port;
++ DEBUGP("ip_nat_talk_help_msg: inserting: %u.%u.%u.%u:%u\n",
++ NIPQUAD(newip), ntohs(port));
++
++ if (!mangle_packet(pskb, ct, newip, port, addr, ctl_addr))
++ verdict = NF_DROP;
++
++ return verdict;
++}
++
++static int talk_help_response(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct sk_buff **pskb,
++ u_char type,
++ u_char answer,
++ struct talk_addr *addr)
++{
++ u_int32_t newip;
++ u_int16_t port;
++ struct ip_conntrack_tuple t;
++ struct ip_ct_talk_expect *ct_talk_info;
++
++ DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, type %d answer %d\n",
++ NIPQUAD(addr->ta_addr), ntohs(addr->ta_port),
++ type, answer);
++
++ LOCK_BH(&ip_talk_lock);
++ ct_talk_info = &exp->help.exp_talk_info;
++
++ if (!(answer == SUCCESS
++ && (type == LOOK_UP || type == ANNOUNCE)
++ && exp != NULL)) {
++ UNLOCK_BH(&ip_talk_lock);
++ return NF_ACCEPT;
++ }
++
++ DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n",
++ ntohs(ct_talk_info->port),
++ type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE");
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL :
++ IP_CT_DIR_REPLY].tuple.dst.ip;
++ /* We can read expect here without conntrack lock, since it's
++ only set in ip_conntrack_talk , with ip_talk_lock held
++ writable */
++ t = exp->tuple;
++ t.dst.ip = newip;
++
++ /* Try to get same port: if not, try to change it. */
++ for (port = ntohs(ct_talk_info->port); port != 0; port++) {
++ if (type == LOOK_UP)
++ t.dst.u.tcp.port = htons(port);
++ else
++ t.dst.u.udp.port = htons(port);
++
++ if (ip_conntrack_change_expect(exp, &t) == 0) {
++ DEBUGP("ip_nat_talk_help_response: using %u.%u.%u.%u:%u\n", NIPQUAD(newip), port);
++ break;
++ }
++ }
++ UNLOCK_BH(&ip_talk_lock);
++
++ if (port == 0 || !mangle_packet(pskb, ct, newip, htons(port), addr, NULL))
++ return NF_DROP;
++
++ return NF_ACCEPT;
++}
++
++static unsigned int talk_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb,
++ int talk_port)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++ unsigned int udplen = (*pskb)->len - iph->ihl * 4;
++ char *data = (char *)udph + sizeof(struct udphdr);
++ int dir;
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("ip_nat_talk_help: Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++ DEBUGP("ip_nat_talk_help: dir %s at hook %s, %u.%u.%u.%u:%u->%u.%u.%u.%u:%u, talk port %d\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
++ NIPQUAD(iph->saddr), ntohs(udph->source),
++ NIPQUAD(iph->daddr), ntohs(udph->dest),
++ talk_port);
++
++ /* Because conntrack does not drop packets, checking must be repeated here... */
++ if (talk_port == TALK_PORT) {
++ if (dir == IP_CT_DIR_ORIGINAL
++ && udplen == sizeof(struct udphdr) + sizeof(struct talk_msg))
++ return talk_help_msg(ct, pskb,
++ ((struct talk_msg *)data)->type,
++ &(((struct talk_msg *)data)->addr),
++ &(((struct talk_msg *)data)->ctl_addr));
++ else if (dir == IP_CT_DIR_REPLY
++ && udplen == sizeof(struct udphdr) + sizeof(struct talk_response))
++ return talk_help_response(ct, exp, pskb,
++ ((struct talk_response *)data)->type,
++ ((struct talk_response *)data)->answer,
++ &(((struct talk_response *)data)->addr));
++ else {
++ DEBUGP("ip_nat_talk_help: not talk %s, datalen %u != %u\n",
++ dir == IP_CT_DIR_ORIGINAL ? "message" : "response",
++ (unsigned)udplen - sizeof(struct udphdr),
++ dir == IP_CT_DIR_ORIGINAL ? sizeof(struct talk_msg) : sizeof(struct talk_response));
++ return NF_DROP;
++ }
++ } else {
++ if (dir == IP_CT_DIR_ORIGINAL) {
++ if (ntalk
++ && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_msg)
++ && ((struct ntalk_msg *)data)->vers == NTALK_VERSION)
++ return talk_help_msg(ct, pskb,
++ ((struct ntalk_msg *)data)->type,
++ &(((struct ntalk_msg *)data)->addr),
++ &(((struct ntalk_msg *)data)->ctl_addr));
++ else if (ntalk2
++ && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_msg)
++ && ((struct ntalk2_msg *)data)->vers == NTALK2_VERSION
++ && udplen == sizeof(struct udphdr)
++ + sizeof(struct ntalk2_msg)
++ + ((struct ntalk2_msg *)data)->extended)
++ return talk_help_msg(ct, pskb,
++ ((struct ntalk2_msg *)data)->type,
++ &(((struct ntalk2_msg *)data)->addr),
++ &(((struct ntalk2_msg *)data)->ctl_addr));
++ else {
++ DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 message, datalen %u != %u or %u + max 256\n",
++ (unsigned)udplen - sizeof(struct udphdr),
++ sizeof(struct ntalk_msg), sizeof(struct ntalk2_msg));
++ return NF_DROP;
++ }
++ } else {
++ if (ntalk
++ && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response)
++ && ((struct ntalk_response *)data)->vers == NTALK_VERSION)
++ return talk_help_response(ct, exp, pskb,
++ ((struct ntalk_response *)data)->type,
++ ((struct ntalk_response *)data)->answer,
++ &(((struct ntalk_response *)data)->addr));
++ else if (ntalk2
++ && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response)
++ && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION)
++ return talk_help_response(ct, exp, pskb,
++ ((struct ntalk2_response *)data)->type,
++ ((struct ntalk2_response *)data)->answer,
++ &(((struct ntalk2_response *)data)->addr));
++ else {
++ DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n",
++ (unsigned)udplen - sizeof(struct udphdr),
++ sizeof(struct ntalk_response), sizeof(struct ntalk2_response));
++ return NF_DROP;
++ }
++ }
++ }
++}
++
++static unsigned int help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ return talk_help(ct, exp, info, ctinfo, hooknum, pskb, TALK_PORT);
++}
++
++static unsigned int nhelp(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ return talk_help(ct, exp, info, ctinfo, hooknum, pskb, NTALK_PORT);
++}
++
++static unsigned int
++talk_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info);
++
++static struct ip_nat_helper talk_helpers[2] =
++ { { { NULL, NULL },
++ "talk", /* name */
++ IP_NAT_HELPER_F_ALWAYS, /* flags */
++ THIS_MODULE, /* module */
++ { { 0, { .udp = { __constant_htons(TALK_PORT) } } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { .udp = { 0xFFFF } } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ help, /* helper */
++ talk_nat_expected }, /* expectfn */
++ { { NULL, NULL },
++ "ntalk", /* name */
++ IP_NAT_HELPER_F_ALWAYS, /* flags */
++ THIS_MODULE, /* module */
++ { { 0, { .udp = { __constant_htons(NTALK_PORT) } } }, /* tuple */
++ { 0, { 0 }, IPPROTO_UDP } },
++ { { 0, { .udp = { 0xFFFF } } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ nhelp, /* helper */
++ talk_nat_expected } /* expectfn */
++ };
++
++static unsigned int
++talk_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++ u_int16_t port;
++ unsigned int ret;
++
++ struct ip_conntrack *master = master_ct(ct);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
++
++ DEBUGP("ip_nat_talk_expected: We have a connection!\n");
++
++ LOCK_BH(&ip_talk_lock);
++ port = ct->master->help.exp_talk_info.port;
++ UNLOCK_BH(&ip_talk_lock);
++
++ DEBUGP("ip_nat_talk_expected: dir %s at hook %s, ct %p, master %p\n",
++ CTINFO2DIR((*pskb)->nfct - ct->infos) == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
++ ct, master);
++
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) {
++ /* Callee client -> caller server */
++#ifdef IP_NAT_TALK_DEBUG
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct udphdr *udph = (void *)iph + iph->ihl * 4;
++
++ DEBUGP("ip_nat_talk_expected: UDP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(udph->source),
++ NIPQUAD(iph->daddr), ntohs(udph->dest));
++#endif
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ DEBUGP("ip_nat_talk_expected: callee client -> caller server, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ } else {
++ /* Callee client -> caller client */
++#ifdef IP_NAT_TALK_DEBUG
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++
++ DEBUGP("ip_nat_talk_expected: TCP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(tcph->source),
++ NIPQUAD(iph->daddr), ntohs(tcph->dest));
++#endif
++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ DEBUGP("ip_nat_talk_expected: callee client -> caller client, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ }
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ newip = newsrcip;
++ else
++ newip = newdstip;
++
++ DEBUGP("ip_nat_talk_expected: IP to %u.%u.%u.%u, port %u\n", NIPQUAD(newip), ntohs(port));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs... */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ /* ... unless we're doing a MANIP_DST, in which case, make
++ sure we map to the correct port */
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
++ mr.range[0].min = mr.range[0].max
++ = ((union ip_conntrack_manip_proto)
++ { .udp = { port } });
++ }
++ ret = ip_nat_setup_info(ct, &mr, hooknum);
++
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) {
++ DEBUGP("talk_expected: setting NAT helper for %p\n", ct);
++ /* NAT expectfn called with ip_nat_lock write-locked */
++ info->helper = &talk_helpers[htons(port) - TALK_PORT];
++ }
++ return ret;
++}
++
++static int __init init(void)
++{
++ int ret = 0;
++
++ if (talk > 0) {
++ ret = ip_nat_helper_register(&talk_helpers[0]);
++
++ if (ret != 0)
++ return ret;
++ }
++ if (ntalk > 0 || ntalk2 > 0) {
++ ret = ip_nat_helper_register(&talk_helpers[1]);
++
++ if (ret != 0 && talk > 0)
++ ip_nat_helper_unregister(&talk_helpers[0]);
++ }
++ return ret;
++}
++
++static void __exit fini(void)
++{
++ if (talk > 0)
++ ip_nat_helper_unregister(&talk_helpers[0]);
++ if (ntalk > 0 || ntalk2 > 0)
++ ip_nat_helper_unregister(&talk_helpers[1]);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_pool.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_pool.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_pool.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_pool.c 2004-06-08 10:31:45.000000000 +0200
+@@ -0,0 +1,334 @@
++/* Kernel module for IP pool management */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_pool.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++
++#if 0
++#define DP printk
++#else
++#define DP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++
++#define NR_POOL 16
++static int nr_pool = NR_POOL;/* overwrite this when loading module */
++
++struct ip_pool {
++ u_int32_t first_ip; /* host byte order, included in range */
++ u_int32_t last_ip; /* host byte order, included in range */
++ void *members; /* the bitmap proper */
++ int nr_use; /* total nr. of tests through this */
++ int nr_match; /* total nr. of matches through this */
++ rwlock_t lock;
++};
++
++static struct ip_pool *POOL;
++
++static inline struct ip_pool *lookup(ip_pool_t index)
++{
++ if (index < 0 || index >= nr_pool) {
++ DP("ip_pool:lookup: bad index %d\n", index);
++ return 0;
++ }
++ return POOL+index;
++}
++
++int ip_pool_match(ip_pool_t index, u_int32_t addr)
++{
++ struct ip_pool *pool = lookup(index);
++ int res = 0;
++
++ if (!pool || !pool->members)
++ return 0;
++ read_lock_bh(&pool->lock);
++ if (pool->members) {
++ if (addr >= pool->first_ip && addr <= pool->last_ip) {
++ addr -= pool->first_ip;
++ if (test_bit(addr, pool->members)) {
++ res = 1;
++#ifdef CONFIG_IP_POOL_STATISTICS
++ pool->nr_match++;
++#endif
++ }
++ }
++#ifdef CONFIG_IP_POOL_STATISTICS
++ pool->nr_use++;
++#endif
++ }
++ read_unlock_bh(&pool->lock);
++ return res;
++}
++EXPORT_SYMBOL(ip_pool_match);
++
++static int pool_change(ip_pool_t index, u_int32_t addr, int isdel)
++{
++ struct ip_pool *pool;
++ int res = -1;
++
++ pool = lookup(index);
++ if ( !pool || !pool->members
++ || addr < pool->first_ip || addr > pool->last_ip)
++ return -1;
++ read_lock_bh(&pool->lock);
++ if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) {
++ addr -= pool->first_ip;
++ res = isdel
++ ? (0 != test_and_clear_bit(addr, pool->members))
++ : (0 != test_and_set_bit(addr, pool->members));
++ }
++ read_unlock_bh(&pool->lock);
++ return res;
++}
++
++int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel)
++{
++ int res = pool_change(index,addr,isdel);
++
++ if (!isdel) res = !res;
++ return res;
++}
++EXPORT_SYMBOL(ip_pool_mod);
++
++static inline int bitmap_bytes(u_int32_t a, u_int32_t b)
++{
++ return 4*((((b-a+8)/8)+3)/4);
++}
++
++static inline int poolbytes(ip_pool_t index)
++{
++ struct ip_pool *pool = lookup(index);
++
++ return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0;
++}
++
++static int setpool(
++ struct sock *sk,
++ int optval,
++ void *user,
++ unsigned int len
++) {
++ struct ip_pool_request req;
++
++ DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len);
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ if (optval != SO_IP_POOL)
++ return -EBADF;
++ if (len != sizeof(req))
++ return -EINVAL;
++ if (copy_from_user(&req, user, sizeof(req)) != 0)
++ return -EFAULT;
++ printk("obsolete op - upgrade your ippool(8) utility.\n");
++ return -EINVAL;
++}
++
++static int getpool(
++ struct sock *sk,
++ int optval,
++ void *user,
++ int *len
++) {
++ struct ip_pool_request req;
++ struct ip_pool *pool;
++ ip_pool_t i;
++ int newbytes;
++ void *newmembers;
++ int res;
++
++ DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user);
++ if (!capable(CAP_NET_ADMIN))
++ return -EINVAL;
++ if (optval != SO_IP_POOL)
++ return -EINVAL;
++ if (*len != sizeof(req)) {
++ return -EFAULT;
++ }
++ if (copy_from_user(&req, user, sizeof(req)) != 0)
++ return -EFAULT;
++ DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index);
++ if (req.op < IP_POOL_BAD001) {
++ printk("obsolete op - upgrade your ippool(8) utility.\n");
++ return -EFAULT;
++ }
++ switch(req.op) {
++ case IP_POOL_HIGH_NR:
++ DP("ip_pool HIGH_NR\n");
++ req.index = IP_POOL_NONE;
++ for (i=0; i<nr_pool; i++)
++ if (POOL[i].members)
++ req.index = i;
++ return copy_to_user(user, &req, sizeof(req));
++ case IP_POOL_LOOKUP:
++ DP("ip_pool LOOKUP\n");
++ pool = lookup(req.index);
++ if (!pool)
++ return -EINVAL;
++ if (!pool->members)
++ return -EBADF;
++ req.addr = htonl(pool->first_ip);
++ req.addr2 = htonl(pool->last_ip);
++ return copy_to_user(user, &req, sizeof(req));
++ case IP_POOL_USAGE:
++ DP("ip_pool USE\n");
++ pool = lookup(req.index);
++ if (!pool)
++ return -EINVAL;
++ if (!pool->members)
++ return -EBADF;
++ req.addr = pool->nr_use;
++ req.addr2 = pool->nr_match;
++ return copy_to_user(user, &req, sizeof(req));
++ case IP_POOL_TEST_ADDR:
++ DP("ip_pool TEST 0x%08x\n", req.addr);
++ pool = lookup(req.index);
++ if (!pool)
++ return -EINVAL;
++ res = 0;
++ read_lock_bh(&pool->lock);
++ if (!pool->members) {
++ DP("ip_pool TEST_ADDR no members in pool\n");
++ res = -EBADF;
++ goto unlock_and_return_res;
++ }
++ req.addr = ntohl(req.addr);
++ if (req.addr < pool->first_ip) {
++ DP("ip_pool TEST_ADDR address < pool bounds\n");
++ res = -ERANGE;
++ goto unlock_and_return_res;
++ }
++ if (req.addr > pool->last_ip) {
++ DP("ip_pool TEST_ADDR address > pool bounds\n");
++ res = -ERANGE;
++ goto unlock_and_return_res;
++ }
++ req.addr = (0 != test_bit((req.addr - pool->first_ip),
++ pool->members));
++ read_unlock_bh(&pool->lock);
++ return copy_to_user(user, &req, sizeof(req));
++ case IP_POOL_FLUSH:
++ DP("ip_pool FLUSH not yet implemented.\n");
++ return -EBUSY;
++ case IP_POOL_DESTROY:
++ DP("ip_pool DESTROY not yet implemented.\n");
++ return -EBUSY;
++ case IP_POOL_INIT:
++ DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2);
++ pool = lookup(req.index);
++ if (!pool)
++ return -EINVAL;
++ req.addr = ntohl(req.addr);
++ req.addr2 = ntohl(req.addr2);
++ if (req.addr > req.addr2) {
++ DP("ip_pool INIT bad ip range\n");
++ return -EINVAL;
++ }
++ newbytes = bitmap_bytes(req.addr, req.addr2);
++ newmembers = kmalloc(newbytes, GFP_KERNEL);
++ if (!newmembers) {
++ DP("ip_pool INIT out of mem for %d bytes\n", newbytes);
++ return -ENOMEM;
++ }
++ memset(newmembers, 0, newbytes);
++ write_lock_bh(&pool->lock);
++ if (pool->members) {
++ DP("ip_pool INIT pool %d exists\n", req.index);
++ kfree(newmembers);
++ res = -EBUSY;
++ goto unlock_and_return_res;
++ }
++ pool->first_ip = req.addr;
++ pool->last_ip = req.addr2;
++ pool->nr_use = 0;
++ pool->nr_match = 0;
++ pool->members = newmembers;
++ write_unlock_bh(&pool->lock);
++ return 0;
++ case IP_POOL_ADD_ADDR:
++ DP("ip_pool ADD_ADDR 0x%08x\n", req.addr);
++ req.addr = pool_change(req.index, ntohl(req.addr), 0);
++ return copy_to_user(user, &req, sizeof(req));
++ case IP_POOL_DEL_ADDR:
++ DP("ip_pool DEL_ADDR 0x%08x\n", req.addr);
++ req.addr = pool_change(req.index, ntohl(req.addr), 1);
++ return copy_to_user(user, &req, sizeof(req));
++ default:
++ DP("ip_pool:getpool bad op %d\n", req.op);
++ return -EINVAL;
++ }
++ return -EINVAL;
++
++unlock_and_return_res:
++ if (pool)
++ read_unlock_bh(&pool->lock);
++ return res;
++}
++
++static struct nf_sockopt_ops so_pool
++= { { NULL, NULL }, PF_INET,
++ SO_IP_POOL, SO_IP_POOL+1, &setpool,
++ SO_IP_POOL, SO_IP_POOL+1, &getpool,
++ 0, NULL };
++
++MODULE_PARM(nr_pool, "i");
++
++static int __init init(void)
++{
++ ip_pool_t i;
++ int res;
++
++ if (nr_pool < 1) {
++ printk("ip_pool module init: bad nr_pool %d\n", nr_pool);
++ return -EINVAL;
++ }
++ POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL);
++ if (!POOL) {
++ printk("ip_pool module init: out of memory for nr_pool %d\n",
++ nr_pool);
++ return -ENOMEM;
++ }
++ for (i=0; i<nr_pool; i++) {
++ POOL[i].first_ip = 0;
++ POOL[i].last_ip = 0;
++ POOL[i].members = 0;
++ POOL[i].nr_use = 0;
++ POOL[i].nr_match = 0;
++ POOL[i].lock = RW_LOCK_UNLOCKED;
++ }
++ res = nf_register_sockopt(&so_pool);
++ DP("ip_pool:init %d pools, result %d\n", nr_pool, res);
++ if (res != 0) {
++ kfree(POOL);
++ POOL = 0;
++ }
++ return res;
++}
++
++static void __exit fini(void)
++{
++ ip_pool_t i;
++
++ DP("ip_pool:fini BYEBYE\n");
++ nf_unregister_sockopt(&so_pool);
++ for (i=0; i<nr_pool; i++) {
++ if (POOL[i].members) {
++ kfree(POOL[i].members);
++ POOL[i].members = 0;
++ }
++ }
++ kfree(POOL);
++ POOL = 0;
++ DP("ip_pool:fini these are the famous last words\n");
++ return;
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_tables.c linux-2.6.7-rc3/net/ipv4/netfilter/ip_tables.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ip_tables.c 2004-06-07 21:14:01.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ip_tables.c 2004-06-08 10:37:30.000000000 +0200
+@@ -29,6 +29,14 @@
+
+ #include <linux/netfilter_ipv4/ip_tables.h>
+
++static const char *hooknames[] = {
++ [NF_IP_PRE_ROUTING] "PREROUTING",
++ [NF_IP_LOCAL_IN] "INPUT",
++ [NF_IP_FORWARD] "FORWARD",
++ [NF_IP_LOCAL_OUT] "OUTPUT",
++ [NF_IP_POST_ROUTING] "POSTROUTING",
++};
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+ MODULE_DESCRIPTION("IPv4 packet filter");
+@@ -323,6 +331,12 @@
+
+ t = ipt_get_target(e);
+ IP_NF_ASSERT(t->u.kernel.target);
++
++ /* The packet traced and the rule isn't an unconditional return/END. */
++ if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) {
++ nf_log_packet(PF_INET, hook, *pskb, in, out, "TRACE: %s/%s/%u ",
++ table->name, e->chainname, e->rulenum);
++ }
+ /* Standard target? */
+ if (!t->u.kernel.target->target) {
+ int v;
+@@ -349,7 +363,6 @@
+ /* set back pointer to next entry */
+ back = next;
+ }
+-
+ e = get_entry(table_base, v);
+ } else {
+ /* Targets which reenter must return
+@@ -475,6 +488,29 @@
+ return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex);
+ }
+
++static inline int
++find_error_target(struct ipt_entry *s,
++ struct ipt_entry *e,
++ char **chainname)
++{
++ struct ipt_entry_target *t;
++ static struct ipt_entry *found = NULL;
++
++ if (s == e) {
++ if (!found)
++ return 0;
++ t = ipt_get_target(found);
++ if (strcmp(t->u.user.name,
++ IPT_ERROR_TARGET) == 0) {
++ *chainname = t->data;
++ return 1;
++ }
++ } else
++ found = s;
++
++ return 0;
++}
++
+ /* All zeroes == unconditional rule. */
+ static inline int
+ unconditional(const struct ipt_ip *ip)
+@@ -494,6 +530,8 @@
+ mark_source_chains(struct ipt_table_info *newinfo, unsigned int valid_hooks)
+ {
+ unsigned int hook;
++ char *chainname = NULL;
++ u_int32_t rulenum;
+
+ /* No recursion; use packet counter to save back ptrs (reset
+ to 0 as we leave), and comefrom to save source hook bitmask */
+@@ -507,6 +545,8 @@
+
+ /* Set initial back pointer. */
+ e->counters.pcnt = pos;
++ rulenum = 1;
++ chainname = (char *) hooknames[hook];
+
+ for (;;) {
+ struct ipt_standard_target *t
+@@ -519,6 +559,8 @@
+ }
+ e->comefrom
+ |= ((1 << hook) | (1 << NF_IP_NUMHOOKS));
++ e->rulenum = rulenum++;
++ e->chainname = chainname;
+
+ /* Unconditional return/END. */
+ if (e->target_offset == sizeof(struct ipt_entry)
+@@ -528,6 +570,10 @@
+ && unconditional(&e->ip)) {
+ unsigned int oldpos, size;
+
++ /* Set unconditional rulenum to zero. */
++ e->rulenum = 0;
++ e->counters.bcnt = 0;
++
+ /* Return: backtrack through the last
+ big jump. */
+ do {
+@@ -553,6 +599,11 @@
+ (newinfo->entries + pos);
+ } while (oldpos == pos + e->next_offset);
+
++ /* Restore chainname, rulenum. */
++ chainname = e->chainname;
++ rulenum = e->counters.bcnt;
++ e->counters.bcnt = 0;
++
+ /* Move along one */
+ size = e->next_offset;
+ e = (struct ipt_entry *)
+@@ -568,6 +619,17 @@
+ /* This a jump; chase it. */
+ duprintf("Jump rule %u -> %u\n",
+ pos, newpos);
++ e->counters.bcnt = rulenum++;
++ rulenum = 1;
++ e = (struct ipt_entry *)
++ (newinfo->entries + newpos);
++ if (IPT_ENTRY_ITERATE(newinfo->entries,
++ newinfo->size,
++ find_error_target,
++ e, &chainname) == 0) {
++ printk("ip_tables: table screwed up!\n");
++ return 0;
++ }
+ } else {
+ /* ... this is a fallthru */
+ newpos = pos + e->next_offset;
+@@ -1713,9 +1775,9 @@
+ };
+
+ #ifdef CONFIG_PROC_FS
+-static inline int print_name(const char *i,
+- off_t start_offset, char *buffer, int length,
+- off_t *pos, unsigned int *count)
++static int print_name(const char *i,
++ off_t start_offset, char *buffer, int length,
++ off_t *pos, unsigned int *count)
+ {
+ if ((*count)++ >= start_offset) {
+ unsigned int namelen;
+@@ -1749,6 +1811,15 @@
+ return pos;
+ }
+
++static inline int print_target(const struct ipt_target *t,
++ off_t start_offset, char *buffer, int length,
++ off_t *pos, unsigned int *count)
++{
++ if (t == &ipt_standard_target || t == &ipt_error_target)
++ return 0;
++ return print_name((char *)t, start_offset, buffer, length, pos, count);
++}
++
+ static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
+ {
+ off_t pos = 0;
+@@ -1757,7 +1828,7 @@
+ if (down_interruptible(&ipt_mutex) != 0)
+ return 0;
+
+- LIST_FIND(&ipt_target, print_name, void *,
++ LIST_FIND(&ipt_target, print_target, struct ipt_target *,
+ offset, buffer, length, &pos, &count);
+
+ up(&ipt_mutex);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_CONNMARK.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_CONNMARK.c 2004-06-08 10:36:58.000000000 +0200
+@@ -0,0 +1,118 @@
++/* This kernel module is used to modify the connection mark values, or
++ * to optionally restore the skb nfmark from the connection mark
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables CONNMARK matching module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++static unsigned int
++target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_connmark_target_info *markinfo = targinfo;
++ unsigned long diff;
++ unsigned long nfmark;
++ unsigned long newmark;
++
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
++ if (ct) {
++ switch(markinfo->mode) {
++ case IPT_CONNMARK_SET:
++ newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
++ if (newmark != ct->mark)
++ ct->mark = newmark;
++ break;
++ case IPT_CONNMARK_SAVE:
++ newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
++ if (ct->mark != newmark)
++ ct->mark = newmark;
++ break;
++ case IPT_CONNMARK_RESTORE:
++ nfmark = (*pskb)->nfmark;
++ diff = (ct->mark ^ nfmark & markinfo->mask);
++ if (diff != 0) {
++ (*pskb)->nfmark = nfmark ^ diff;
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++ break;
++ }
++ }
++
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_connmark_target_info *matchinfo = targinfo;
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
++ printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
++ return 0;
++ }
++
++ if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_connmark_reg = {
++ .name = "CONNMARK",
++ .target = &target,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_connmark_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_connmark_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_IPMARK.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_IPMARK.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_IPMARK.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_IPMARK.c 2004-06-08 10:37:02.000000000 +0200
+@@ -0,0 +1,81 @@
++/* This is a module which is used for setting the NFMARK field of an skb. */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_IPMARK.h>
++
++MODULE_AUTHOR("Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>");
++MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address");
++MODULE_LICENSE("GPL");
++
++static unsigned int
++target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_ipmark_target_info *ipmarkinfo = targinfo;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ unsigned long mark;
++
++ if (ipmarkinfo->addr == IPT_IPMARK_SRC)
++ mark = (unsigned long) ntohl(iph->saddr);
++ else
++ mark = (unsigned long) ntohl(iph->daddr);
++
++ mark &= ipmarkinfo->andmask;
++ mark |= ipmarkinfo->ormask;
++
++ if ((*pskb)->nfmark != mark) {
++ (*pskb)->nfmark = mark;
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))) {
++ printk(KERN_WARNING "IPMARK: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_ipmark_target_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING "IPMARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_ipmark_reg = {
++ .name = "IPMARK",
++ .target = target,
++ .checkentry = checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_ipmark_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_ipmark_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-06-08 10:31:05.000000000 +0200
+@@ -0,0 +1,89 @@
++/**
++ * Strip all IP options in the IP packet header.
++ *
++ * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Strip all options in IPv4 packets");
++MODULE_LICENSE("GPL");
++
++static unsigned int
++target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ struct iphdr *iph;
++ struct sk_buff *skb;
++ struct ip_options *opt;
++ unsigned char *optiph;
++ int l;
++
++ if (!skb_ip_make_writable(pskb, (*pskb)->len))
++ return NF_DROP;
++
++ skb = (*pskb);
++ iph = (*pskb)->nh.iph;
++ optiph = skb->nh.raw;
++ l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
++
++ /* if no options in packet then nothing to clear. */
++ if (iph->ihl * 4 == sizeof(struct iphdr))
++ return IPT_CONTINUE;
++
++ /* else clear all options */
++ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
++ memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
++ opt = &(IPCB(skb)->opt);
++ opt->is_data = 0;
++ opt->optlen = l;
++
++ skb->nfcache |= NFC_ALTERED;
++
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++ /* nothing else to check because no parameters */
++ return 1;
++}
++
++static struct ipt_target ipt_ipv4optsstrip_reg = {
++ .name = "IPV4OPTSSTRIP",
++ .target = target,
++ .checkentry = checkentry,
++ .me = THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_ipv4optsstrip_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_ipv4optsstrip_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_NETLINK.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_NETLINK.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_NETLINK.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_NETLINK.c 2004-06-08 10:31:09.000000000 +0200
+@@ -0,0 +1,119 @@
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/kernel.h>
++#include <linux/netlink.h>
++#include <linux/netdevice.h>
++#include <linux/mm.h>
++#include <linux/socket.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_NETLINK.h>
++#include <net/sock.h>
++
++MODULE_AUTHOR("Gianni Tedesco <gianni@ecsc.co.uk>");
++MODULE_DESCRIPTION("Provides iptables NETLINK target similar to ipchains -o");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static struct sock *ipfwsk;
++
++static unsigned int ipt_netlink_target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo, void *userinfo)
++{
++ struct ipt_nldata *nld = (struct ipt_nldata *)targinfo;
++ struct iphdr *ip = (*pskb)->nh.iph;
++ struct sk_buff *outskb;
++ struct netlink_t nlhdr;
++ size_t len=0;
++
++ /* Allocate a socket buffer */
++ if ( MASK(nld->flags, USE_SIZE) )
++ len = nld->size+sizeof(nlhdr);
++ else
++ len = ntohs(ip->tot_len)+sizeof(nlhdr);
++
++ outskb=alloc_skb(len, GFP_ATOMIC);
++
++ if (outskb) {
++ nlhdr.len=len;
++
++ if ( MASK(nld->flags, USE_MARK) )
++ nlhdr.mark=(*pskb)->nfmark=nld->mark;
++ else
++ nlhdr.mark=(*pskb)->nfmark;
++
++ if ( in && in->name ) {
++ strncpy((char *)&nlhdr.iface, in->name, IFNAMSIZ);
++ }else if ( out && out->name ){
++ strncpy((char *)&nlhdr.iface, out->name, IFNAMSIZ);
++ }
++
++ skb_put(outskb, len);
++ memcpy(outskb->data, &nlhdr, sizeof(nlhdr));
++ memcpy((outskb->data)+sizeof(nlhdr), ip, len-sizeof(nlhdr));
++ netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC);
++ }else{
++ if (net_ratelimit())
++ printk(KERN_WARNING "ipt_NETLINK: packet drop due to netlink failure\n");
++ }
++
++ if ( MASK(nld->flags, USE_DROP) )
++ return NF_DROP;
++
++ return IPT_CONTINUE;
++}
++
++static int ipt_netlink_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hookmask)
++{
++ //struct ipt_nldata *nld = (struct ipt_nldata *)targinfo;
++
++ return 1;
++}
++
++static struct ipt_target ipt_netlink_reg = {
++ {NULL, NULL},
++ "NETLINK",
++ ipt_netlink_target,
++ ipt_netlink_checkentry,
++ NULL,
++ THIS_MODULE
++};
++
++static int __init init(void)
++{
++ DEBUGP("ipt_NETLINK: init module\n");
++
++ if (ipt_register_target(&ipt_netlink_reg) != 0) {
++ return -EINVAL;
++ }
++
++ if ( !(ipfwsk=netlink_kernel_create(NETLINK_FIREWALL, NULL)) ){
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ DEBUGP("ipt_NETLINK: cleanup_module\n");
++ ipt_unregister_target(&ipt_netlink_reg);
++ if(ipfwsk->sk_socket) sock_release(ipfwsk->sk_socket);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_POOL.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_POOL.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_POOL.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_POOL.c 2004-06-08 10:31:45.000000000 +0200
+@@ -0,0 +1,116 @@
++/* ipt_POOL.c - netfilter target to manipulate IP pools
++ *
++ * This target can be used almost everywhere. It acts on some specified
++ * IP pool, adding or deleting some IP address in the pool. The address
++ * can be either the source (--addsrc, --delsrc), or destination (--add/deldst)
++ * of the packet under inspection.
++ *
++ * The target normally returns IPT_CONTINUE.
++ */
++
++#include <linux/types.h>
++#include <linux/ip.h>
++#include <linux/timer.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/netdevice.h>
++#include <linux/if.h>
++#include <linux/inetdevice.h>
++#include <net/protocol.h>
++#include <net/checksum.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ipt_pool.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++/*** NOTE NOTE NOTE NOTE ***
++**
++** By sheer luck, I get away with using the "struct ipt_pool_info", as defined
++** in <linux/netfilter_ipv4/ipt_pool.h>, both as the match and target info.
++** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE,
++** is modified for the source IP address of the packet under inspection.
++** The same way, the ipt_pool_info.dst pool is modified for the destination.
++**
++** The address is added to the pool normally. However, if IPT_POOL_DEL_dir
++** flag is set in ipt_pool_info.flags, the address is deleted from the pool.
++**
++** If a modification was done to the pool, we possibly return ACCEPT or DROP,
++** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set.
++** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the
++** ACCEPT and DROP flags are evaluated when the pool was not modified.)
++*/
++
++static int
++do_check(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ const struct ipt_pool_info *ipi = targinfo;
++
++ if (targinfosize != IPT_ALIGN(sizeof(*ipi))) {
++ DEBUGP("POOL_check: size %u.\n", targinfosize);
++ return 0;
++ }
++ DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags);
++ return 1;
++}
++
++static unsigned int
++do_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 ipt_pool_info *ipi = targinfo;
++ int modified;
++ unsigned int verdict = IPT_CONTINUE;
++
++ if (ipi->src != IP_POOL_NONE) {
++ modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr),
++ ipi->flags & IPT_POOL_DEL_SRC);
++ if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) {
++ if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT)
++ verdict = NF_ACCEPT;
++ else if (ipi->flags & IPT_POOL_MOD_SRC_DROP)
++ verdict = NF_DROP;
++ }
++ }
++ if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) {
++ modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr),
++ ipi->flags & IPT_POOL_DEL_DST);
++ if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) {
++ if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT)
++ verdict = NF_ACCEPT;
++ else if (ipi->flags & IPT_POOL_MOD_DST_DROP)
++ verdict = NF_DROP;
++ }
++ }
++ return verdict;
++}
++
++static struct ipt_target pool_reg
++= { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ DEBUGP("init ipt_POOL\n");
++ return ipt_register_target(&pool_reg);
++}
++
++static void __exit fini(void)
++{
++ DEBUGP("fini ipt_POOL\n");
++ ipt_unregister_target(&pool_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_REJECT.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_REJECT.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_REJECT.c 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_REJECT.c 2004-06-08 10:30:55.000000000 +0200
+@@ -142,12 +142,7 @@
+ nskb->dst = &rt->u.dst;
+
+ /* 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
++ nf_reset(nskb);
+ nskb->nfmark = 0;
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ nf_bridge_put(nskb->nf_bridge);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_ROUTE.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_ROUTE.c 2004-06-08 10:37:08.000000000 +0200
+@@ -0,0 +1,393 @@
++/*
++ * This implements the ROUTE target, which enables you to setup unusual
++ * routes not supported by the standard kernel routing table.
++ *
++ * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * v 1.9 2004/05/14
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_ROUTE.h>
++#include <linux/netdevice.h>
++#include <linux/route.h>
++#include <net/ip.h>
++#include <net/route.h>
++#include <net/icmp.h>
++#include <net/checksum.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
++MODULE_DESCRIPTION("iptables ROUTE target module");
++
++/* Try to route the packet according to the routing keys specified in
++ * route_info. Keys are :
++ * - ifindex :
++ * 0 if no oif preferred,
++ * otherwise set to the index of the desired oif
++ * - route_info->gw :
++ * 0 if no gateway specified,
++ * otherwise set to the next host to which the pkt must be routed
++ * If success, skb->dev is the output device to which the packet must
++ * be sent and skb->dst is not NULL
++ *
++ * RETURN: -1 if an error occured
++ * 1 if the packet was succesfully routed to the
++ * destination desired
++ * 0 if the kernel routing table could not route the packet
++ * according to the keys specified
++ */
++static int route(struct sk_buff *skb,
++ unsigned int ifindex,
++ const struct ipt_route_target_info *route_info)
++{
++ int err;
++ struct rtable *rt;
++ struct iphdr *iph = skb->nh.iph;
++ struct flowi fl = {
++ .oif = ifindex,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = 0,
++ .tos = RT_TOS(iph->tos),
++ .scope = RT_SCOPE_UNIVERSE,
++ }
++ }
++ };
++
++ /* The destination address may be overloaded by the target */
++ if (route_info->gw)
++ fl.fld_dst = route_info->gw;
++
++ /* Trying to route the packet using the standard routing table. */
++ if ((err = ip_route_output_key(&rt, &fl))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
++ return -1;
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ /* Success if no oif specified or if the oif correspond to the
++ * one desired */
++ if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
++ skb->dst = &rt->u.dst;
++ skb->dev = skb->dst->dev;
++ return 1;
++ }
++
++ /* The interface selected by the routing table is not the one
++ * specified by the user. This may happen because the dst address
++ * is one of our own addresses.
++ */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n",
++ NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
++
++ return 0;
++}
++
++
++/* Stolen from ip_finish_output2
++ * PRE : skb->dev is set to the device we are leaving by
++ * skb->dst is not NULL
++ * POST: the packet is sent with the link layer header pushed
++ * the packet is destroyed
++ */
++static void ip_direct_send(struct sk_buff *skb)
++{
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++
++ if (hh) {
++ read_lock_bh(&hh->hh_lock);
++ memcpy(skb->data - 16, hh->hh_data, 16);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
++}
++
++
++/* PRE : skb->dev is set to the device we are leaving by
++ * POST: - the packet is directly sent to the skb->dev device, without
++ * pushing the link layer header.
++ * - the packet is destroyed
++ */
++static inline int dev_direct_send(struct sk_buff *skb)
++{
++ return dev_queue_xmit(skb);
++}
++
++
++static unsigned int route_oif(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ switch (route(skb, ifindex, route_info)) {
++ case 1:
++ dev_put(dev_out);
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++
++ case 0:
++ /* Failed to send to oif. Trying the hard way */
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return NF_DROP;
++
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: forcing the use of %i\n",
++ ifindex);
++
++ /* We have to force the use of an interface.
++ * This interface must be a tunnel interface since
++ * otherwise we can't guess the hw address for
++ * the packet. For a tunnel interface, no hw address
++ * is needed.
++ */
++ if ((dev_out->type != ARPHRD_TUNNEL)
++ && (dev_out->type != ARPHRD_IPGRE)) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
++ dev_put(dev_out);
++ return NF_DROP;
++ }
++
++ /* Send the packet. This will also free skb
++ * Do not go through the POST_ROUTING hook because
++ * skb->dst is not set and because it will probably
++ * get confused by the destination IP address.
++ */
++ skb->dev = dev_out;
++ dev_direct_send(skb);
++ dev_put(dev_out);
++ return NF_STOLEN;
++
++ default:
++ /* Unexpected error */
++ dev_put(dev_out);
++ return NF_DROP;
++ }
++}
++
++
++static unsigned int route_iif(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ struct net_device *dev_in = NULL;
++
++ /* Getting the current interface index. */
++ if (!(dev_in = dev_get_by_name(route_info->iif))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
++ return NF_DROP;
++ }
++
++ skb->dev = dev_in;
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ netif_rx(skb);
++ dev_put(dev_in);
++ return NF_STOLEN;
++}
++
++
++static unsigned int route_gw(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ if (route(skb, 0, route_info)!=1)
++ return NF_DROP;
++
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++}
++
++
++static unsigned int ipt_route_target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP_PRE_ROUTING ||
++ hooknum == NF_IP_LOCAL_IN) {
++
++ struct iphdr *iph = skb->nh.iph;
++
++ if (iph->ttl <= 1) {
++ struct rtable *rt;
++ struct flowi fl = {
++ .oif = 0,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = iph->saddr,
++ .tos = RT_TOS(iph->tos),
++ .scope = ((iph->tos & RTO_ONLINK) ?
++ RT_SCOPE_LINK :
++ RT_SCOPE_UNIVERSE)
++ }
++ }
++ };
++
++ if (ip_route_output_key(&rt, &fl)) {
++ return NF_DROP;
++ }
++
++ if (skb->dev == rt->u.dst.dev) {
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++
++ /* this will traverse normal stack, and
++ * thus call conntrack on the icmp packet */
++ icmp_send(skb, ICMP_TIME_EXCEEDED,
++ ICMP_EXC_TTL, 0);
++ }
++
++ return NF_DROP;
++ }
++
++ /*
++ * If we are at INPUT the checksum must be recalculated since
++ * the length could change as the result of a defragmentation.
++ */
++ if(hooknum == NF_IP_LOCAL_IN) {
++ iph->ttl = iph->ttl - 1;
++ iph->check = 0;
++ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++ } else {
++ ip_decrease_ttl(iph);
++ }
++ }
++
++ /* Tell conntrack to forget this packet since it may get confused
++ * when a packet is leaving with dst address == our address.
++ * Good idea ? Dunno. Need advice.
++ */
++ if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
++ nf_conntrack_put(skb->nfct);
++ skb->nfct = NULL;
++ skb->nfcache = 0;
++#ifdef CONFIG_NETFILTER_DEBUG
++ skb->nf_debug = 0;
++#endif
++ }
++
++ if (route_info->oif[0] != '\0')
++ return route_oif(route_info, *pskb);
++
++ if (route_info->iif[0] != '\0')
++ return route_iif(route_info, *pskb);
++
++ if (route_info->gw)
++ return route_gw(route_info, *pskb);
++
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
++
++ return IPT_CONTINUE;
++}
++
++
++static int ipt_route_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
++ tablename);
++ return 0;
++ }
++
++ if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING)
++ | (1 << NF_IP_LOCAL_IN)
++ | (1 << NF_IP_FORWARD)
++ | (1 << NF_IP_LOCAL_OUT)
++ | (1 << NF_IP_POST_ROUTING))) {
++ printk("ipt_ROUTE: bad hook\n");
++ return 0;
++ }
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
++ printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_route_target_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static struct ipt_target ipt_route_reg = {
++ .name = "ROUTE",
++ .target = ipt_route_target,
++ .checkentry = ipt_route_checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_route_reg);
++}
++
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_route_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TARPIT.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TARPIT.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TARPIT.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TARPIT.c 2004-06-08 10:37:16.000000000 +0200
+@@ -0,0 +1,290 @@
++/*
++ * Kernel module to capture and hold incoming TCP connections using
++ * no local per-connection resources.
++ *
++ * Based on ipt_REJECT.c and offering functionality similar to
++ * LaBrea <http://www.hackbusters.net/LaBrea/>.
++ *
++ * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Goal:
++ * - Allow incoming TCP connections to be established.
++ * - Passing data should result in the connection being switched to the
++ * persist state (0 byte window), in which the remote side stops sending
++ * data and asks to continue every 60 seconds.
++ * - Attempts to shut down the connection should be ignored completely, so
++ * the remote side ends up having to time it out.
++ *
++ * This means:
++ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
++ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
++ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/ip.h>
++#include <net/tcp.h>
++#include <net/icmp.h>
++struct in_device;
++#include <net/route.h>
++#include <linux/random.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Aaron Hopkins <tools@die.net>");
++
++/* Stolen from ip_finish_output2 */
++static int ip_direct_send(struct sk_buff *skb)
++{
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++
++ if (hh) {
++ read_lock_bh(&hh->hh_lock);
++ memcpy(skb->data - 16, hh->hh_data, 16);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ return hh->hh_output(skb);
++ } else if (dst->neighbour)
++ return dst->neighbour->output(skb);
++
++ if (net_ratelimit())
++ printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
++ kfree_skb(skb);
++ return -EINVAL;
++}
++
++
++/* Send reply */
++static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local)
++{
++ struct sk_buff *nskb;
++ struct rtable *nrt;
++ struct tcphdr *otcph, *ntcph;
++ struct flowi fl = {};
++ unsigned int otcplen;
++ u_int16_t tmp;
++
++ /* A truncated TCP header isn't going to be useful */
++ if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr))
++ return;
++
++ otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph
++ + oskb->nh.iph->ihl);
++ otcplen = oskb->len - oskb->nh.iph->ihl*4;
++
++ /* No replies for RST or FIN */
++ if (otcph->rst || otcph->fin)
++ return;
++
++ /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */
++ if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
++ return;
++
++ /* Check checksum. */
++ if (tcp_v4_check(otcph, otcplen, oskb->nh.iph->saddr,
++ oskb->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(oskb, 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
++
++ ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
++
++ /* Truncate to length (no data) */
++ ntcph->doff = sizeof(struct tcphdr)/4;
++ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
++ nskb->nh.iph->tot_len = htons(nskb->len);
++
++ /* Swap source and dest */
++ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
++ tmp = ntcph->source;
++ ntcph->source = ntcph->dest;
++ ntcph->dest = tmp;
++
++ /* Use supplied sequence number or make a new one */
++ ntcph->seq = otcph->ack ? otcph->ack_seq
++ : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr,
++ nskb->nh.iph->daddr,
++ ntcph->source,
++ ntcph->dest));
++
++ /* Our SYN-ACKs must have a >0 window */
++ ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
++
++ ntcph->urg_ptr = 0;
++
++ /* Reset flags */
++ ((u_int8_t *)ntcph)[13] = 0;
++
++ if (otcph->syn && otcph->ack) {
++ ntcph->rst = 1;
++ ntcph->ack_seq = 0;
++ } else {
++ ntcph->syn = otcph->syn;
++ ntcph->ack = 1;
++ ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
++ }
++
++ /* Adjust TCP checksum */
++ ntcph->check = 0;
++ ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr),
++ nskb->nh.iph->saddr,
++ nskb->nh.iph->daddr,
++ csum_partial((char *)ntcph,
++ sizeof(struct tcphdr), 0));
++
++ /* Adjust IP TTL */
++ nskb->nh.iph->ttl = sysctl_ip_default_ttl;
++
++ /* 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);
++
++ fl.nl_u.ip4_u.daddr = nskb->nh.iph->daddr;
++ fl.nl_u.ip4_u.saddr = local ? nskb->nh.iph->saddr : 0;
++ fl.nl_u.ip4_u.tos = RT_TOS(nskb->nh.iph->tos) | RTO_CONN;
++ fl.oif = 0;
++
++ if (ip_route_output_key(&nrt, &fl))
++ goto free_nskb;
++
++ dst_release(nskb->dst);
++ nskb->dst = &nrt->u.dst;
++
++ /* "Never happens" */
++ if (nskb->len > dst_pmtu(nskb->dst))
++ goto free_nskb;
++
++ ip_direct_send (nskb);
++
++ return;
++
++ free_nskb:
++ kfree_skb(nskb);
++}
++
++
++static unsigned int tarpit(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ struct sk_buff *skb = *pskb;
++ struct rtable *rt = (struct rtable*)skb->dst;
++
++ /* Do we have an input route cache entry? */
++ if (!rt)
++ return NF_DROP;
++
++ /* No replies to physical multicast/broadcast */
++ if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
++ return NF_DROP;
++
++ /* Now check at the protocol level */
++ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
++ return NF_DROP;
++
++ /* Our naive response construction doesn't deal with IP
++ options, and probably shouldn't try. */
++ if (skb->nh.iph->ihl*4 != sizeof(struct iphdr))
++ return NF_DROP;
++
++ /* We aren't interested in fragments */
++ if (skb->nh.iph->frag_off & htons(IP_OFFSET))
++ return NF_DROP;
++
++ tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN);
++
++ return NF_DROP;
++}
++
++
++static int check(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ /* Only allow these for input/forward packet filtering. */
++ if (strcmp(tablename, "filter") != 0) {
++ DEBUGP("TARPIT: bad table %s'.\n", tablename);
++ return 0;
++ }
++ if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
++ | (1 << NF_IP_FORWARD))) != 0) {
++ DEBUGP("TARPIT: bad hook mask %X\n", hook_mask);
++ return 0;
++ }
++
++ /* Must specify that it's a TCP packet */
++ if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) {
++ DEBUGP("TARPIT: not valid for non-tcp\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_tarpit_reg = {
++ .name = "TARPIT",
++ .target = tarpit,
++ .checkentry = check,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_tarpit_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_tarpit_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TRACE.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TRACE.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TRACE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TRACE.c 2004-06-08 10:37:30.000000000 +0200
+@@ -0,0 +1,64 @@
++/* This is a module which is used for setting
++ * the NFC_TRACE flag in the nfcache field of an skb.
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++static unsigned int
++target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ (*pskb)->nfcache |= NFC_TRACE;
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (targinfosize != 0) {
++ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
++ targinfosize);
++ return 0;
++ }
++
++ if (strcmp(tablename, "raw") != 0) {
++ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_trace_reg = {
++ .name = "TRACE",
++ .target = target,
++ .checkentry = checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ipt_register_target(&ipt_trace_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_trace_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TTL.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_TTL.c 2004-06-08 10:31:21.000000000 +0200
+@@ -0,0 +1,120 @@
++/* TTL modification target for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Version: $Revision$
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_TTL.h>
++
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("IP tables TTL modification module");
++MODULE_LICENSE("GPL");
++
++static unsigned int
++ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
++ const struct net_device *out, unsigned int hooknum,
++ const void *targinfo, void *userinfo)
++{
++ struct iphdr *iph;
++ const struct ipt_TTL_info *info = targinfo;
++ u_int16_t diffs[2];
++ int new_ttl;
++
++ if (!skb_ip_make_writable(pskb, (*pskb)->len))
++ return NF_DROP;
++
++ iph = (*pskb)->nh.iph;
++
++ switch (info->mode) {
++ case IPT_TTL_SET:
++ new_ttl = info->ttl;
++ break;
++ case IPT_TTL_INC:
++ new_ttl = iph->ttl + info->ttl;
++ if (new_ttl > 255)
++ new_ttl = 255;
++ break;
++ case IPT_TTL_DEC:
++ new_ttl = iph->ttl + info->ttl;
++ if (new_ttl < 0)
++ new_ttl = 0;
++ break;
++ default:
++ new_ttl = iph->ttl;
++ break;
++ }
++
++ if (new_ttl != iph->ttl) {
++ diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
++ iph->ttl = new_ttl;
++ diffs[1] = htons(((unsigned)iph->ttl) << 8);
++ iph->check = csum_fold(csum_partial((char *)diffs,
++ sizeof(diffs),
++ iph->check^0xFFFF));
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++
++ return IPT_CONTINUE;
++}
++
++static int ipt_ttl_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_TTL_info *info = targinfo;
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
++ printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_TTL_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ if (info->mode > IPT_TTL_MAXMODE) {
++ printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
++ info->mode);
++ return 0;
++ }
++
++ if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
++ printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_TTL = {
++ .name = "TTL",
++ .target = ipt_ttl_target,
++ .checkentry = ipt_ttl_checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_TTL);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_TTL);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_XOR.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_XOR.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_XOR.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_XOR.c 2004-06-08 10:37:54.000000000 +0200
+@@ -0,0 +1,117 @@
++/* XOR target for IP tables
++ * (C) 2000 by Tim Vandermeersch <Tim.Vandermeersch@pandora.be>
++ * Based on ipt_TTL.c
++ *
++ * Version 1.0
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_XOR.h>
++
++MODULE_AUTHOR("Tim Vandermeersch <Tim.Vandermeersch@pandora.be>");
++MODULE_DESCRIPTION("IP tables XOR module");
++MODULE_LICENSE("GPL");
++
++static unsigned int
++ipt_xor_target(struct sk_buff **pskb,
++ const struct net_device *in, const struct net_device *out,
++ unsigned int hooknum, const void *targinfo, void *userinfo)
++{
++ struct ipt_XOR_info *info = (void *) targinfo;
++ struct iphdr *iph;
++ struct tcphdr *tcph;
++ struct udphdr *udph;
++ int i, j, k;
++
++ if (!skb_ip_make_writable(pskb, (*pskb)->len))
++ return NF_DROP;
++
++ iph = (*pskb)->nh.iph;
++
++ if (iph->protocol == IPPROTO_TCP) {
++ tcph = (struct tcphdr *) ((*pskb)->data + iph->ihl*4);
++ for (i=0, j=0; i<(ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4); ) {
++ for (k=0; k<=info->block_size; k++) {
++ (char) (*pskb)->data[ iph->ihl*4 + tcph->doff*4 + i ] ^=
++ info->key[j];
++ i++;
++ }
++ j++;
++ if (info->key[j] == 0x00)
++ j = 0;
++ }
++ } else if (iph->protocol == IPPROTO_UDP) {
++ udph = (struct udphdr *) ((*pskb)->data + iph->ihl*4);
++ for (i=0, j=0; i<(ntohs(udph->len)-8); ) {
++ for (k=0; k<=info->block_size; k++) {
++ (char) (*pskb)->data[ iph->ihl*4 + sizeof(struct udphdr) + i ] ^=
++ info->key[j];
++ i++;
++ }
++ j++;
++ if (info->key[j] == 0x00)
++ j = 0;
++ }
++ }
++
++ return IPT_CONTINUE;
++}
++
++static int ipt_xor_checkentry(const char *tablename, const struct ipt_entry *e,
++ void *targinfo, unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_XOR_info *info = targinfo;
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_XOR_info))) {
++ printk(KERN_WARNING "XOR: targinfosize %u != %Zu\n",
++ targinfosize, IPT_ALIGN(sizeof(struct ipt_XOR_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "XOR: can only be called from"
++ "\"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ if (!strcmp(info->key, "")) {
++ printk(KERN_WARNING "XOR: You must specify a key");
++ return 0;
++ }
++
++ if (info->block_size == 0) {
++ printk(KERN_WARNING "XOR: You must specify a block-size");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_XOR = {
++ .name = "XOR",
++ .target = ipt_xor_target,
++ .checkentry = ipt_xor_checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_XOR);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_XOR);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_addrtype.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_addrtype.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_addrtype.c 2004-06-08 10:38:04.000000000 +0200
+@@ -0,0 +1,75 @@
++/*
++ * iptables module to match inet_addr_type() of an ip.
++ *
++ * Copyright (c) 2004 Patrick McHardy <kaber@trash.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/route.h>
++
++#include <linux/netfilter_ipv4/ipt_addrtype.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
++MODULE_DESCRIPTION("iptables addrtype match");
++
++static inline int match_type(u_int32_t addr, u_int16_t mask)
++{
++ return !!(mask & (1 << inet_addr_type(addr)));
++}
++
++static int match(const struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const void *matchinfo,
++ int offset, int *hotdrop)
++{
++ const struct ipt_addrtype_info *info = matchinfo;
++ const struct iphdr *iph = skb->nh.iph;
++ int ret = 1;
++
++ if (info->source)
++ ret &= match_type(iph->saddr, info->source)^info->invert_source;
++ if (info->dest)
++ ret &= match_type(iph->daddr, info->dest)^info->invert_dest;
++
++ return ret;
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) {
++ printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.",
++ matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match addrtype_match = {
++ .name = "addrtype",
++ .match = match,
++ .checkentry = checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&addrtype_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&addrtype_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_connlimit.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_connlimit.c 2004-06-08 10:31:23.000000000 +0200
+@@ -0,0 +1,230 @@
++/*
++ * netfilter module to limit the number of parallel tcp
++ * connections per IP address.
++ * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
++ * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
++ * only ignore TIME_WAIT or gone connections
++ *
++ * based on ...
++ *
++ * Kernel module to match connection tracking information.
++ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connlimit.h>
++
++#define DEBUG 0
++
++MODULE_LICENSE("GPL");
++
++/* we'll save the tuples of all connections we care about */
++struct ipt_connlimit_conn
++{
++ struct list_head list;
++ struct ip_conntrack_tuple tuple;
++};
++
++struct ipt_connlimit_data {
++ spinlock_t lock;
++ struct list_head iphash[256];
++};
++
++static int ipt_iphash(u_int32_t addr)
++{
++ int hash;
++
++ hash = addr & 0xff;
++ hash ^= (addr >> 8) & 0xff;
++ hash ^= (addr >> 16) & 0xff;
++ hash ^= (addr >> 24) & 0xff;
++ return hash;
++}
++
++static int count_them(struct ipt_connlimit_data *data,
++ u_int32_t addr, u_int32_t mask,
++ struct ip_conntrack *ct)
++{
++#if DEBUG
++ const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
++ "fin_wait", "time_wait", "close", "close_wait",
++ "last_ack", "listen" };
++#endif
++ int addit = 1, matches = 0;
++ struct ip_conntrack_tuple tuple;
++ struct ip_conntrack_tuple_hash *found;
++ struct ipt_connlimit_conn *conn;
++ struct list_head *hash,*lh;
++
++ spin_lock(&data->lock);
++ tuple = ct->tuplehash[0].tuple;
++ hash = &data->iphash[ipt_iphash(addr & mask)];
++
++ /* check the saved connections */
++ for (lh = hash->next; lh != hash; lh = lh->next) {
++ conn = list_entry(lh,struct ipt_connlimit_conn,list);
++ found = ip_conntrack_find_get(&conn->tuple,ct);
++ if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
++ found != NULL &&
++ found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
++ /* Just to be sure we have it only once in the list.
++ We should'nt see tuples twice unless someone hooks this
++ into a table without "-p tcp --syn" */
++ addit = 0;
++ }
++#if DEBUG
++ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
++ ipt_iphash(addr & mask),
++ NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
++ NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
++ (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
++#endif
++ if (NULL == found) {
++ /* this one is gone */
++ lh = lh->prev;
++ list_del(lh->next);
++ kfree(conn);
++ continue;
++ }
++ if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
++ /* we don't care about connections which are
++ closed already -> ditch it */
++ lh = lh->prev;
++ list_del(lh->next);
++ kfree(conn);
++ nf_conntrack_put(&found->ctrack->infos[0]);
++ continue;
++ }
++ if ((addr & mask) == (conn->tuple.src.ip & mask)) {
++ /* same source IP address -> be counted! */
++ matches++;
++ }
++ nf_conntrack_put(&found->ctrack->infos[0]);
++ }
++ if (addit) {
++ /* save the new connection in our list */
++#if DEBUG
++ printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
++ ipt_iphash(addr & mask),
++ NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
++ NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
++#endif
++ conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
++ if (NULL == conn)
++ return -1;
++ memset(conn,0,sizeof(*conn));
++ INIT_LIST_HEAD(&conn->list);
++ conn->tuple = tuple;
++ list_add(&conn->list,hash);
++ matches++;
++ }
++ spin_unlock(&data->lock);
++ return matches;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_connlimit_info *info = matchinfo;
++ int connections, match;
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++
++ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++ if (NULL == ct) {
++ printk("ipt_connlimit: Oops: invalid ct state ?\n");
++ *hotdrop = 1;
++ return 0;
++ }
++ connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
++ if (-1 == connections) {
++ printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
++ *hotdrop = 1; /* let's free some memory :-) */
++ return 0;
++ }
++ match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
++#if DEBUG
++ printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
++ "connections=%d limit=%d match=%s\n",
++ NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
++ connections, info->limit, match ? "yes" : "no");
++#endif
++
++ return match;
++}
++
++static int check(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_connlimit_info *info = matchinfo;
++ int i;
++
++ /* verify size */
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
++ return 0;
++
++ /* refuse anything but tcp */
++ if (ip->proto != IPPROTO_TCP)
++ return 0;
++
++ /* init private data */
++ info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
++ spin_lock_init(&(info->data->lock));
++ for (i = 0; i < 256; i++)
++ INIT_LIST_HEAD(&(info->data->iphash[i]));
++
++ return 1;
++}
++
++static void destroy(void *matchinfo, unsigned int matchinfosize)
++{
++ struct ipt_connlimit_info *info = matchinfo;
++ struct ipt_connlimit_conn *conn;
++ struct list_head *hash;
++ int i;
++
++ /* cleanup */
++ for (i = 0; i < 256; i++) {
++ hash = &(info->data->iphash[i]);
++ while (hash != hash->next) {
++ conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
++ list_del(hash->next);
++ kfree(conn);
++ }
++ }
++ kfree(info->data);
++}
++
++static struct ipt_match connlimit_match = {
++ .name = "connlimit",
++ .match = &match,
++ .checkentry = &check,
++ .destroy = &destroy,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&connlimit_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&connlimit_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_connmark.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_connmark.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_connmark.c 2004-06-08 10:36:58.000000000 +0200
+@@ -0,0 +1,81 @@
++/* This kernel module matches connection mark values set by the
++ * CONNMARK target
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables connmark match module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connmark.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_connmark_info *info = matchinfo;
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++ if (!ct)
++ return 0;
++
++ return ((ct->mark & info->mask) == info->mark) ^ info->invert;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match connmark_match = {
++ .name = "connmark",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&connmark_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&connmark_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_dstlimit.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_dstlimit.c 2004-06-08 10:31:34.000000000 +0200
+@@ -0,0 +1,690 @@
++/* iptables match extension to limit the number of packets per second
++ * seperately for each destination.
++ *
++ * (C) 2003 by Harald Welte <laforge@netfilter.org>
++ *
++ * $Id$
++ *
++ * Development of this code was funded by Astaro AG, http://www.astaro.com/
++ *
++ * based on ipt_limit.c by:
++ * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
++ * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
++ * Rusty Russell <rusty@rustcorp.com.au>
++ *
++ * The general idea is to create a hash table for every dstip and have a
++ * seperate limit counter per tuple. This way you can do something like 'limit
++ * the number of syn packets for each of my internal addresses.
++ *
++ * Ideally this would just be implemented as a general 'hash' match, which would
++ * allow us to attach any iptables target to it's hash buckets. But this is
++ * not possible in the current iptables architecture. As always, pkttables for
++ * 2.7.x will help ;)
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/random.h>
++#include <linux/jhash.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++
++#define ASSERT_READ_LOCK(x)
++#define ASSERT_WRITE_LOCK(x)
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_dstlimit.h>
++
++/* FIXME: this is just for IP_NF_ASSERRT */
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++#define MS2JIFFIES(x) ((x*HZ)/1000)
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
++MODULE_DESCRIPTION("iptables match for limiting per destination");
++
++/* need to declare this at the top */
++static struct proc_dir_entry *dstlimit_procdir;
++static struct file_operations dl_file_ops;
++
++/* hash table crap */
++
++struct dsthash_dst {
++ u_int32_t src_ip;
++ u_int32_t dst_ip;
++ u_int16_t port;
++};
++
++struct dsthash_ent {
++ /* static / read-only parts in the beginning */
++ struct list_head list;
++ struct dsthash_dst dst;
++
++ /* modified structure members in the end */
++ unsigned long expires; /* precalculated expiry time */
++ struct {
++ unsigned long prev; /* last modification */
++ u_int32_t credit;
++ u_int32_t credit_cap, cost;
++ } rateinfo;
++};
++
++struct ipt_dstlimit_htable {
++ struct list_head list; /* global list of all htables */
++ atomic_t use;
++
++ struct dstlimit_cfg cfg; /* config */
++
++ /* used internally */
++ spinlock_t lock; /* lock for list_head */
++ u_int32_t rnd; /* random seed for hash */
++ struct timer_list timer; /* timer for gc */
++ atomic_t count; /* number entries in table */
++
++ /* seq_file stuff */
++ struct proc_dir_entry *pde;
++
++ struct list_head hash[0]; /* hashtable itself */
++};
++
++DECLARE_RWLOCK(dstlimit_lock); /* protects htables list */
++static LIST_HEAD(dstlimit_htables);
++static kmem_cache_t *dstlimit_cachep;
++
++static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
++{
++ return (ent->dst.dst_ip == b->dst_ip
++ && ent->dst.port == b->port
++ && ent->dst.src_ip == b->src_ip);
++}
++
++static inline u_int32_t
++hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
++{
++ return (jhash_3words(dst->dst_ip, dst->port,
++ dst->src_ip, ht->rnd) % ht->cfg.size);
++}
++
++static inline struct dsthash_ent *
++__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
++{
++ struct dsthash_ent *ent;
++ u_int32_t hash = hash_dst(ht, dst);
++ MUST_BE_LOCKED(&ht->lock);
++ ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
++ return ent;
++}
++
++/* allocate dsthash_ent, initialize dst, put in htable and lock it */
++static struct dsthash_ent *
++__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
++{
++ struct dsthash_ent *ent;
++
++ /* initialize hash with random val at the time we allocate
++ * the first hashtable entry */
++ if (!ht->rnd)
++ get_random_bytes(&ht->rnd, 4);
++
++ if (ht->cfg.max &&
++ atomic_read(&ht->count) >= ht->cfg.max) {
++ /* FIXME: do something. question is what.. */
++ if (net_ratelimit())
++ printk(KERN_WARNING
++ "ipt_dstlimit: max count of %u reached\n",
++ ht->cfg.max);
++ return NULL;
++ }
++
++ ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
++ if (!ent) {
++ if (net_ratelimit())
++ printk(KERN_ERR
++ "ipt_dstlimit: can't allocate dsthash_ent\n");
++ return NULL;
++ }
++
++ atomic_inc(&ht->count);
++
++ ent->dst.dst_ip = dst->dst_ip;
++ ent->dst.port = dst->port;
++ ent->dst.src_ip = dst->src_ip;
++
++ list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
++
++ return ent;
++}
++
++static inline void
++__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
++{
++ MUST_BE_LOCKED(&ht->lock);
++
++ list_del(&ent->list);
++ kmem_cache_free(dstlimit_cachep, ent);
++ atomic_dec(&ht->count);
++}
++static void htable_gc(unsigned long htlong);
++
++static int htable_create(struct ipt_dstlimit_info *minfo)
++{
++ int i;
++ unsigned int size;
++ struct ipt_dstlimit_htable *hinfo;
++
++ if (minfo->cfg.size)
++ size = minfo->cfg.size;
++ else {
++ size = (((num_physpages << PAGE_SHIFT) / 16384)
++ / sizeof(struct list_head));
++ if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
++ size = 8192;
++ if (size < 16)
++ size = 16;
++ }
++ /* FIXME: don't use vmalloc() here or anywhere else -HW */
++ hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
++ + (sizeof(struct list_head) * size));
++ if (!hinfo) {
++ printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
++ return -1;
++ }
++ minfo->hinfo = hinfo;
++
++ /* copy match config into hashtable config */
++ memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
++ hinfo->cfg.size = size;
++ if (!hinfo->cfg.max)
++ hinfo->cfg.max = 8 * hinfo->cfg.size;
++ else if (hinfo->cfg.max < hinfo->cfg.size)
++ hinfo->cfg.max = hinfo->cfg.size;
++
++ for (i = 0; i < hinfo->cfg.size; i++)
++ INIT_LIST_HEAD(&hinfo->hash[i]);
++
++ atomic_set(&hinfo->count, 0);
++ atomic_set(&hinfo->use, 1);
++ hinfo->rnd = 0;
++ hinfo->lock = SPIN_LOCK_UNLOCKED;
++ hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
++ if (!hinfo->pde) {
++ vfree(hinfo);
++ return -1;
++ }
++ hinfo->pde->proc_fops = &dl_file_ops;
++ hinfo->pde->data = hinfo;
++
++ init_timer(&hinfo->timer);
++ hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
++ hinfo->timer.data = (unsigned long )hinfo;
++ hinfo->timer.function = htable_gc;
++ add_timer(&hinfo->timer);
++
++ WRITE_LOCK(&dstlimit_lock);
++ list_add(&hinfo->list, &dstlimit_htables);
++ WRITE_UNLOCK(&dstlimit_lock);
++
++ return 0;
++}
++
++static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
++{
++ return 1;
++}
++
++static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
++{
++ return (jiffies >= he->expires);
++}
++
++static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
++ int (*select)(struct ipt_dstlimit_htable *ht,
++ struct dsthash_ent *he))
++{
++ int i;
++
++ IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
++
++ /* lock hash table and iterate over it */
++ LOCK_BH(&ht->lock);
++ for (i = 0; i < ht->cfg.size; i++) {
++ struct dsthash_ent *dh, *n;
++ list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
++ if ((*select)(ht, dh))
++ __dsthash_free(ht, dh);
++ }
++ }
++ UNLOCK_BH(&ht->lock);
++}
++
++/* hash table garbage collector, run by timer */
++static void htable_gc(unsigned long htlong)
++{
++ struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
++
++ htable_selective_cleanup(ht, select_gc);
++
++ /* re-add the timer accordingly */
++ ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
++ add_timer(&ht->timer);
++}
++
++static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
++{
++ /* remove timer, if it is pending */
++ if (timer_pending(&hinfo->timer))
++ del_timer(&hinfo->timer);
++
++ /* remove proc entry */
++ remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
++
++ htable_selective_cleanup(hinfo, select_all);
++ vfree(hinfo);
++}
++
++static struct ipt_dstlimit_htable *htable_find_get(char *name)
++{
++ struct ipt_dstlimit_htable *hinfo;
++
++ READ_LOCK(&dstlimit_lock);
++ list_for_each_entry(hinfo, &dstlimit_htables, list) {
++ if (!strcmp(name, hinfo->pde->name)) {
++ atomic_inc(&hinfo->use);
++ READ_UNLOCK(&dstlimit_lock);
++ return hinfo;
++ }
++ }
++ READ_UNLOCK(&dstlimit_lock);
++
++ return NULL;
++}
++
++static void htable_put(struct ipt_dstlimit_htable *hinfo)
++{
++ if (atomic_dec_and_test(&hinfo->use)) {
++ WRITE_LOCK(&dstlimit_lock);
++ list_del(&hinfo->list);
++ WRITE_UNLOCK(&dstlimit_lock);
++ htable_destroy(hinfo);
++ }
++}
++
++
++/* The algorithm used is the Simple Token Bucket Filter (TBF)
++ * see net/sched/sch_tbf.c in the linux source tree
++ */
++
++/* Rusty: This is my (non-mathematically-inclined) understanding of
++ this algorithm. The `average rate' in jiffies becomes your initial
++ amount of credit `credit' and the most credit you can ever have
++ `credit_cap'. The `peak rate' becomes the cost of passing the
++ test, `cost'.
++
++ `prev' tracks the last packet hit: you gain one credit per jiffy.
++ If you get credit balance more than this, the extra credit is
++ discarded. Every time the match passes, you lose `cost' credits;
++ if you don't have that many, the test fails.
++
++ See Alexey's formal explanation in net/sched/sch_tbf.c.
++
++ To get the maximum range, we multiply by this factor (ie. you get N
++ credits per jiffy). We want to allow a rate as low as 1 per day
++ (slowest userspace tool allows), which means
++ CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
++*/
++#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
++
++/* Repeated shift and or gives us all 1s, final shift and add 1 gives
++ * us the power of 2 below the theoretical max, so GCC simply does a
++ * shift. */
++#define _POW2_BELOW2(x) ((x)|((x)>>1))
++#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
++#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
++#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
++#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
++#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
++
++#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
++
++/* Precision saver. */
++static inline u_int32_t
++user2credits(u_int32_t user)
++{
++ /* If multiplying would overflow... */
++ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
++ /* Divide first. */
++ return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
++
++ return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
++}
++
++static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
++{
++ dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
++ * CREDITS_PER_JIFFY;
++ if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
++ dh->rateinfo.credit = dh->rateinfo.credit_cap;
++}
++
++static int
++dstlimit_match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ struct ipt_dstlimit_info *r =
++ ((struct ipt_dstlimit_info *)matchinfo)->u.master;
++ struct ipt_dstlimit_htable *hinfo = r->hinfo;
++ unsigned long now = jiffies;
++ struct dsthash_ent *dh;
++ struct dsthash_dst dst;
++
++ memset(&dst, 0, sizeof(dst));
++
++ /* dest ip is always in hash */
++ dst.dst_ip = skb->nh.iph->daddr;
++
++ /* source ip only if respective hashmode, otherwise set to
++ * zero */
++ if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
++ dst.src_ip = skb->nh.iph->saddr;
++
++ /* dest port only if respective mode */
++ if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
++ u16 ports[2];
++
++ /* Must not be a fragment. */
++ if (offset)
++ return 0;
++
++ /* Must be big enough to read ports (both UDP and TCP have
++ them at the start). */
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
++ /* We've been asked to examine this packet, and we
++ can't. Hence, no choice but to drop. */
++ *hotdrop = 1;
++ return 0;
++ }
++
++ switch (skb->nh.iph->protocol) {
++ struct tcphdr *th;
++ struct udphdr *uh;
++ case IPPROTO_TCP:
++ th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
++ dst.port = th->dest;
++ break;
++ case IPPROTO_UDP:
++ uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
++ dst.port = uh->dest;
++ break;
++ default:
++ break;
++ }
++ }
++
++ LOCK_BH(&hinfo->lock);
++ dh = __dsthash_find(hinfo, &dst);
++ if (!dh) {
++ dh = __dsthash_alloc_init(hinfo, &dst);
++
++ if (!dh) {
++ /* enomem... don't match == DROP */
++ if (net_ratelimit())
++ printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
++ UNLOCK_BH(&hinfo->lock);
++ return 0;
++ }
++
++ dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
++
++ dh->rateinfo.prev = jiffies;
++ dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
++ hinfo->cfg.burst);
++ dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
++ hinfo->cfg.burst);
++ dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
++
++ UNLOCK_BH(&hinfo->lock);
++ return 1;
++ }
++
++ /* update expiration timeout */
++ dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
++
++ rateinfo_recalc(dh, now);
++ if (dh->rateinfo.credit >= dh->rateinfo.cost) {
++ /* We're underlimit. */
++ dh->rateinfo.credit -= dh->rateinfo.cost;
++ UNLOCK_BH(&hinfo->lock);
++ return 1;
++ }
++
++ UNLOCK_BH(&hinfo->lock);
++
++ /* default case: we're overlimit, thus don't match */
++ return 0;
++}
++
++static int
++dstlimit_checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_dstlimit_info *r = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
++ return 0;
++
++ /* Check for overflow. */
++ if (r->cfg.burst == 0
++ || user2credits(r->cfg.avg * r->cfg.burst) <
++ user2credits(r->cfg.avg)) {
++ printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
++ r->cfg.avg, r->cfg.burst);
++ return 0;
++ }
++
++ if (r->cfg.mode == 0
++ || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
++ |IPT_DSTLIMIT_HASH_DIP
++ |IPT_DSTLIMIT_HASH_SIP))
++ return 0;
++
++ if (!r->cfg.gc_interval)
++ return 0;
++
++ if (!r->cfg.expire)
++ return 0;
++
++ r->hinfo = htable_find_get(r->name);
++ if (!r->hinfo && (htable_create(r) != 0)) {
++ return 0;
++ }
++
++ /* Ugly hack: For SMP, we only want to use one set */
++ r->u.master = r;
++
++ return 1;
++}
++
++static void
++dstlimit_destroy(void *matchinfo, unsigned int matchsize)
++{
++ struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
++
++ htable_put(r->hinfo);
++}
++
++static struct ipt_match ipt_dstlimit = {
++ .list = { .prev = NULL, .next = NULL },
++ .name = "dstlimit",
++ .match = dstlimit_match,
++ .checkentry = dstlimit_checkentry,
++ .destroy = dstlimit_destroy,
++ .me = THIS_MODULE
++};
++
++/* PROC stuff */
++
++static void *dl_seq_start(struct seq_file *s, loff_t *pos)
++{
++ struct proc_dir_entry *pde = s->private;
++ struct ipt_dstlimit_htable *htable = pde->data;
++ unsigned int *bucket;
++
++ LOCK_BH(&htable->lock);
++ if (*pos >= htable->cfg.size)
++ return NULL;
++
++ bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
++ if (!bucket)
++ return ERR_PTR(-ENOMEM);
++
++ *bucket = *pos;
++ return bucket;
++}
++
++static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
++{
++ struct proc_dir_entry *pde = s->private;
++ struct ipt_dstlimit_htable *htable = pde->data;
++ unsigned int *bucket = (unsigned int *)v;
++
++ *pos = ++(*bucket);
++ if (*pos >= htable->cfg.size) {
++ kfree(v);
++ return NULL;
++ }
++ return bucket;
++}
++
++static void dl_seq_stop(struct seq_file *s, void *v)
++{
++ struct proc_dir_entry *pde = s->private;
++ struct ipt_dstlimit_htable *htable = pde->data;
++ unsigned int *bucket = (unsigned int *)v;
++
++ kfree(bucket);
++
++ UNLOCK_BH(&htable->lock);
++}
++
++static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
++{
++ /* recalculate to show accurate numbers */
++ rateinfo_recalc(ent, jiffies);
++
++ return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
++ (ent->expires - jiffies)/HZ,
++ NIPQUAD(ent->dst.src_ip),
++ NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
++ ent->rateinfo.credit, ent->rateinfo.credit_cap,
++ ent->rateinfo.cost);
++}
++
++static int dl_seq_show(struct seq_file *s, void *v)
++{
++ struct proc_dir_entry *pde = s->private;
++ struct ipt_dstlimit_htable *htable = pde->data;
++ unsigned int *bucket = (unsigned int *)v;
++
++ if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
++ struct dsthash_ent *, s)) {
++ /* buffer was filled and unable to print that tuple */
++ return 1;
++ }
++ return 0;
++}
++
++static struct seq_operations dl_seq_ops = {
++ .start = dl_seq_start,
++ .next = dl_seq_next,
++ .stop = dl_seq_stop,
++ .show = dl_seq_show
++};
++
++static int dl_proc_open(struct inode *inode, struct file *file)
++{
++ int ret = seq_open(file, &dl_seq_ops);
++
++ if (!ret) {
++ struct seq_file *sf = file->private_data;
++ sf->private = PDE(inode);
++ }
++ return ret;
++}
++
++static struct file_operations dl_file_ops = {
++ .owner = THIS_MODULE,
++ .open = dl_proc_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release
++};
++
++static int init_or_fini(int fini)
++{
++ int ret = 0;
++
++ if (fini)
++ goto cleanup;
++
++ if (ipt_register_match(&ipt_dstlimit)) {
++ ret = -EINVAL;
++ goto cleanup_nothing;
++ }
++
++ /* FIXME: do we really want HWCACHE_ALIGN since our objects are
++ * quite small ? */
++ dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
++ sizeof(struct dsthash_ent), 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (!dstlimit_cachep) {
++ printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
++ ret = -ENOMEM;
++ goto cleanup_unreg_match;
++ }
++
++ dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
++ if (!dstlimit_procdir) {
++ printk(KERN_ERR "Unable to create proc dir entry\n");
++ ret = -ENOMEM;
++ goto cleanup_free_slab;
++ }
++
++ return ret;
++
++cleanup:
++ remove_proc_entry("ipt_dstlimit", proc_net);
++cleanup_free_slab:
++ kmem_cache_destroy(dstlimit_cachep);
++cleanup_unreg_match:
++ ipt_unregister_match(&ipt_dstlimit);
++cleanup_nothing:
++ return ret;
++
++}
++
++static int __init init(void)
++{
++ return init_or_fini(0);
++}
++
++static void __exit fini(void)
++{
++ init_or_fini(1);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_fuzzy.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_fuzzy.c 2004-06-08 10:31:37.000000000 +0200
+@@ -0,0 +1,185 @@
++/*
++ * This module implements a simple TSK FLC
++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
++ * to limit , in an adaptive and flexible way , the packet rate crossing
++ * a given stream . It serves as an initial and very simple (but effective)
++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
++ * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
++ * into our code in a precise , adaptive and efficient manner.
++ * The goal is very similar to that of "limit" match , but using techniques of
++ * Fuzzy Control , that allow us to shape the transfer functions precisely ,
++ * avoiding over and undershoots - and stuff like that .
++ *
++ *
++ * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
++ * 2002-08-17 : Changed to eliminate floating point operations .
++ * 2002-08-23 : Coding style changes .
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/random.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_fuzzy.h>
++
++/*
++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
++ Expressed in percentage
++*/
++
++#define PAR_LOW 1/100
++#define PAR_HIGH 1
++
++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
++
++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
++MODULE_LICENSE("GPL");
++
++static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++ if (tx >= maxi)
++ return 100;
++
++ if (tx <= mini)
++ return 0;
++
++ return ( (100*(tx-mini)) / (maxi-mini) );
++}
++
++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++ if (tx <= mini)
++ return 100;
++
++ if (tx >= maxi)
++ return 0;
++
++ return ( (100*( maxi - tx )) / ( maxi - mini ) );
++}
++
++static int
++ipt_fuzzy_match(const struct sk_buff *pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ /* From userspace */
++
++ struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
++
++ u_int8_t random_number;
++ unsigned long amount;
++ u_int8_t howhigh, howlow;
++
++
++ spin_lock_bh(&fuzzy_lock); /* Rise the lock */
++
++ info->bytes_total += pskb->len;
++ info->packets_total++;
++
++ info->present_time = jiffies;
++
++ if (info->present_time >= info->previous_time)
++ amount = info->present_time - info->previous_time;
++ else {
++ /* There was a transition : I choose to re-sample
++ and keep the old acceptance rate...
++ */
++
++ amount = 0;
++ info->previous_time = info->present_time;
++ info->bytes_total = info->packets_total = 0;
++ };
++
++ if (amount > HZ/10) /* More than 100 ms elapsed ... */
++ {
++
++ info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \
++ / amount );
++
++ info->previous_time = info->present_time;
++ info->bytes_total = info->packets_total = 0;
++
++ howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
++ howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
++
++ info->acceptance_rate = (u_int8_t) \
++ (howhigh*PAR_LOW + PAR_HIGH*howlow);
++
++ /* In fact , the above defuzzification would require a denominator
++ proportional to (howhigh+howlow) but , in this particular case ,
++ that expression is constant .
++ An imediate consequence is that it isn't necessary to call
++ both mf_high and mf_low - but to keep things understandable ,
++ I did so . */
++
++ }
++
++ spin_unlock_bh(&fuzzy_lock); /* Release the lock */
++
++
++ if ( info->acceptance_rate < 100 )
++ {
++ get_random_bytes((void *)(&random_number), 1);
++
++ /* If within the acceptance , it can pass => don't match */
++ if (random_number <= (255 * info->acceptance_rate) / 100)
++ return 0;
++ else
++ return 1; /* It can't pass ( It matches ) */
++ } ;
++
++ return 0; /* acceptance_rate == 100 % => Everything passes ... */
++
++}
++
++static int
++ipt_fuzzy_checkentry(const char *tablename,
++ const struct ipt_ip *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++
++ const struct ipt_fuzzy_info *info = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
++ printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
++ IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
++ return 0;
++ }
++
++ if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
++ || (info->minimum_rate >= info->maximum_rate )) {
++ printk("ipt_fuzzy: BAD limits , please verify !!!\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match ipt_fuzzy_reg = {
++ .name = "fuzzy",
++ .match = ipt_fuzzy_match,
++ .checkentry = ipt_fuzzy_checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&ipt_fuzzy_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipt_fuzzy_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_helper.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_helper.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_helper.c 2004-06-07 21:14:55.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_helper.c 2004-06-08 10:42:23.000000000 +0200
+@@ -41,17 +41,17 @@
+ struct ip_conntrack_expect *exp;
+ struct ip_conntrack *ct;
+ enum ip_conntrack_info ctinfo;
+- int ret = 0;
++ int ret = info->invert;
+
+ ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+ if (!ct) {
+ DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
+- return 0;
++ return ret;
+ }
+
+ if (!ct->master) {
+ DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
+- return 0;
++ return ret;
+ }
+
+ exp = ct->master;
+@@ -71,8 +71,11 @@
+ DEBUGP("master's name = %s , info->name = %s\n",
+ exp->expectant->helper->name, info->name);
+
+- ret = !strncmp(exp->expectant->helper->name, info->name,
+- strlen(exp->expectant->helper->name)) ^ info->invert;
++ if (info->name[0] == '\0')
++ ret ^= 1;
++ else
++ ret ^= !strncmp(exp->expectant->helper->name, info->name,
++ strlen(exp->expectant->helper->name));
+ out_unlock:
+ READ_UNLOCK(&ip_conntrack_lock);
+ return ret;
+@@ -92,10 +95,6 @@
+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
+ return 0;
+
+- /* verify that we actually should match anything */
+- if ( strlen(info->name) == 0 )
+- return 0;
+-
+ return 1;
+ }
+
+@@ -108,7 +107,6 @@
+
+ static int __init init(void)
+ {
+- need_ip_conntrack();
+ return ipt_register_match(&helper_match);
+ }
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_ipv4options.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_ipv4options.c 2004-06-08 10:31:39.000000000 +0200
+@@ -0,0 +1,172 @@
++/*
++ This is a module which is used to match ipv4 options.
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from:
++ ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++ 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++ 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
++ 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
++ 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
++ 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_ipv4options.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
++ const struct iphdr *iph = skb->nh.iph;
++ const struct ip_options *opt;
++
++ if (iph->ihl * 4 == sizeof(struct iphdr)) {
++ /* No options, so we match only the "DONTs" and the "IGNOREs" */
++
++ if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
++ return 0;
++ return 1;
++ }
++ else {
++ if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
++ /* there are options, and we don't need to care which one */
++ return 1;
++ else {
++ if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
++ /* there are options but we don't want any ! */
++ return 0;
++ }
++ }
++
++ opt = &(IPCB(skb)->opt);
++
++ /* source routing */
++ if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
++ if (!((opt->srr) & (opt->is_strictroute)))
++ return 0;
++ }
++ else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
++ if (!((opt->srr) & (!opt->is_strictroute)))
++ return 0;
++ }
++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
++ if (opt->srr)
++ return 0;
++ }
++ /* record route */
++ if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
++ if (!opt->rr)
++ return 0;
++ }
++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
++ if (opt->rr)
++ return 0;
++ }
++ /* timestamp */
++ if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
++ if (!opt->ts)
++ return 0;
++ }
++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
++ if (opt->ts)
++ return 0;
++ }
++ /* router-alert option */
++ if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
++ if (!opt->router_alert)
++ return 0;
++ }
++ else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
++ if (opt->router_alert)
++ return 0;
++ }
++
++ /* we match ! */
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
++ /* Check the size */
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
++ return 0;
++ /* Now check the coherence of the data ... */
++ if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
++ (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
++ return 0; /* opposites */
++ if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
++ (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
++ return 0; /* opposites */
++ if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
++ return 0; /* cannot match in the same time loose and strict source routing */
++ if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
++ ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
++ return 0; /* opposites */
++ if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
++ return 0; /* opposites */
++ if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
++ return 0; /* opposites */
++ if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
++ ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
++ return 0; /* opposites */
++
++ /* everything looks ok. */
++ return 1;
++}
++
++static struct ipt_match ipv4options_match = {
++ .name = "ipv4options",
++ .match = match,
++ .checkentry = checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&ipv4options_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipv4options_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_mport.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_mport.c 2004-06-08 10:31:40.000000000 +0200
+@@ -0,0 +1,116 @@
++/* Kernel module to match one of a list of TCP/UDP ports: ports are in
++ the same place so we can treat them as equal. */
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/udp.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ipt_mport.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_LICENSE("GPL");
++
++#if 0
++#define duprintf(format, args...) printk(format , ## args)
++#else
++#define duprintf(format, args...)
++#endif
++
++/* Returns 1 if the port is matched by the test, 0 otherwise. */
++static inline int
++ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
++{
++ unsigned int i;
++ unsigned int m;
++ u_int16_t pflags = minfo->pflags;
++ for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
++ u_int16_t s, e;
++
++ if (pflags & m
++ && minfo->ports[i] == 65535)
++ return 0;
++
++ s = minfo->ports[i];
++
++ if (pflags & m) {
++ e = minfo->ports[++i];
++ m <<= 1;
++ } else
++ e = s;
++
++ if (minfo->flags & IPT_MPORT_SOURCE
++ && src >= s && src <= e)
++ return 1;
++
++ if (minfo->flags & IPT_MPORT_DESTINATION
++ && dst >= s && dst <= e)
++ return 1;
++ }
++
++ return 0;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ u16 ports[2];
++ const struct ipt_mport *minfo = matchinfo;
++
++ if (offset)
++ return 0;
++
++ /* Must be big enough to read ports (both UDP and TCP have
++ them at the start). */
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
++ /* We've been asked to examine this packet, and we
++ can't. Hence, no choice but to drop. */
++ duprintf("ipt_multiport:"
++ " Dropping evil offset=0 tinygram.\n");
++ *hotdrop = 1;
++ return 0;
++ }
++
++ return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
++}
++
++/* Called when user tries to insert an entry of this type. */
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
++ return 0;
++
++ /* Must specify proto == TCP/UDP, no unknown flags or bad count */
++ return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
++ && !(ip->invflags & IPT_INV_PROTO)
++ && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
++}
++
++static struct ipt_match mport_match = {
++ .name = "mport",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&mport_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&mport_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_nth.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_nth.c 2004-06-08 10:31:42.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ This is a module which is used for match support for every Nth packet
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from:
++ ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++ 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++ 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
++ * added support for multiple counters
++ * added support for matching on individual packets
++ in the counter cycle
++ 2004-02-19 Harald Welte <laforge@netfilter.org>
++ * port to 2.6.x
++
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_nth.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
++
++/*
++ * State information.
++ */
++struct state {
++ spinlock_t lock;
++ u_int16_t number;
++};
++
++static struct state states[IPT_NTH_NUM_COUNTERS];
++
++static int
++ipt_nth_match(const struct sk_buff *pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ /* Parameters from userspace */
++ const struct ipt_nth_info *info = matchinfo;
++ unsigned counter = info->counter;
++ if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
++ {
++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
++ return 0;
++ };
++
++ spin_lock(&states[counter].lock);
++
++ /* Are we matching every nth packet?*/
++ if (info->packet == 0xFF)
++ {
++ /* We're matching every nth packet and only every nth packet*/
++ /* Do we match or invert match? */
++ if (info->not == 0)
++ {
++ if (states[counter].number == 0)
++ {
++ ++states[counter].number;
++ goto match;
++ }
++ if (states[counter].number >= info->every)
++ states[counter].number = 0; /* reset the counter */
++ else
++ ++states[counter].number;
++ goto dontmatch;
++ }
++ else
++ {
++ if (states[counter].number == 0)
++ {
++ ++states[counter].number;
++ goto dontmatch;
++ }
++ if (states[counter].number >= info->every)
++ states[counter].number = 0;
++ else
++ ++states[counter].number;
++ goto match;
++ }
++ }
++ else
++ {
++ /* We're using the --packet, so there must be a rule for every value */
++ if (states[counter].number == info->packet)
++ {
++ /* only increment the counter when a match happens */
++ if (states[counter].number >= info->every)
++ states[counter].number = 0; /* reset the counter */
++ else
++ ++states[counter].number;
++ goto match;
++ }
++ else
++ goto dontmatch;
++ }
++
++ dontmatch:
++ /* don't match */
++ spin_unlock(&states[counter].lock);
++ return 0;
++
++ match:
++ spin_unlock(&states[counter].lock);
++ return 1;
++}
++
++static int
++ipt_nth_checkentry(const char *tablename,
++ const struct ipt_ip *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Parameters from userspace */
++ const struct ipt_nth_info *info = matchinfo;
++ unsigned counter = info->counter;
++ if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
++ {
++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
++ return 0;
++ };
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
++ printk("nth: matchsize %u != %u\n", matchsize,
++ IPT_ALIGN(sizeof(struct ipt_nth_info)));
++ return 0;
++ }
++
++ states[counter].number = info->startat;
++
++ return 1;
++}
++
++static struct ipt_match ipt_nth_reg = {
++ .name = "nth",
++ .match = ipt_nth_match,
++ .checkentry = ipt_nth_checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ unsigned counter;
++
++ memset(&states, 0, sizeof(states));
++ for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++)
++ spin_lock_init(&(states[counter].lock));
++
++ return ipt_register_match(&ipt_nth_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipt_nth_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_osf.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_osf.c 2004-06-08 10:31:44.000000000 +0200
+@@ -0,0 +1,865 @@
++/*
++ * ipt_osf.c
++ *
++ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*
++ * OS fingerprint matching module.
++ * It simply compares various parameters from SYN packet with
++ * some hardcoded ones.
++ *
++ * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
++ * for his p0f.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/string.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <linux/ip.h>
++#include <linux/proc_fs.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/ctype.h>
++#include <linux/list.h>
++#include <linux/if.h>
++
++#include <net/sock.h>
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#include <linux/netfilter_ipv4/ipt_osf.h>
++
++#define OSF_DEBUG
++
++#ifdef OSF_DEBUG
++#define log(x...) printk(KERN_INFO "ipt_osf: " x)
++#define loga(x...) printk(x)
++#else
++#define log(x...) do {} while(0)
++#define loga(x...) do {} while(0)
++#endif
++
++#define FMATCH_WRONG 0
++#define FMATCH_OK 1
++#define FMATCH_OPT_WRONG 2
++
++#define OPTDEL ','
++#define OSFPDEL ':'
++#define MAXOPTSTRLEN 128
++#define OSFFLUSH "FLUSH"
++
++static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
++static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head finger_list;
++static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
++ const void *, int,
++ const void *, u_int16_t,
++ int *);
++static int checkentry(const char *, const struct ipt_ip *, void *,
++ unsigned int, unsigned int);
++
++static unsigned long seq, ipt_osf_groups = 1;
++static struct sock *nts;
++
++static struct ipt_match osf_match =
++{
++ { NULL, NULL },
++ "osf",
++ &match,
++ &checkentry,
++ NULL,
++ THIS_MODULE
++};
++
++static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
++{
++ unsigned int size;
++ struct sk_buff *skb;
++ struct ipt_osf_nlmsg *data;
++ struct nlmsghdr *nlh;
++
++ size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
++
++ skb = alloc_skb(size, GFP_ATOMIC);
++ if (!skb)
++ {
++ log("skb_alloc() failed.\n");
++ return;
++ }
++
++ nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
++
++ data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
++
++ memcpy(&data->f, f, sizeof(struct osf_finger));
++ memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
++ memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
++
++ NETLINK_CB(skb).dst_groups = ipt_osf_groups;
++ netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
++
++nlmsg_failure:
++ return;
++}
++
++static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
++{
++ struct iphdr *ip = skb->nh.iph;
++
++ if (flags & IPT_OSF_SMART)
++ {
++ struct in_device *in_dev = in_dev_get(skb->dev);
++
++ for_ifa(in_dev)
++ {
++ if (inet_ifa_match(ip->saddr, ifa))
++ {
++ in_dev_put(in_dev);
++ return (ip->ttl == f_ttl);
++ }
++ }
++ endfor_ifa(in_dev);
++
++ in_dev_put(in_dev);
++ return (ip->ttl <= f_ttl);
++ }
++ else
++ return (ip->ttl == f_ttl);
++}
++
++static int
++match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
++ const void *matchinfo, int offset,
++ const void *hdr, u_int16_t datalen,
++ int *hotdrop)
++{
++ struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
++ struct iphdr *ip = skb->nh.iph;
++ struct tcphdr *tcp;
++ int fmatch = FMATCH_WRONG, fcount = 0;
++ unsigned long totlen, optsize = 0, window;
++ unsigned char df, *optp = NULL, *_optp = NULL;
++ char check_WSS = 0;
++ struct list_head *ent;
++ struct osf_finger *f;
++
++ if (!ip || !info)
++ return 0;
++
++ tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
++
++ if (!tcp->syn)
++ return 0;
++
++ totlen = ntohs(ip->tot_len);
++ df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
++ window = ntohs(tcp->window);
++
++ if (tcp->doff*4 > sizeof(struct tcphdr))
++ {
++ _optp = optp = (char *)(tcp+1);
++ optsize = tcp->doff*4 - sizeof(struct tcphdr);
++ }
++
++
++ /* Actually we can create hash/table of all genres and search
++ * only in appropriate part, but here is initial variant,
++ * so will use slow path.
++ */
++ read_lock(&osf_lock);
++ list_for_each(ent, &finger_list)
++ {
++ f = list_entry(ent, struct osf_finger, flist);
++
++ if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre))
++ continue;
++
++ optp = _optp;
++ fmatch = FMATCH_WRONG;
++
++ if (totlen == f->ss && df == f->df &&
++ smart_dec(skb, info->flags, f->ttl))
++ {
++ unsigned long foptsize;
++ int optnum;
++ unsigned short mss = 0;
++
++ check_WSS = 0;
++
++ switch (f->wss.wc)
++ {
++ case 0: check_WSS = 0; break;
++ case 'S': check_WSS = 1; break;
++ case 'T': check_WSS = 2; break;
++ case '%': check_WSS = 3; break;
++ default: log("Wrong fingerprint wss.wc=%d, %s - %s\n",
++ f->wss.wc, f->genre, f->details);
++ check_WSS = 4;
++ break;
++ }
++ if (check_WSS == 4)
++ continue;
++
++ /* Check options */
++
++ foptsize = 0;
++ for (optnum=0; optnum<f->opt_num; ++optnum)
++ foptsize += f->opt[optnum].length;
++
++
++ if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
++ continue;
++
++ if (!optp)
++ {
++ fmatch = FMATCH_OK;
++ loga("\tYEP : matching without options.\n");
++ if ((info->flags & IPT_OSF_LOG) &&
++ info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
++ break;
++ else
++ continue;
++ }
++
++
++ for (optnum=0; optnum<f->opt_num; ++optnum)
++ {
++ if (f->opt[optnum].kind == (*optp))
++ {
++ unsigned char len = f->opt[optnum].length;
++ unsigned char *optend = optp + len;
++ int loop_cont = 0;
++
++ fmatch = FMATCH_OK;
++
++
++ switch (*optp)
++ {
++ case OSFOPT_MSS:
++ mss = ntohs(*(unsigned short *)(optp+2));
++ break;
++ case OSFOPT_TS:
++ loop_cont = 1;
++ break;
++ }
++
++ if (loop_cont)
++ {
++ optp = optend;
++ continue;
++ }
++
++ if (len != 1)
++ {
++ /* Skip kind and length fields*/
++ optp += 2;
++
++ if (f->opt[optnum].wc.val != 0)
++ {
++ unsigned long tmp = 0;
++
++ /* Hmmm... It looks a bit ugly. :) */
++ memcpy(&tmp, optp,
++ (len > sizeof(unsigned long)?
++ sizeof(unsigned long):len));
++ /* 2 + 2: optlen(2 bytes) +
++ * kind(1 byte) + length(1 byte) */
++ if (len == 4)
++ tmp = ntohs(tmp);
++ else
++ tmp = ntohl(tmp);
++
++ if (f->opt[optnum].wc.wc == '%')
++ {
++ if ((tmp % f->opt[optnum].wc.val) != 0)
++ fmatch = FMATCH_OPT_WRONG;
++ }
++ else if (tmp != f->opt[optnum].wc.val)
++ fmatch = FMATCH_OPT_WRONG;
++ }
++ }
++
++ optp = optend;
++ }
++ else
++ fmatch = FMATCH_OPT_WRONG;
++
++ if (fmatch != FMATCH_OK)
++ break;
++ }
++
++ if (fmatch != FMATCH_OPT_WRONG)
++ {
++ fmatch = FMATCH_WRONG;
++
++ switch (check_WSS)
++ {
++ case 0:
++ if (f->wss.val == 0 || window == f->wss.val)
++ fmatch = FMATCH_OK;
++ break;
++ case 1: /* MSS */
++/* Lurked in OpenBSD */
++#define SMART_MSS 1460
++ if (window == f->wss.val*mss ||
++ window == f->wss.val*SMART_MSS)
++ fmatch = FMATCH_OK;
++ break;
++ case 2: /* MTU */
++ if (window == f->wss.val*(mss+40) ||
++ window == f->wss.val*(SMART_MSS+40))
++ fmatch = FMATCH_OK;
++ break;
++ case 3: /* MOD */
++ if ((window % f->wss.val) == 0)
++ fmatch = FMATCH_OK;
++ break;
++ }
++ }
++
++
++ if (fmatch == FMATCH_OK)
++ {
++ fcount++;
++ log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n",
++ f->genre, f->version,
++ f->subtype, f->details,
++ NIPQUAD(ip->saddr), ntohs(tcp->source),
++ NIPQUAD(ip->daddr), ntohs(tcp->dest),
++ f->ttl - ip->ttl);
++ if (info->flags & IPT_OSF_NETLINK)
++ {
++ spin_lock_bh(&ipt_osf_netlink_lock);
++ ipt_osf_nlsend(f, skb);
++ spin_unlock_bh(&ipt_osf_netlink_lock);
++ }
++ if ((info->flags & IPT_OSF_LOG) &&
++ info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
++ break;
++ }
++ }
++ }
++ if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
++ {
++ unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
++ unsigned int i, optsize;
++ struct osf_finger fg;
++
++ memset(&fg, 0, sizeof(fg));
++
++ if ((info->flags & IPT_OSF_LOG))
++ log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
++ if (optp)
++ {
++ optsize = tcp->doff * 4 - sizeof(struct tcphdr);
++ if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
++ opt, optsize) < 0)
++ {
++ if (info->flags & IPT_OSF_LOG)
++ loga("TRUNCATED");
++ if (info->flags & IPT_OSF_NETLINK)
++ strcpy(fg.details, "TRUNCATED");
++ }
++ else
++ {
++ for (i = 0; i < optsize; i++)
++ {
++ if (info->flags & IPT_OSF_LOG)
++ loga("%02X", opt[i]);
++ }
++ if (info->flags & IPT_OSF_NETLINK)
++ memcpy(fg.details, opt, MAXDETLEN);
++ }
++ }
++ if ((info->flags & IPT_OSF_LOG))
++ loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
++ NIPQUAD(ip->saddr), ntohs(tcp->source),
++ NIPQUAD(ip->daddr), ntohs(tcp->dest));
++
++ if (info->flags & IPT_OSF_NETLINK)
++ {
++ fg.wss.val = window;
++ fg.ttl = ip->ttl;
++ fg.df = df;
++ fg.ss = totlen;
++ strncpy(fg.genre, "Unknown", MAXGENRELEN);
++
++ spin_lock_bh(&ipt_osf_netlink_lock);
++ ipt_osf_nlsend(&fg, skb);
++ spin_unlock_bh(&ipt_osf_netlink_lock);
++ }
++ }
++
++ read_unlock(&osf_lock);
++
++ return (fmatch == FMATCH_OK)?1:0;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
++ return 0;
++ if (ip->proto != IPPROTO_TCP)
++ return 0;
++
++ return 1;
++}
++
++static char * osf_strchr(char *ptr, char c)
++{
++ char *tmp;
++
++ tmp = strchr(ptr, c);
++
++ while (tmp && tmp+1 && isspace(*(tmp+1)))
++ tmp++;
++
++ return tmp;
++}
++
++static struct osf_finger * finger_alloc(void)
++{
++ struct osf_finger *f;
++
++ f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
++ if (f)
++ memset(f, 0, sizeof(struct osf_finger));
++
++ return f;
++}
++
++static void finger_free(struct osf_finger *f)
++{
++ memset(f, 0, sizeof(struct osf_finger));
++ kfree(f);
++}
++
++
++static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
++{
++ int i, op;
++ char *ptr, wc;
++ unsigned long val;
++
++ ptr = &obuf[0];
++ i = 0;
++ while (ptr != NULL && i < olen)
++ {
++ val = 0;
++ op = 0;
++ wc = 0;
++ switch (obuf[i])
++ {
++ case 'N':
++ op = OSFOPT_NOP;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ *ptr = '\0';
++ ptr++;
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ case 'S':
++ op = OSFOPT_SACKP;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ *ptr = '\0';
++ ptr++;
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ case 'T':
++ op = OSFOPT_TS;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ *ptr = '\0';
++ ptr++;
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ case 'W':
++ op = OSFOPT_WSO;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ switch (obuf[i+1])
++ {
++ case '%': wc = '%'; break;
++ case 'S': wc = 'S'; break;
++ case 'T': wc = 'T'; break;
++ default: wc = 0; break;
++ }
++
++ *ptr = '\0';
++ ptr++;
++ if (wc)
++ val = simple_strtoul(&obuf[i+2], NULL, 10);
++ else
++ val = simple_strtoul(&obuf[i+1], NULL, 10);
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ case 'M':
++ op = OSFOPT_MSS;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ if (obuf[i+1] == '%')
++ wc = '%';
++ *ptr = '\0';
++ ptr++;
++ if (wc)
++ val = simple_strtoul(&obuf[i+2], NULL, 10);
++ else
++ val = simple_strtoul(&obuf[i+1], NULL, 10);
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ case 'E':
++ op = OSFOPT_EOL;
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ *ptr = '\0';
++ ptr++;
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ default:
++ ptr = osf_strchr(&obuf[i], OPTDEL);
++ if (ptr)
++ {
++ ptr++;
++ i += (int)(ptr-&obuf[i]);
++
++ }
++ else
++ i++;
++ break;
++ }
++
++ opt[*optnum].kind = IANA_opts[op].kind;
++ opt[*optnum].length = IANA_opts[op].length;
++ opt[*optnum].wc.wc = wc;
++ opt[*optnum].wc.val = val;
++
++ (*optnum)++;
++ }
++}
++
++static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
++{
++ struct list_head *ent;
++ struct osf_finger *f = NULL;
++ int i;
++
++ *eof = 1;
++ count = 0;
++
++ read_lock_bh(&osf_lock);
++ list_for_each(ent, &finger_list)
++ {
++ f = list_entry(ent, struct osf_finger, flist);
++
++ log("%s [%s]", f->genre, f->details);
++
++ count += sprintf(buf+count, "%s - %s[%s] : %s",
++ f->genre, f->version,
++ f->subtype, f->details);
++
++ if (f->opt_num)
++ {
++ loga(" OPT: ");
++ //count += sprintf(buf+count, " OPT: ");
++ for (i=0; i<f->opt_num; ++i)
++ {
++ //count += sprintf(buf+count, "%d.%c%lu; ",
++ // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
++ loga("%d.%c%lu; ",
++ f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
++ }
++ }
++ loga("\n");
++ count += sprintf(buf+count, "\n");
++ }
++ read_unlock_bh(&osf_lock);
++
++ return count;
++}
++
++static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++ int cnt;
++ unsigned long i;
++ char obuf[MAXOPTSTRLEN];
++ struct osf_finger *finger;
++ struct list_head *ent, *n;
++
++ char *pbeg, *pend;
++
++ if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
++ {
++ int i = 0;
++ write_lock_bh(&osf_lock);
++ list_for_each_safe(ent, n, &finger_list)
++ {
++ i++;
++ finger = list_entry(ent, struct osf_finger, flist);
++ list_del(&finger->flist);
++ finger_free(finger);
++ }
++ write_unlock_bh(&osf_lock);
++
++ log("Flushed %d entries.\n", i);
++
++ return count;
++ }
++
++
++ cnt = 0;
++ for (i=0; i<count && buffer[i] != '\0'; ++i)
++ if (buffer[i] == ':')
++ cnt++;
++
++ if (cnt != 8 || i != count)
++ {
++ log("Wrong input line cnt=%d[8], len=%lu[%lu]\n",
++ cnt, i, count);
++ return count;
++ }
++
++ memset(obuf, 0, sizeof(obuf));
++
++ finger = finger_alloc();
++ if (!finger)
++ {
++ log("Failed to allocate new fingerprint entry.\n");
++ return -ENOMEM;
++ }
++
++ pbeg = (char *)buffer;
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ if (pbeg[0] == 'S')
++ {
++ finger->wss.wc = 'S';
++ if (pbeg[1] == '%')
++ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
++ else if (pbeg[1] == '*')
++ finger->wss.val = 0;
++ else
++ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++ }
++ else if (pbeg[0] == 'T')
++ {
++ finger->wss.wc = 'T';
++ if (pbeg[1] == '%')
++ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
++ else if (pbeg[1] == '*')
++ finger->wss.val = 0;
++ else
++ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++ }
++ else if (pbeg[0] == '%')
++ {
++ finger->wss.wc = '%';
++ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
++ }
++ else if (isdigit(pbeg[0]))
++ {
++ finger->wss.wc = 0;
++ finger->wss.val = simple_strtoul(pbeg, NULL, 10);
++ }
++
++ pbeg = pend+1;
++ }
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ finger->ttl = simple_strtoul(pbeg, NULL, 10);
++ pbeg = pend+1;
++ }
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ finger->df = simple_strtoul(pbeg, NULL, 10);
++ pbeg = pend+1;
++ }
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ finger->ss = simple_strtoul(pbeg, NULL, 10);
++ pbeg = pend+1;
++ }
++
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
++ pbeg = pend+1;
++ }
++
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ if (pbeg[0] == '@' || pbeg[0] == '*')
++ cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
++ else
++ cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
++ pbeg = pend+1;
++ }
++
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
++ pbeg = pend+1;
++ }
++
++ pend = osf_strchr(pbeg, OSFPDEL);
++ if (pend)
++ {
++ *pend = '\0';
++ cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
++ pbeg = pend+1;
++ }
++
++ cnt = snprintf(finger->details,
++ ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1),
++ "%s", pbeg);
++
++ log("%s - %s[%s] : %s\n",
++ finger->genre, finger->version,
++ finger->subtype, finger->details);
++
++ osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
++
++
++ write_lock_bh(&osf_lock);
++ list_add_tail(&finger->flist, &finger_list);
++ write_unlock_bh(&osf_lock);
++
++ return count;
++}
++
++static int __init osf_init(void)
++{
++ int err;
++ struct proc_dir_entry *p;
++
++ log("Startng OS fingerprint matching module.\n");
++
++ INIT_LIST_HEAD(&finger_list);
++
++ err = ipt_register_match(&osf_match);
++ if (err)
++ {
++ log("Failed to register OS fingerprint matching module.\n");
++ return -ENXIO;
++ }
++
++ p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
++ if (!p)
++ {
++ ipt_unregister_match(&osf_match);
++ return -ENXIO;
++ }
++
++ p->write_proc = osf_proc_write;
++ p->read_proc = osf_proc_read;
++
++ nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
++ if (!nts)
++ {
++ log("netlink_kernel_create() failed\n");
++ remove_proc_entry("sys/net/ipv4/osf", NULL);
++ ipt_unregister_match(&osf_match);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void __exit osf_fini(void)
++{
++ struct list_head *ent, *n;
++ struct osf_finger *f;
++
++ remove_proc_entry("sys/net/ipv4/osf", NULL);
++ ipt_unregister_match(&osf_match);
++ if (nts && nts->sk_socket)
++ sock_release(nts->sk_socket);
++
++ list_for_each_safe(ent, n, &finger_list)
++ {
++ f = list_entry(ent, struct osf_finger, flist);
++ list_del(&f->flist);
++ finger_free(f);
++ }
++
++ log("OS fingerprint matching module finished.\n");
++}
++
++module_init(osf_init);
++module_exit(osf_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
++MODULE_DESCRIPTION("Passive OS fingerprint matching.");
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_owner.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_owner.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_owner.c 2004-06-07 21:15:11.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_owner.c 2004-06-08 10:39:56.000000000 +0200
+@@ -6,12 +6,19 @@
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
++ *
++ * 03/26/2003 Patrick McHardy <kaber@trash.net> : LOCAL_IN support
+ */
+
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+ #include <linux/file.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
+ #include <net/sock.h>
++#include <net/tcp.h>
++#include <net/udp.h>
+
+ #include <linux/netfilter_ipv4/ipt_owner.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+@@ -21,7 +28,7 @@
+ MODULE_DESCRIPTION("iptables owner match");
+
+ static int
+-match_comm(const struct sk_buff *skb, const char *comm)
++match_comm(const struct sock *sk, const char *comm)
+ {
+ struct task_struct *g, *p;
+ struct files_struct *files;
+@@ -38,7 +45,7 @@
+ spin_lock(&files->file_lock);
+ for (i=0; i < files->max_fds; i++) {
+ if (fcheck_files(files, i) ==
+- skb->sk->sk_socket->file) {
++ sk->sk_socket->file) {
+ spin_unlock(&files->file_lock);
+ task_unlock(p);
+ read_unlock(&tasklist_lock);
+@@ -54,7 +61,7 @@
+ }
+
+ static int
+-match_pid(const struct sk_buff *skb, pid_t pid)
++match_pid(const struct sock *sk, pid_t pid)
+ {
+ struct task_struct *p;
+ struct files_struct *files;
+@@ -70,7 +77,7 @@
+ spin_lock(&files->file_lock);
+ for (i=0; i < files->max_fds; i++) {
+ if (fcheck_files(files, i) ==
+- skb->sk->sk_socket->file) {
++ sk->sk_socket->file) {
+ spin_unlock(&files->file_lock);
+ task_unlock(p);
+ read_unlock(&tasklist_lock);
+@@ -86,10 +93,10 @@
+ }
+
+ static int
+-match_sid(const struct sk_buff *skb, pid_t sid)
++match_sid(const struct sock *sk, pid_t sid)
+ {
+ struct task_struct *g, *p;
+- struct file *file = skb->sk->sk_socket->file;
++ struct file *file = sk->sk_socket->file;
+ int i, found=0;
+
+ read_lock(&tasklist_lock);
+@@ -129,41 +136,71 @@
+ int *hotdrop)
+ {
+ const struct ipt_owner_info *info = matchinfo;
++ struct iphdr *iph = skb->nh.iph;
++ struct sock *sk = NULL;
++ int ret = 0;
++
++ if (out) {
++ sk = skb->sk;
++ } else {
++ if (iph->protocol == IPPROTO_TCP) {
++ struct tcphdr *tcph =
++ (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
++ sk = tcp_v4_lookup(iph->saddr, tcph->source,
++ iph->daddr, tcph->dest,
++ skb->dev->ifindex);
++ if (sk && sk->sk_state == TCP_TIME_WAIT) {
++ tcp_tw_put((struct tcp_tw_bucket *)sk);
++ return ret;
++ }
++ } else if (iph->protocol == IPPROTO_UDP) {
++ struct udphdr *udph =
++ (struct udphdr *)((u_int32_t *)iph + iph->ihl);
++ sk = udp_v4_lookup(iph->saddr, udph->source, iph->daddr,
++ udph->dest, skb->dev->ifindex);
++ }
++ }
+
+- if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
+- return 0;
++ if (!sk || !sk->sk_socket || !sk->sk_socket->file)
++ goto out;
+
+ if(info->match & IPT_OWNER_UID) {
+- if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
++ if ((sk->sk_socket->file->f_uid != info->uid) ^
+ !!(info->invert & IPT_OWNER_UID))
+- return 0;
++ goto out;
+ }
+
+ if(info->match & IPT_OWNER_GID) {
+- if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
++ if ((sk->sk_socket->file->f_gid != info->gid) ^
+ !!(info->invert & IPT_OWNER_GID))
+- return 0;
++ goto out;
+ }
+
+ if(info->match & IPT_OWNER_PID) {
+- if (!match_pid(skb, info->pid) ^
++ if (!match_pid(sk, info->pid) ^
+ !!(info->invert & IPT_OWNER_PID))
+- return 0;
++ goto out;
+ }
+
+ if(info->match & IPT_OWNER_SID) {
+- if (!match_sid(skb, info->sid) ^
++ if (!match_sid(sk, info->sid) ^
+ !!(info->invert & IPT_OWNER_SID))
+- return 0;
++ goto out;
+ }
+
+ if(info->match & IPT_OWNER_COMM) {
+- if (!match_comm(skb, info->comm) ^
++ if (!match_comm(sk, info->comm) ^
+ !!(info->invert & IPT_OWNER_COMM))
+- return 0;
++ goto out;
+ }
+
+- return 1;
++ ret = 1;
++
++out:
++ if (in && sk)
++ sock_put(sk);
++
++ return ret;
+ }
+
+ static int
+@@ -173,11 +210,19 @@
+ unsigned int matchsize,
+ unsigned int hook_mask)
+ {
+- if (hook_mask
+- & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) {
+- printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
+- return 0;
+- }
++ if (hook_mask
++ & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING) |
++ (1 << NF_IP_LOCAL_IN))) {
++ printk("ipt_owner: only valid for LOCAL_IN, LOCAL_OUT "
++ "or POST_ROUTING.\n");
++ return 0;
++ }
++
++ if ((hook_mask & (1 << NF_IP_LOCAL_IN))
++ && ip->proto != IPPROTO_TCP && ip->proto != IPPROTO_UDP) {
++ printk("ipt_owner: only TCP or UDP can be used in LOCAL_IN\n");
++ return 0;
++ }
+
+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) {
+ printk("Matchsize %u != %Zu\n", matchsize,
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_policy.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_policy.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_policy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_policy.c 2004-06-08 10:42:36.000000000 +0200
+@@ -0,0 +1,176 @@
++/* IP tables module for matching IPsec policy
++ *
++ * Copyright (c) 2004 Patrick McHardy, <kaber@trash.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <net/xfrm.h>
++
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ipt_policy.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
++MODULE_DESCRIPTION("IPtables IPsec policy matching module");
++MODULE_LICENSE("GPL");
++
++
++static inline int
++match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
++{
++#define MISMATCH(x,y) (e->match.x && ((e->x != (y)) ^ e->invert.x))
++
++ if (MISMATCH(saddr, x->props.saddr.a4 & e->smask) ||
++ MISMATCH(daddr, x->id.daddr.a4 & e->dmask) ||
++ MISMATCH(proto, x->id.proto) ||
++ MISMATCH(mode, x->props.mode) ||
++ MISMATCH(spi, x->id.spi) ||
++ MISMATCH(reqid, x->props.reqid))
++ return 0;
++ return 1;
++}
++
++static int
++match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info)
++{
++ const struct ipt_policy_elem *e;
++ struct sec_path *sp = skb->sp;
++ int strict = info->flags & POLICY_MATCH_STRICT;
++ int i, pos;
++
++ if (sp == NULL)
++ return -1;
++ if (strict && info->len != sp->len)
++ return 0;
++
++ for (i = sp->len - 1; i >= 0; i--) {
++ pos = strict ? i - sp->len + 1 : 0;
++ if (pos >= info->len)
++ return 0;
++ e = &info->pol[pos];
++
++ if (match_xfrm_state(sp->x[i].xvec, e)) {
++ if (!strict)
++ return 1;
++ } else if (strict)
++ return 0;
++ }
++
++ return strict ? 1 : 0;
++}
++
++static int
++match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
++{
++ const struct ipt_policy_elem *e;
++ struct dst_entry *dst = skb->dst;
++ int strict = info->flags & POLICY_MATCH_STRICT;
++ int i, pos;
++
++ if (dst->xfrm == NULL)
++ return -1;
++
++ for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
++ pos = strict ? i : 0;
++ if (pos >= info->len)
++ return 0;
++ e = &info->pol[pos];
++
++ if (match_xfrm_state(dst->xfrm, e)) {
++ if (!strict)
++ return 1;
++ } else if (strict)
++ return 0;
++ }
++
++ return strict ? 1 : 0;
++}
++
++static int match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo, int offset, int *hotdrop)
++{
++ const struct ipt_policy_info *info = matchinfo;
++ int ret;
++
++ if (info->flags & POLICY_MATCH_IN)
++ ret = match_policy_in(skb, info);
++ else
++ ret = match_policy_out(skb, info);
++
++ if (ret < 0) {
++ if (info->flags & POLICY_MATCH_NONE)
++ ret = 1;
++ else
++ ret = 0;
++ } else if (info->flags & POLICY_MATCH_NONE)
++ ret = 0;
++
++ return ret;
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_policy_info *info = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(*info))) {
++ printk(KERN_ERR "ipt_policy: matchsize %u != %u\n",
++ matchsize, IPT_ALIGN(sizeof(*info)));
++ return 0;
++ }
++ if (!(info->flags & (POLICY_MATCH_IN|POLICY_MATCH_OUT))) {
++ printk(KERN_ERR "ipt_policy: neither incoming nor "
++ "outgoing policy selected\n");
++ return 0;
++ }
++ if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
++ && info->flags & POLICY_MATCH_OUT) {
++ printk(KERN_ERR "ipt_policy: output policy not valid in "
++ "PRE_ROUTING and INPUT\n");
++ return 0;
++ }
++ if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
++ && info->flags & POLICY_MATCH_IN) {
++ printk(KERN_ERR "ipt_policy: input policy not valid in "
++ "POST_ROUTING and OUTPUT\n");
++ return 0;
++ }
++ if (info->len > POLICY_MAX_ELEM) {
++ printk(KERN_ERR "ipt_policy: too many policy elements\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match policy_match =
++{
++ .name = "policy",
++ .match = match,
++ .checkentry = checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&policy_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&policy_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_pool.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_pool.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_pool.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_pool.c 2004-06-08 10:31:45.000000000 +0200
+@@ -0,0 +1,71 @@
++/* Kernel module to match an IP address pool. */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_pool.h>
++#include <linux/netfilter_ipv4/ipt_pool.h>
++
++static inline int match_pool(
++ ip_pool_t index,
++ __u32 addr,
++ int inv
++) {
++ if (ip_pool_match(index, ntohl(addr)))
++ inv = !inv;
++ return inv;
++}
++
++static int match(
++ const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop
++) {
++ const struct ipt_pool_info *info = matchinfo;
++ const struct iphdr *iph = skb->nh.iph;
++
++ if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr,
++ info->flags&IPT_POOL_INV_SRC))
++ return 0;
++
++ if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr,
++ info->flags&IPT_POOL_INV_DST))
++ return 0;
++
++ return 1;
++}
++
++static int checkentry(
++ const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask
++) {
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info)))
++ return 0;
++ return 1;
++}
++
++static struct ipt_match pool_match
++= { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_match(&pool_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&pool_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_psd.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_psd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_psd.c 2004-06-08 10:31:53.000000000 +0200
+@@ -0,0 +1,358 @@
++/*
++ This is a module which is used for PSD (portscan detection)
++ Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
++ and LOG target module.
++
++ Copyright (C) 2000,2001 astaro AG
++
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from:
++ ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++ 2000-05-04 Markus Hennig <hennig@astaro.de> : initial
++ 2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
++ 2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
++ 2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
++ 2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
++ 2004-05-05 Martijn Lievaart <m@rtij.nl> : ported to 2.6
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_psd.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
++
++#define HF_DADDR_CHANGING 0x01
++#define HF_SPORT_CHANGING 0x02
++#define HF_TOS_CHANGING 0x04
++#define HF_TTL_CHANGING 0x08
++
++/*
++ * Information we keep per each target port
++ */
++struct port {
++ u_int16_t number; /* port number */
++ u_int8_t proto; /* protocol number */
++ u_int8_t and_flags; /* tcp ANDed flags */
++ u_int8_t or_flags; /* tcp ORed flags */
++};
++
++/*
++ * Information we keep per each source address.
++ */
++struct host {
++ struct host *next; /* Next entry with the same hash */
++ clock_t timestamp; /* Last update time */
++ struct in_addr src_addr; /* Source address */
++ struct in_addr dest_addr; /* Destination address */
++ unsigned short src_port; /* Source port */
++ int count; /* Number of ports in the list */
++ int weight; /* Total weight of ports in the list */
++ struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */
++ unsigned char tos; /* TOS */
++ unsigned char ttl; /* TTL */
++ unsigned char flags; /* HF_ flags bitmask */
++};
++
++/*
++ * State information.
++ */
++static struct {
++ spinlock_t lock;
++ struct host list[LIST_SIZE]; /* List of source addresses */
++ struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */
++ int index; /* Oldest entry to be replaced */
++} state;
++
++/*
++ * Convert an IP address into a hash table index.
++ */
++static inline int hashfunc(struct in_addr addr)
++{
++ unsigned int value;
++ int hash;
++
++ value = addr.s_addr;
++ hash = 0;
++ do {
++ hash ^= value;
++ } while ((value >>= HASH_LOG));
++
++ return hash & (HASH_SIZE - 1);
++}
++
++static int
++ipt_psd_match(const struct sk_buff *pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ struct iphdr *ip_hdr;
++ struct tcphdr *tcp_hdr;
++ struct in_addr addr;
++ u_int16_t src_port,dest_port;
++ u_int8_t tcp_flags, proto;
++ clock_t now;
++ struct host *curr, *last, **head;
++ int hash, index, count;
++
++ /* Parameters from userspace */
++ const struct ipt_psd_info *psdinfo = matchinfo;
++
++ /* IP header */
++ ip_hdr = pskb->nh.iph;
++
++ /* Sanity check */
++ if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
++ DEBUGP("PSD: sanity check failed\n");
++ return 0;
++ }
++
++ /* TCP or UDP ? */
++ proto = ip_hdr->protocol;
++
++ if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
++ DEBUGP("PSD: protocol not supported\n");
++ return 0;
++ }
++
++ /* Get the source address, source & destination ports, and TCP flags */
++
++ addr.s_addr = ip_hdr->saddr;
++
++ tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
++
++ /* Yep, it´s dirty */
++ src_port = tcp_hdr->source;
++ dest_port = tcp_hdr->dest;
++
++ if (proto == IPPROTO_TCP) {
++ tcp_flags = *((u_int8_t*)tcp_hdr + 13);
++ }
++ else {
++ tcp_flags = 0x00;
++ }
++
++ /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
++ * them spoof us. [DHCP needs this feature - HW] */
++ if (!addr.s_addr) {
++ DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
++ return 0;
++ }
++
++ /* Use jiffies here not to depend on someone setting the time while we're
++ * running; we need to be careful with possible return value overflows. */
++ now = jiffies;
++
++ spin_lock(&state.lock);
++
++ /* Do we know this source address already? */
++ count = 0;
++ last = NULL;
++ if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
++ do {
++ if (curr->src_addr.s_addr == addr.s_addr) break;
++ count++;
++ if (curr->next) last = curr;
++ } while ((curr = curr->next));
++
++ if (curr) {
++
++ /* We know this address, and the entry isn't too old. Update it. */
++ if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
++ time_after_eq(now, curr->timestamp)) {
++
++ /* Just update the appropriate list entry if we've seen this port already */
++ for (index = 0; index < curr->count; index++) {
++ if (curr->ports[index].number == dest_port) {
++ curr->ports[index].proto = proto;
++ curr->ports[index].and_flags &= tcp_flags;
++ curr->ports[index].or_flags |= tcp_flags;
++ goto out_no_match;
++ }
++ }
++
++ /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
++ if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
++ goto out_no_match;
++
++ /* Packet to a new port, and not TCP/ACK: update the timestamp */
++ curr->timestamp = now;
++
++ /* Logged this scan already? Then drop the packet. */
++ if (curr->weight >= psdinfo->weight_threshold)
++ goto out_match;
++
++ /* Specify if destination address, source port, TOS or TTL are not fixed */
++ if (curr->dest_addr.s_addr != ip_hdr->daddr)
++ curr->flags |= HF_DADDR_CHANGING;
++ if (curr->src_port != src_port)
++ curr->flags |= HF_SPORT_CHANGING;
++ if (curr->tos != ip_hdr->tos)
++ curr->flags |= HF_TOS_CHANGING;
++ if (curr->ttl != ip_hdr->ttl)
++ curr->flags |= HF_TTL_CHANGING;
++
++ /* Update the total weight */
++ curr->weight += (ntohs(dest_port) < 1024) ?
++ psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++
++ /* Got enough destination ports to decide that this is a scan? */
++ /* Then log it and drop the packet. */
++ if (curr->weight >= psdinfo->weight_threshold)
++ goto out_match;
++
++ /* Remember the new port */
++ if (curr->count < SCAN_MAX_COUNT) {
++ curr->ports[curr->count].number = dest_port;
++ curr->ports[curr->count].proto = proto;
++ curr->ports[curr->count].and_flags = tcp_flags;
++ curr->ports[curr->count].or_flags = tcp_flags;
++ curr->count++;
++ }
++
++ goto out_no_match;
++ }
++
++ /* We know this address, but the entry is outdated. Mark it unused, and
++ * remove from the hash table. We'll allocate a new entry instead since
++ * this one might get re-used too soon. */
++ curr->src_addr.s_addr = 0;
++ if (last)
++ last->next = last->next->next;
++ else if (*head)
++ *head = (*head)->next;
++ last = NULL;
++ }
++
++ /* We don't need an ACK from a new source address */
++ if (proto == IPPROTO_TCP && tcp_hdr->ack)
++ goto out_no_match;
++
++ /* Got too many source addresses with the same hash value? Then remove the
++ * oldest one from the hash table, so that they can't take too much of our
++ * CPU time even with carefully chosen spoofed IP addresses. */
++ if (count >= HASH_MAX && last) last->next = NULL;
++
++ /* We're going to re-use the oldest list entry, so remove it from the hash
++ * table first (if it is really already in use, and isn't removed from the
++ * hash table already because of the HASH_MAX check above). */
++
++ /* First, find it */
++ if (state.list[state.index].src_addr.s_addr)
++ head = &state.hash[hashfunc(state.list[state.index].src_addr)];
++ else
++ head = &last;
++ last = NULL;
++ if ((curr = *head))
++ do {
++ if (curr == &state.list[state.index]) break;
++ last = curr;
++ } while ((curr = curr->next));
++
++ /* Then, remove it */
++ if (curr) {
++ if (last)
++ last->next = last->next->next;
++ else if (*head)
++ *head = (*head)->next;
++ }
++
++ /* Get our list entry */
++ curr = &state.list[state.index++];
++ if (state.index >= LIST_SIZE) state.index = 0;
++
++ /* Link it into the hash table */
++ head = &state.hash[hash];
++ curr->next = *head;
++ *head = curr;
++
++ /* And fill in the fields */
++ curr->timestamp = now;
++ curr->src_addr = addr;
++ curr->dest_addr.s_addr = ip_hdr->daddr;
++ curr->src_port = src_port;
++ curr->count = 1;
++ curr->weight = (ntohs(dest_port) < 1024) ?
++ psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++ curr->ports[0].number = dest_port;
++ curr->ports[0].proto = proto;
++ curr->ports[0].and_flags = tcp_flags;
++ curr->ports[0].or_flags = tcp_flags;
++ curr->tos = ip_hdr->tos;
++ curr->ttl = ip_hdr->ttl;
++
++out_no_match:
++ spin_unlock(&state.lock);
++ return 0;
++
++out_match:
++ spin_unlock(&state.lock);
++ return 1;
++}
++
++static int ipt_psd_checkentry(const char *tablename,
++ const struct ipt_ip *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++/* const struct ipt_psd_info *psdinfo = targinfo;*/
++
++ /* we accept TCP only */
++/* if (e->ip.proto != IPPROTO_TCP) { */
++/* DEBUGP("PSD: specified protocol may be TCP only\n"); */
++/* return 0; */
++/* } */
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
++ DEBUGP("PSD: matchsize %u != %u\n",
++ matchsize,
++ IPT_ALIGN(sizeof(struct ipt_psd_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match ipt_psd_reg = {
++ .name = "psd",
++ .match = ipt_psd_match,
++ .checkentry = ipt_psd_checkentry,
++ .me = THIS_MODULE };
++
++static int __init init(void)
++{
++ if (ipt_register_match(&ipt_psd_reg))
++ return -EINVAL;
++
++ memset(&state, 0, sizeof(state));
++
++ spin_lock_init(&(state.lock));
++
++ printk("netfilter PSD loaded - (c) astaro AG\n");
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipt_psd_reg);
++ printk("netfilter PSD unloaded - (c) astaro AG\n");
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_quota.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_quota.c 2004-06-08 10:31:54.000000000 +0200
+@@ -0,0 +1,91 @@
++/*
++ * netfilter module to enforce network quotas
++ *
++ * Sam Johnston <samj@samj.net>
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_quota.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
++
++static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset, int *hotdrop)
++{
++ struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
++ unsigned int datalen;
++
++ if (skb->len < sizeof(struct iphdr))
++ return NF_ACCEPT;
++
++ datalen = skb->len - skb->nh.iph->ihl*4;
++
++ spin_lock_bh("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 --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_random.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_random.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_random.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_random.c 2004-06-08 10:31:56.000000000 +0200
+@@ -0,0 +1,96 @@
++/*
++ This is a module which is used for a "random" match support.
++ 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-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++*/
++
++#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_random.h>
++
++MODULE_LICENSE("GPL");
++
++static int
++ipt_rand_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 ipt_rand_info *info = matchinfo;
++ u_int8_t random_number;
++
++ /* get 1 random number from the kernel random number generation routine */
++ get_random_bytes((void *)(&random_number), 1);
++
++ /* Do we match ? */
++ if (random_number <= info->average)
++ return 1;
++ else
++ return 0;
++}
++
++static int
++ipt_rand_checkentry(const char *tablename,
++ const struct ipt_ip *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Parameters from userspace */
++ const struct ipt_rand_info *info = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) {
++ printk("ipt_random: matchsize %u != %u\n", matchsize,
++ IPT_ALIGN(sizeof(struct ipt_rand_info)));
++ return 0;
++ }
++
++ /* must be 1 <= average % <= 99 */
++ /* 1 x 2.55 = 2 */
++ /* 99 x 2.55 = 252 */
++ if ((info->average < 2) || (info->average > 252)) {
++ printk("ipt_random: invalid average %u\n", info->average);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match ipt_rand_reg = {
++ {NULL, NULL},
++ "random",
++ ipt_rand_match,
++ ipt_rand_checkentry,
++ NULL,
++ THIS_MODULE };
++
++static int __init init(void)
++{
++ if (ipt_register_match(&ipt_rand_reg))
++ return -EINVAL;
++
++ printk("ipt_random match loaded\n");
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipt_rand_reg);
++ printk("ipt_random match unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_realm.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_realm.c 2004-06-08 10:32:20.000000000 +0200
+@@ -0,0 +1,78 @@
++/* IP tables module for matching the routing realm
++ *
++ * $Id$
++ *
++ * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <net/route.h>
++
++#include <linux/netfilter_ipv4/ipt_realm.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
++MODULE_LICENSE("GPL");
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_realm_info *info = matchinfo;
++ struct dst_entry *dst = skb->dst;
++
++ if (!dst)
++ return 0;
++
++ return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
++}
++
++static int check(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (hook_mask
++ & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
++ (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
++ printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
++ "LOCAL_IN or FORWARD.\n");
++ return 0;
++ }
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match realm_match = {
++ .name = "realm",
++ .match = match,
++ .checkentry = check,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&realm_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&realm_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_sctp.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_sctp.c 2004-06-08 10:32:21.000000000 +0200
+@@ -0,0 +1,199 @@
++#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 0
++#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;
++
++ int i = 0;
++
++ if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
++ SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
++ }
++
++ offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
++ do {
++ if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
++ duprintf("Dropping invalid SCTP packet.\n");
++ *hotdrop = 1;
++ return 0;
++ }
++
++ duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
++ ++i, offset, sch.type, htons(sch.length), sch.flags);
++
++ offset += (htons(sch.length) + 3) & ~3;
++
++ duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
++
++ if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
++ switch (chunk_match_type) {
++ case SCTP_CHUNK_MATCH_ANY:
++ if (match_flags(flag_info, flag_count,
++ sch.type, sch.flags)) {
++ return 1;
++ }
++ break;
++
++ case SCTP_CHUNK_MATCH_ALL:
++ if (match_flags(flag_info, flag_count,
++ sch.type, sch.flags)) {
++ SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
++ }
++ break;
++
++ case SCTP_CHUNK_MATCH_ONLY:
++ if (!match_flags(flag_info, flag_count,
++ sch.type, sch.flags)) {
++ return 0;
++ }
++ break;
++ }
++ } else {
++ switch (chunk_match_type) {
++ case SCTP_CHUNK_MATCH_ONLY:
++ return 0;
++ }
++ }
++ } while (offset < skb->len);
++
++ switch (chunk_match_type) {
++ case SCTP_CHUNK_MATCH_ALL:
++ return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
++ case SCTP_CHUNK_MATCH_ANY:
++ return 0;
++ case SCTP_CHUNK_MATCH_ONLY:
++ return 1;
++ }
++
++ /* This will never be reached, but required to stop compiler whine */
++ return 0;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_sctp_info *info;
++ sctp_sctphdr_t sh;
++
++ info = (const struct ipt_sctp_info *)matchinfo;
++
++ if (offset) {
++ duprintf("Dropping non-first fragment.. FIXME\n");
++ return 0;
++ }
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
++ duprintf("Dropping evil TCP offset=0 tinygram.\n");
++ *hotdrop = 1;
++ return 0;
++ }
++ duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
++
++ return SCCHECK(((ntohs(sh.source) >= info->spts[0])
++ && (ntohs(sh.source) <= info->spts[1])),
++ IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
++ && SCCHECK(((ntohs(sh.dest) >= info->dpts[0])
++ && (ntohs(sh.dest) <= info->dpts[1])),
++ IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
++ && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
++ info->flag_info, info->flag_count,
++ hotdrop),
++ IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ const struct ipt_sctp_info *info;
++
++ info = (const struct ipt_sctp_info *)matchinfo;
++
++ return ip->proto == IPPROTO_SCTP
++ && !(ip->invflags & IPT_INV_PROTO)
++ && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
++ && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
++ && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
++ && !(info->invflags & ~info->flags)
++ && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) ||
++ (info->chunk_match_type &
++ (SCTP_CHUNK_MATCH_ALL
++ | SCTP_CHUNK_MATCH_ANY
++ | SCTP_CHUNK_MATCH_ONLY)));
++}
++
++static struct ipt_match sctp_match =
++{
++ .list = { NULL, NULL},
++ .name = "sctp",
++ .match = &match,
++ .checkentry = &checkentry,
++ .destroy = NULL,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&sctp_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&sctp_match);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Kiran Kumar Immidi");
++MODULE_DESCRIPTION("Match for SCTP protocol packets");
++
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_string.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_string.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_string.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_string.c 2004-06-08 10:41:24.000000000 +0200
+@@ -0,0 +1,183 @@
++/* Kernel module to match a string into a packet.
++ *
++ * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
++ *
++ * ChangeLog
++ * 24.03.2004: Eric Lauriault <elauri@lacitec.on.ca>
++ * Initial 2.6 port
++ * 19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Fixed SMP re-entrancy problem using per-cpu data areas
++ * for the skip/shift tables.
++ * 02.05.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Fixed kernel panic, due to overrunning boyer moore string
++ * tables. Also slightly tweaked heuristic for deciding what
++ * search algo to use.
++ * 27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Implemented Boyer Moore Sublinear search algorithm
++ * alongside the existing linear search based on memcmp().
++ * Also a quick check to decide which method to use on a per
++ * packet basis.
++ */
++
++#include <linux/smp.h>
++#include <linux/percpu.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_string.h>
++
++MODULE_LICENSE("GPL");
++
++struct string_per_cpu {
++ int skip[BM_MAX_HLEN];
++ int shift[BM_MAX_HLEN];
++ int len[BM_MAX_HLEN];
++};
++
++static DEFINE_PER_CPU(struct string_per_cpu, bm_string_data);
++
++
++/* Boyer Moore Sublinear string search - VERY FAST */
++char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len)
++{
++ int M1, right_end, sk, sh;
++ int ended, j, i;
++
++ int *skip, *shift, *len;
++
++ /* use data suitable for this CPU */
++ shift=__get_cpu_var(bm_string_data).shift;
++ skip=__get_cpu_var(bm_string_data).skip;
++ len=__get_cpu_var(bm_string_data).len;
++
++ /* Setup skip/shift tables */
++ M1 = right_end = needle_len-1;
++ for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len;
++ for (i = 0; needle[i]; i++) skip[(int)needle[i]] = M1 - i;
++
++ for (i = 1; i < needle_len; i++) {
++ for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++);
++ len[i] = j;
++ }
++
++ shift[0] = 1;
++ for (i = 1; i < needle_len; i++) shift[i] = needle_len;
++ for (i = M1; i > 0; i--) shift[len[i]] = i;
++ ended = 0;
++
++ for (i = 0; i < needle_len; i++) {
++ if (len[i] == M1 - i) ended = i;
++ if (ended) shift[i] = ended;
++ }
++
++ /* Do the search*/
++ while (right_end < haystack_len)
++ {
++ for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++);
++ if (i == needle_len) {
++ return haystack+(right_end - M1);
++ }
++
++ sk = skip[(int)haystack[right_end - i]];
++ sh = shift[i];
++ right_end = max(right_end - i + sk, right_end + sh);
++ }
++
++ return NULL;
++}
++
++/* Linear string search based on memcmp() */
++char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len)
++{
++ char *k = haystack + (haystack_len-needle_len);
++ char *t = haystack;
++
++ while ( t <= k ) {
++ if (memcmp(t, needle, needle_len) == 0)
++ return t;
++ t++;
++ }
++
++ return NULL;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_string_info *info = matchinfo;
++ struct iphdr *ip = skb->nh.iph;
++ int hlen, nlen;
++ char *needle, *haystack;
++ proc_ipt_search search=search_linear;
++
++ if ( !ip ) return 0;
++
++ /* get lenghts, and validate them */
++ nlen=info->len;
++ hlen=ntohs(ip->tot_len)-(ip->ihl*4);
++ if ( nlen > hlen ) return 0;
++
++ needle=(char *)&info->string;
++ haystack=(char *)ip+(ip->ihl*4);
++
++ /* The sublinear search comes in to its own
++ * on the larger packets */
++ if ( (hlen>IPT_STRING_HAYSTACK_THRESH) &&
++ (nlen>IPT_STRING_NEEDLE_THRESH) ) {
++ if ( hlen < BM_MAX_HLEN ) {
++ search=search_sublinear;
++ }else{
++ if (net_ratelimit())
++ printk(KERN_INFO "ipt_string: Packet too big "
++ "to attempt sublinear string search "
++ "(%d bytes)\n", hlen );
++ }
++ }
++
++ return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert);
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match string_match = {
++ .name = "string",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++
++static int __init init(void)
++{
++ return ipt_register_match(&string_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&string_match);
++}
++
++module_init(init);
++module_exit(fini);
++
++
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_time.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_time.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_time.c 2004-06-08 10:32:31.000000000 +0200
+@@ -0,0 +1,189 @@
++/*
++ This is a module which is used for time matching
++ It is using some modified code from dietlibc (localtime() function)
++ that you can find at http://www.fefe.de/dietlibc/
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
++ 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++ 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
++ thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
++ 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
++ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
++ added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
++ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO.
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_time.h>
++#include <linux/time.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Match arrival timestamp/date");
++MODULE_LICENSE("GPL");
++
++struct tm
++{
++ int tm_sec; /* Seconds. [0-60] (1 leap second) */
++ int tm_min; /* Minutes. [0-59] */
++ int tm_hour; /* Hours. [0-23] */
++ int tm_mday; /* Day. [1-31] */
++ int tm_mon; /* Month. [0-11] */
++ int tm_year; /* Year - 1900. */
++ int tm_wday; /* Day of week. [0-6] */
++ int tm_yday; /* Days in year.[0-365] */
++ int tm_isdst; /* DST. [-1/0/1]*/
++
++ long int tm_gmtoff; /* we don't care, we count from GMT */
++ const char *tm_zone; /* we don't care, we count from GMT */
++};
++
++void
++localtime(const time_t *timepr, struct tm *r);
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_time_info *info = matchinfo; /* match info for rule */
++ struct tm currenttime; /* time human readable */
++ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
++ u_int16_t packet_time;
++ struct timeval kerneltimeval;
++ time_t packet_local_time;
++
++ /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
++ if (info->kerneltime)
++ {
++ do_gettimeofday(&kerneltimeval);
++ packet_local_time = kerneltimeval.tv_sec;
++ }
++ else
++ packet_local_time = skb->stamp.tv_sec;
++
++ /* First we make sure we are in the date start-stop boundaries */
++ if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop))
++ return 0; /* We are outside the date boundaries */
++
++ /* Transform the timestamp of the packet, in a human readable form */
++ localtime(&packet_local_time, ¤ttime);
++
++ /* check if we match this timestamp, we start by the days... */
++ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
++ return 0; /* the day doesn't match */
++
++ /* ... check the time now */
++ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
++ if ((packet_time < info->time_start) || (packet_time > info->time_stop))
++ return 0;
++
++ /* here we match ! */
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_time_info *info = matchinfo; /* match info for rule */
++
++ /* First, check that we are in the correct hooks */
++ if (hook_mask
++ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++ {
++ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
++ return 0;
++ }
++ /* we use the kerneltime if we are in forward or output */
++ info->kerneltime = 1;
++ if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++ /* we use the skb time */
++ info->kerneltime = 0;
++
++ /* Check the size */
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
++ return 0;
++ /* Now check the coherence of the data ... */
++ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
++ (info->time_stop > 1439))
++ {
++ printk(KERN_WARNING "ipt_time: invalid argument\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match time_match
++= { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ printk("ipt_time loading\n");
++ return ipt_register_match(&time_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&time_match);
++ printk("ipt_time unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
++
++
++/* The part below is borowed and modified from dietlibc */
++
++/* seconds per day */
++#define SPD 24*60*60
++
++void
++localtime(const time_t *timepr, struct tm *r) {
++ time_t i;
++ time_t timep;
++ extern struct timezone sys_tz;
++ const unsigned int __spm[12] =
++ { 0,
++ (31),
++ (31+28),
++ (31+28+31),
++ (31+28+31+30),
++ (31+28+31+30+31),
++ (31+28+31+30+31+30),
++ (31+28+31+30+31+30+31),
++ (31+28+31+30+31+30+31+31),
++ (31+28+31+30+31+30+31+31+30),
++ (31+28+31+30+31+30+31+31+30+31),
++ (31+28+31+30+31+30+31+31+30+31+30),
++ };
++ register time_t work;
++
++ timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
++ work=timep%(SPD);
++ r->tm_sec=work%60; work/=60;
++ r->tm_min=work%60; r->tm_hour=work/60;
++ work=timep/(SPD);
++ r->tm_wday=(4+work)%7;
++ for (i=1970; ; ++i) {
++ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
++ if (work>k)
++ work-=k;
++ else
++ break;
++ }
++ r->tm_year=i-1900;
++ for (i=11; i && __spm[i]>work; --i) ;
++ r->tm_mon=i;
++ r->tm_mday=work-__spm[i]+1;
++}
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_u32.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_u32.c 2004-06-08 10:32:32.000000000 +0200
+@@ -0,0 +1,211 @@
++/* Kernel module to match u32 packet content. */
++
++/*
++U32 tests whether quantities of up to 4 bytes extracted from a packet
++have specified values. The specification of what to extract is general
++enough to find data at given offsets from tcp headers or payloads.
++
++ --u32 tests
++ The argument amounts to a program in a small language described below.
++ tests := location = value | tests && location = value
++ value := range | value , range
++ range := number | number : number
++ a single number, n, is interpreted the same as n:n
++ n:m is interpreted as the range of numbers >=n and <=m
++ location := number | location operator number
++ operator := & | << | >> | @
++
++ The operators &, <<, >>, && mean the same as in c. The = is really a set
++ membership operator and the value syntax describes a set. The @ operator
++ is what allows moving to the next header and is described further below.
++
++ *** Until I can find out how to avoid it, there are some artificial limits
++ on the size of the tests:
++ - no more than 10 ='s (and 9 &&'s) in the u32 argument
++ - no more than 10 ranges (and 9 commas) per value
++ - no more than 10 numbers (and 9 operators) per location
++
++ To describe the meaning of location, imagine the following machine that
++ interprets it. There are three registers:
++ A is of type char*, initially the address of the IP header
++ B and C are unsigned 32 bit integers, initially zero
++
++ The instructions are:
++ number B = number;
++ C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
++ &number C = C&number
++ <<number C = C<<number
++ >>number C = C>>number
++ @number A = A+C; then do the instruction number
++ Any access of memory outside [skb->head,skb->end] causes the match to fail.
++ Otherwise the result of the computation is the final value of C.
++
++ Whitespace is allowed but not required in the tests.
++ However the characters that do occur there are likely to require
++ shell quoting, so it's a good idea to enclose the arguments in quotes.
++
++Example:
++ match IP packets with total length >= 256
++ The IP header contains a total length field in bytes 2-3.
++ --u32 "0&0xFFFF=0x100:0xFFFF"
++ read bytes 0-3
++ AND that with FFFF (giving bytes 2-3),
++ and test whether that's in the range [0x100:0xFFFF]
++
++Example: (more realistic, hence more complicated)
++ match icmp packets with icmp type 0
++ First test that it's an icmp packet, true iff byte 9 (protocol) = 1
++ --u32 "6&0xFF=1 && ...
++ read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
++ Next test that it's not a fragment.
++ (If so it might be part of such a packet but we can't always tell.)
++ n.b. This test is generally needed if you want to match anything
++ beyond the IP header.
++ The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
++ packet (not a fragment). Alternatively, you can allow first fragments
++ by only testing the last 5 bits of byte 6.
++ ... 4&0x3FFF=0 && ...
++ Last test: the first byte past the IP header (the type) is 0
++ This is where we have to use the @syntax. The length of the IP header
++ (IHL) in 32 bit words is stored in the right half of byte 0 of the
++ IP header itself.
++ ... 0>>22&0x3C@0>>24=0"
++ The first 0 means read bytes 0-3,
++ >>22 means shift that 22 bits to the right. Shifting 24 bits would give
++ the first byte, so only 22 bits is four times that plus a few more bits.
++ &3C then eliminates the two extra bits on the right and the first four
++ bits of the first byte.
++ For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
++ In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
++ >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
++ @ means to use this number as a new offset into the packet, and read
++ four bytes starting from there. This is the first 4 bytes of the icmp
++ payload, of which byte 0 is the icmp type. Therefore we simply shift
++ the value 24 to the right to throw out all but the first byte and compare
++ the result with 0.
++
++Example:
++ tcp payload bytes 8-12 is any of 1, 2, 5 or 8
++ First we test that the packet is a tcp packet (similar to icmp).
++ --u32 "6&0xFF=6 && ...
++ Next, test that it's not a fragment (same as above).
++ ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
++ 0>>22&3C as above computes the number of bytes in the IP header.
++ @ makes this the new offset into the packet, which is the start of the
++ tcp header. The length of the tcp header (again in 32 bit words) is
++ the left half of byte 12 of the tcp header. The 12>>26&3C
++ computes this length in bytes (similar to the IP header before).
++ @ makes this the new offset, which is the start of the tcp payload.
++ Finally 8 reads bytes 8-12 of the payload and = checks whether the
++ result is any of 1, 2, 5 or 8
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ipt_u32.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++/* #include <asm-i386/timex.h> for timing */
++
++MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
++MODULE_DESCRIPTION("IP tables u32 matching module");
++MODULE_LICENSE("GPL");
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_u32 *data = matchinfo;
++ int testind, i;
++ unsigned char* origbase = (char*)skb->nh.iph;
++ unsigned char* base = origbase;
++ unsigned char* head = skb->head;
++ unsigned char* end = skb->end;
++ int nnums, nvals;
++ u_int32_t pos, val;
++ /* unsigned long long cycles1, cycles2, cycles3, cycles4;
++ cycles1 = get_cycles(); */
++
++ for (testind=0; testind < data->ntests; testind++) {
++ base = origbase; /* reset for each test */
++ pos = data->tests[testind].location[0].number;
++ if (base+pos+3 > end || base+pos < head)
++ return 0;
++ val = (base[pos]<<24) + (base[pos+1]<<16) +
++ (base[pos+2]<<8) + base[pos+3];
++ nnums = data->tests[testind].nnums;
++ for (i=1; i < nnums; i++) {
++ u_int32_t number = data->tests[testind].location[i].number;
++ switch (data->tests[testind].location[i].nextop) {
++ case IPT_U32_AND:
++ val = val & number;
++ break;
++ case IPT_U32_LEFTSH:
++ val = val << number;
++ break;
++ case IPT_U32_RIGHTSH:
++ val = val >> number;
++ break;
++ case IPT_U32_AT:
++ base = base + val;
++ pos = number;
++ if (base+pos+3 > end || base+pos < head)
++ return 0;
++ val = (base[pos]<<24) + (base[pos+1]<<16) +
++ (base[pos+2]<<8) + base[pos+3];
++ break;
++ }
++ }
++ nvals = data->tests[testind].nvalues;
++ for (i=0; i < nvals; i++) {
++ if ((data->tests[testind].value[i].min <= val) &&
++ (val <= data->tests[testind].value[i].max)) {
++ break;
++ }
++ }
++ if (i >= data->tests[testind].nvalues) {
++ /* cycles2 = get_cycles();
++ printk("failed %d in %d cycles\n", testind,
++ cycles2-cycles1); */
++ return 0;
++ }
++ }
++ /* cycles2 = get_cycles();
++ printk("succeeded in %d cycles\n", cycles2-cycles1); */
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
++ return 0;
++ return 1;
++}
++
++static struct ipt_match u32_match
++= { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_match(&u32_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&u32_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_unclean.c linux-2.6.7-rc3/net/ipv4/netfilter/ipt_unclean.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/ipt_unclean.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/ipt_unclean.c 2004-06-08 10:41:16.000000000 +0200
+@@ -0,0 +1,604 @@
++/* Kernel module to match suspect packets. */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/udp.h>
++#include <linux/tcp.h>
++#include <linux/icmp.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++#define limpk(format, args...) \
++do { \
++ if (net_ratelimit()) \
++ printk("ipt_unclean: %s" format, \
++ embedded ? "(embedded packet) " : "" , ## args); \
++} while(0)
++
++enum icmp_error_status
++{
++ ICMP_MAY_BE_ERROR,
++ ICMP_IS_ERROR,
++ ICMP_NOT_ERROR
++};
++
++struct icmp_info
++{
++ size_t min_len, max_len;
++ enum icmp_error_status err;
++ u_int8_t min_code, max_code;
++};
++
++static int
++check_ip(struct iphdr *iph, size_t length, int embedded);
++
++/* ICMP-specific checks. */
++static int
++check_icmp(const struct icmphdr *icmph,
++ u_int16_t datalen,
++ unsigned int offset,
++ int more_frags,
++ int embedded)
++{
++ static struct icmp_info info[]
++ = { [ICMP_ECHOREPLY]
++ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_DEST_UNREACH]
++ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 15 },
++ [ICMP_SOURCE_QUENCH]
++ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 0 },
++ [ICMP_REDIRECT]
++ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 3 },
++ [ICMP_ECHO]
++ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
++ /* Router advertisement. */
++ [9]
++ = { 8, 8 + 255 * 8, ICMP_NOT_ERROR, 0, 0 },
++ /* Router solicitation. */
++ [10]
++ = { 8, 8, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_TIME_EXCEEDED]
++ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1 },
++ [ICMP_PARAMETERPROB]
++ = { 8 + 28, 65536, ICMP_IS_ERROR, 0, 1 },
++ [ICMP_TIMESTAMP]
++ = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_TIMESTAMPREPLY]
++ = { 20, 20, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_INFO_REQUEST]
++ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_INFO_REPLY]
++ = { 8, 65536, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_ADDRESS]
++ = { 12, 12, ICMP_NOT_ERROR, 0, 0 },
++ [ICMP_ADDRESSREPLY]
++ = { 12, 12, ICMP_NOT_ERROR, 0, 0 } };
++
++ /* Can't do anything if it's a fragment. */
++ if (offset)
++ return 1;
++
++ /* Must cover type and code. */
++ if (datalen < 2) {
++ limpk("ICMP len=%u too short\n", datalen);
++ return 0;
++ }
++
++ /* If not embedded. */
++ if (!embedded) {
++ /* Bad checksum? Don't print, just ignore. */
++ if (!more_frags
++ && ip_compute_csum((unsigned char *) icmph, datalen) != 0)
++ return 0;
++
++ /* CHECK: Truncated ICMP (even if first fragment). */
++ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
++ && info[icmph->type].min_len != 0
++ && datalen < info[icmph->type].min_len) {
++ limpk("ICMP type %u len %u too short\n",
++ icmph->type, datalen);
++ return 0;
++ }
++
++ /* CHECK: Check within known error ICMPs. */
++ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
++ && info[icmph->type].err == ICMP_IS_ERROR) {
++ /* CHECK: Embedded packet must be at least
++ length of iph + 8 bytes. */
++ struct iphdr *inner = (void *)icmph + 8;
++
++ /* datalen > 8 since all ICMP_IS_ERROR types
++ have min length > 8 */
++ if (datalen - 8 < sizeof(struct iphdr)) {
++ limpk("ICMP error internal way too short\n");
++ return 0;
++ }
++ if (datalen - 8 < inner->ihl*4 + 8) {
++ limpk("ICMP error internal too short\n");
++ return 0;
++ }
++ if (!check_ip(inner, datalen - 8, 1))
++ return 0;
++ }
++ } else {
++ /* CHECK: Can't embed ICMP unless known non-error. */
++ if (icmph->type >= sizeof(info)/sizeof(struct icmp_info)
++ || info[icmph->type].err != ICMP_NOT_ERROR) {
++ limpk("ICMP type %u not embeddable\n",
++ icmph->type);
++ return 0;
++ }
++ }
++
++ /* CHECK: Invalid ICMP codes. */
++ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
++ && (icmph->code < info[icmph->type].min_code
++ || icmph->code > info[icmph->type].max_code)) {
++ limpk("ICMP type=%u code=%u\n",
++ icmph->type, icmph->code);
++ return 0;
++ }
++
++ /* CHECK: Above maximum length. */
++ if (icmph->type < sizeof(info)/sizeof(struct icmp_info)
++ && info[icmph->type].max_len != 0
++ && datalen > info[icmph->type].max_len) {
++ limpk("ICMP type=%u too long: %u bytes\n",
++ icmph->type, datalen);
++ return 0;
++ }
++
++ switch (icmph->type) {
++ case ICMP_PARAMETERPROB: {
++ /* CHECK: Problem param must be within error packet's
++ * IP header. */
++ struct iphdr *iph = (void *)icmph + 8;
++ u_int32_t arg = ntohl(icmph->un.gateway);
++
++ if (icmph->code == 0) {
++ /* Code 0 means that upper 8 bits is pointer
++ to problem. */
++ if ((arg >> 24) >= iph->ihl*4) {
++ limpk("ICMP PARAMETERPROB ptr = %u\n",
++ ntohl(icmph->un.gateway) >> 24);
++ return 0;
++ }
++ arg &= 0x00FFFFFF;
++ }
++
++ /* CHECK: Rest must be zero. */
++ if (arg) {
++ limpk("ICMP PARAMETERPROB nonzero arg = %u\n",
++ arg);
++ return 0;
++ }
++ break;
++ }
++
++ case ICMP_TIME_EXCEEDED:
++ case ICMP_SOURCE_QUENCH:
++ /* CHECK: Unused must be zero. */
++ if (icmph->un.gateway != 0) {
++ limpk("ICMP type=%u unused = %u\n",
++ icmph->type, ntohl(icmph->un.gateway));
++ return 0;
++ }
++ break;
++ }
++
++ return 1;
++}
++
++/* UDP-specific checks. */
++static int
++check_udp(const struct iphdr *iph,
++ const struct udphdr *udph,
++ u_int16_t datalen,
++ unsigned int offset,
++ int more_frags,
++ int embedded)
++{
++ /* Can't do anything if it's a fragment. */
++ if (offset)
++ return 1;
++
++ /* CHECK: Must cover UDP header. */
++ if (datalen < sizeof(struct udphdr)) {
++ limpk("UDP len=%u too short\n", datalen);
++ return 0;
++ }
++
++ /* Bad checksum? Don't print, just say it's unclean. */
++ /* FIXME: SRC ROUTE packets won't match checksum --RR */
++ if (!more_frags && !embedded && udph->check
++ && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP,
++ csum_partial((char *)udph, datalen, 0)) != 0)
++ return 0;
++
++ /* CHECK: Destination port can't be zero. */
++ if (!udph->dest) {
++ limpk("UDP zero destination port\n");
++ return 0;
++ }
++
++ if (!more_frags) {
++ if (!embedded) {
++ /* CHECK: UDP length must match. */
++ if (ntohs(udph->len) != datalen) {
++ limpk("UDP len too short %u vs %u\n",
++ ntohs(udph->len), datalen);
++ return 0;
++ }
++ } else {
++ /* CHECK: UDP length be >= this truncated pkt. */
++ if (ntohs(udph->len) < datalen) {
++ limpk("UDP len too long %u vs %u\n",
++ ntohs(udph->len), datalen);
++ return 0;
++ }
++ }
++ } else {
++ /* CHECK: UDP length must be > this frag's length. */
++ if (ntohs(udph->len) <= datalen) {
++ limpk("UDP fragment len too short %u vs %u\n",
++ ntohs(udph->len), datalen);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++#define TH_FIN 0x01
++#define TH_SYN 0x02
++#define TH_RST 0x04
++#define TH_PUSH 0x08
++#define TH_ACK 0x10
++#define TH_URG 0x20
++#define TH_ECE 0x40
++#define TH_CWR 0x80
++
++/* table of valid flag combinations - ECE and CWR are always valid */
++static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
++{
++ [TH_SYN] = 1,
++ [TH_SYN|TH_ACK] = 1,
++ [TH_RST] = 1,
++ [TH_RST|TH_ACK] = 1,
++ [TH_RST|TH_ACK|TH_PUSH] = 1,
++ [TH_FIN|TH_ACK] = 1,
++ [TH_ACK] = 1,
++ [TH_ACK|TH_PUSH] = 1,
++ [TH_ACK|TH_URG] = 1,
++ [TH_ACK|TH_URG|TH_PUSH] = 1,
++ [TH_FIN|TH_ACK|TH_PUSH] = 1,
++ [TH_FIN|TH_ACK|TH_URG] = 1,
++ [TH_FIN|TH_ACK|TH_URG|TH_PUSH] = 1
++};
++
++/* TCP-specific checks. */
++static int
++check_tcp(const struct iphdr *iph,
++ const struct tcphdr *tcph,
++ u_int16_t datalen,
++ unsigned int offset,
++ int more_frags,
++ int embedded)
++{
++ u_int8_t *opt = (u_int8_t *)tcph;
++ u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4;
++ u_int8_t tcpflags;
++ int end_of_options = 0;
++ size_t i;
++
++ /* CHECK: Can't have offset=1: used to override TCP syn-checks. */
++ /* In fact, this is caught below (offset < 516). */
++
++ /* Can't do anything if it's a fragment. */
++ if (offset)
++ return 1;
++
++ /* CHECK: Smaller than minimal TCP hdr. */
++ if (datalen < sizeof(struct tcphdr)) {
++ if (!embedded) {
++ limpk("Packet length %u < TCP header.\n", datalen);
++ return 0;
++ }
++ /* Must have ports available (datalen >= 8), from
++ check_icmp which set embedded = 1 */
++ /* CHECK: TCP ports inside ICMP error */
++ if (!tcph->source || !tcph->dest) {
++ limpk("Zero TCP ports %u/%u.\n",
++ htons(tcph->source), htons(tcph->dest));
++ return 0;
++ }
++ return 1;
++ }
++
++ /* CHECK: Smaller than actual TCP hdr. */
++ if (datalen < tcph->doff * 4) {
++ if (!embedded) {
++ limpk("Packet length %u < actual TCP header.\n",
++ datalen);
++ return 0;
++ } else
++ return 1;
++ }
++
++ /* Bad checksum? Don't print, just say it's unclean. */
++ /* FIXME: SRC ROUTE packets won't match checksum --RR */
++ if (!more_frags && !embedded
++ && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_TCP,
++ csum_partial((char *)tcph, datalen, 0)) != 0)
++ return 0;
++
++ /* CHECK: TCP ports non-zero */
++ if (!tcph->source || !tcph->dest) {
++ limpk("Zero TCP ports %u/%u.\n",
++ htons(tcph->source), htons(tcph->dest));
++ return 0;
++ }
++
++ /* CHECK: TCP reserved bits zero. */
++ if(tcp_flag_word(tcph) & TCP_RESERVED_BITS) {
++ limpk("TCP reserved bits not zero\n");
++ return 0;
++ }
++
++ /* CHECK: TCP flags. */
++ tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
++ if (!tcp_valid_flags[tcpflags]) {
++ limpk("TCP flags bad: %u\n", tcpflags);
++ return 0;
++ }
++
++ for (i = sizeof(struct tcphdr); i < tcph->doff * 4; ) {
++ switch (opt[i]) {
++ case 0:
++ end_of_options = 1;
++ i++;
++ break;
++ case 1:
++ i++;
++ break;
++ default:
++ /* CHECK: options after EOO. */
++ if (end_of_options) {
++ limpk("TCP option %u after end\n",
++ opt[i]);
++ return 0;
++ }
++ /* CHECK: options at tail. */
++ else if (i+1 >= tcph->doff * 4) {
++ limpk("TCP option %u at tail\n",
++ opt[i]);
++ return 0;
++ }
++ /* CHECK: zero-length options. */
++ else if (opt[i+1] == 0) {
++ limpk("TCP option %u 0 len\n",
++ opt[i]);
++ return 0;
++ }
++ /* CHECK: oversize options. */
++ else if (&opt[i] + opt[i+1] > endhdr) {
++ limpk("TCP option %u at %Zu too long\n",
++ (unsigned int) opt[i], i);
++ return 0;
++ }
++ /* Move to next option */
++ i += opt[i+1];
++ }
++ }
++
++ return 1;
++}
++
++/* Returns 1 if ok */
++/* Standard IP checks. */
++static int
++check_ip(struct iphdr *iph, size_t length, int embedded)
++{
++ u_int8_t *opt = (u_int8_t *)iph;
++ u_int8_t *endhdr = (u_int8_t *)iph + iph->ihl * 4;
++ int end_of_options = 0;
++ void *protoh;
++ size_t datalen;
++ unsigned int i;
++ unsigned int offset;
++
++ /* Should only happen for local outgoing raw-socket packets. */
++ /* CHECK: length >= ip header. */
++ if (length < sizeof(struct iphdr) || length < iph->ihl * 4) {
++ limpk("Packet length %Zu < IP header.\n", length);
++ return 0;
++ }
++
++ offset = ntohs(iph->frag_off) & IP_OFFSET;
++ protoh = (void *)iph + iph->ihl * 4;
++ datalen = length - iph->ihl * 4;
++
++ /* CHECK: Embedded fragment. */
++ if (embedded && offset) {
++ limpk("Embedded fragment.\n");
++ return 0;
++ }
++
++ for (i = sizeof(struct iphdr); i < iph->ihl * 4; ) {
++ switch (opt[i]) {
++ case 0:
++ end_of_options = 1;
++ i++;
++ break;
++ case 1:
++ i++;
++ break;
++ default:
++ /* CHECK: options after EOO. */
++ if (end_of_options) {
++ limpk("IP option %u after end\n",
++ opt[i]);
++ return 0;
++ }
++ /* CHECK: options at tail. */
++ else if (i+1 >= iph->ihl * 4) {
++ limpk("IP option %u at tail\n",
++ opt[i]);
++ return 0;
++ }
++ /* CHECK: zero-length or one-length options. */
++ else if (opt[i+1] < 2) {
++ limpk("IP option %u %u len\n",
++ opt[i], opt[i+1]);
++ return 0;
++ }
++ /* CHECK: oversize options. */
++ else if (&opt[i] + opt[i+1] > endhdr) {
++ limpk("IP option %u at %u too long\n",
++ opt[i], i);
++ return 0;
++ }
++ /* Move to next option */
++ i += opt[i+1];
++ }
++ }
++
++ /* Fragment checks. */
++
++ /* CHECK: More fragments, but doesn't fill 8-byte boundary. */
++ if ((ntohs(iph->frag_off) & IP_MF)
++ && (ntohs(iph->tot_len) % 8) != 0) {
++ limpk("Truncated fragment %u long.\n", ntohs(iph->tot_len));
++ return 0;
++ }
++
++ /* CHECK: Oversize fragment a-la Ping of Death. */
++ if (offset * 8 + datalen > 65535) {
++ limpk("Oversize fragment to %u.\n", offset * 8);
++ return 0;
++ }
++
++ /* CHECK: DF set and offset or MF set. */
++ if ((ntohs(iph->frag_off) & IP_DF)
++ && (offset || (ntohs(iph->frag_off) & IP_MF))) {
++ limpk("DF set and offset=%u, MF=%u.\n",
++ offset, ntohs(iph->frag_off) & IP_MF);
++ return 0;
++ }
++
++ /* CHECK: Zero-sized fragments. */
++ if ((offset || (ntohs(iph->frag_off) & IP_MF))
++ && datalen == 0) {
++ limpk("Zero size fragment offset=%u\n", offset);
++ return 0;
++ }
++
++ /* Note: we can have even middle fragments smaller than this:
++ consider a large packet passing through a 600MTU then
++ 576MTU link: this gives a fragment of 24 data bytes. But
++ everyone packs fragments largest first, hence a fragment
++ can't START before 576 - MAX_IP_HEADER_LEN. */
++
++ /* Used to be min-size 576: I recall Alan Cox saying ax25 goes
++ down to 128 (576 taken from RFC 791: All hosts must be
++ prepared to accept datagrams of up to 576 octets). Use 128
++ here. */
++#define MIN_LIKELY_MTU 128
++ /* CHECK: Min size of first frag = 128. */
++ if ((ntohs(iph->frag_off) & IP_MF)
++ && offset == 0
++ && ntohs(iph->tot_len) < MIN_LIKELY_MTU) {
++ limpk("First fragment size %u < %u\n", ntohs(iph->tot_len),
++ MIN_LIKELY_MTU);
++ return 0;
++ }
++
++ /* CHECK: Min offset of frag = 128 - IP hdr len. */
++ if (offset && offset * 8 < MIN_LIKELY_MTU - iph->ihl * 4) {
++ limpk("Fragment starts at %u < %u\n", offset * 8,
++ MIN_LIKELY_MTU - iph->ihl * 4);
++ return 0;
++ }
++
++ /* CHECK: Protocol specification non-zero. */
++ if (iph->protocol == 0) {
++ limpk("Zero protocol\n");
++ return 0;
++ }
++
++ /* CHECK: Do not use what is unused.
++ * First bit of fragmentation flags should be unused.
++ * May be used by OS fingerprinting tools.
++ * 04 Jun 2002, Maciej Soltysiak, solt@dns.toxicfilms.tv
++ */
++ if (ntohs(iph->frag_off)>>15) {
++ limpk("IP unused bit set\n");
++ return 0;
++ }
++
++ /* Per-protocol checks. */
++ switch (iph->protocol) {
++ case IPPROTO_ICMP:
++ return check_icmp(protoh, datalen, offset,
++ (ntohs(iph->frag_off) & IP_MF),
++ embedded);
++
++ case IPPROTO_UDP:
++ return check_udp(iph, protoh, datalen, offset,
++ (ntohs(iph->frag_off) & IP_MF),
++ embedded);
++
++ case IPPROTO_TCP:
++ return check_tcp(iph, protoh, datalen, offset,
++ (ntohs(iph->frag_off) & IP_MF),
++ embedded);
++ default:
++ /* Ignorance is bliss. */
++ return 1;
++ }
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ return !check_ip(skb->nh.iph, skb->len, 0);
++}
++
++/* 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(0))
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match unclean_match
++= { { NULL, NULL }, "unclean", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_match(&unclean_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&unclean_match);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_filter.c linux-2.6.7-rc3/net/ipv4/netfilter/iptable_filter.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_filter.c 2004-06-07 21:14:05.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/iptable_filter.c 2004-06-08 10:37:30.000000000 +0200
+@@ -59,7 +59,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+@@ -67,7 +67,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -75,7 +75,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } }
+ },
+@@ -84,7 +84,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_mangle.c linux-2.6.7-rc3/net/ipv4/netfilter/iptable_mangle.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_mangle.c 2004-06-07 21:14:58.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/iptable_mangle.c 2004-06-08 10:37:30.000000000 +0200
+@@ -74,7 +74,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_IN */
+@@ -82,7 +82,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+@@ -90,7 +90,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -98,7 +98,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* POST_ROUTING */
+@@ -106,7 +106,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ },
+@@ -115,7 +115,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+ { } },
+ "ERROR"
+@@ -173,8 +173,13 @@
+ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
+ && ((*pskb)->nh.iph->saddr != saddr
+ || (*pskb)->nh.iph->daddr != daddr
++#ifdef CONFIG_IP_ROUTE_FWMARK
+ || (*pskb)->nfmark != nfmark
+- || (*pskb)->nh.iph->tos != tos))
++#endif
++#ifdef CONFIG_IP_ROUTE_TOS
++ || (*pskb)->nh.iph->tos != tos
++#endif
++ ))
+ return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+
+ return ret;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.7-rc3/net/ipv4/netfilter/iptable_raw.c
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/iptable_raw.c 2004-06-07 21:14:59.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/netfilter/iptable_raw.c 2004-06-08 10:37:30.000000000 +0200
+@@ -46,7 +46,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -54,7 +54,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } }
+ },
+@@ -63,7 +63,7 @@
+ 0,
+ sizeof(struct ipt_entry),
+ sizeof(struct ipt_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/netfilter/string.2.6.patch linux-2.6.7-rc3/net/ipv4/netfilter/string.2.6.patch
+--- linux-2.6.7-rc3.org/net/ipv4/netfilter/string.2.6.patch 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv4/netfilter/string.2.6.patch 2004-06-08 10:41:24.000000000 +0200
+@@ -0,0 +1,152 @@
++--- ipt_string.c.old Mon Mar 29 06:00:23 2004
+++++ ipt_string.c Mon Mar 29 06:01:04 2004
++@@ -3,6 +3,8 @@
++ * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be>
++ *
++ * ChangeLog
+++ * 24.03.2004: Eric Lauriault <elauri@lacitec.on.ca>
+++ * Initial 2.6 port
++ * 19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk>
++ * Fixed SMP re-entrancy problem using per-cpu data areas
++ * for the skip/shift tables.
++@@ -18,6 +20,7 @@
++ */
++
++ #include <linux/smp.h>
+++#include <linux/percpu.h>
++ #include <linux/module.h>
++ #include <linux/skbuff.h>
++ #include <linux/file.h>
++@@ -29,12 +32,13 @@
++ MODULE_LICENSE("GPL");
++
++ struct string_per_cpu {
++- int *skip;
++- int *shift;
++- int *len;
+++ int skip[BM_MAX_HLEN];
+++ int shift[BM_MAX_HLEN];
+++ int len[BM_MAX_HLEN];
++ };
++
++-struct string_per_cpu *bm_string_data=NULL;
+++static DEFINE_PER_CPU(struct string_per_cpu, bm_string_data);
+++
++
++ /* Boyer Moore Sublinear string search - VERY FAST */
++ char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len)
++@@ -45,14 +49,14 @@
++ int *skip, *shift, *len;
++
++ /* use data suitable for this CPU */
++- shift=bm_string_data[smp_processor_id()].shift;
++- skip=bm_string_data[smp_processor_id()].skip;
++- len=bm_string_data[smp_processor_id()].len;
+++ shift=__get_cpu_var(bm_string_data).shift;
+++ skip=__get_cpu_var(bm_string_data).skip;
+++ len=__get_cpu_var(bm_string_data).len;
++
++ /* Setup skip/shift tables */
++ M1 = right_end = needle_len-1;
++ for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len;
++- for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i;
+++ for (i = 0; needle[i]; i++) skip[(int)needle[i]] = M1 - i;
++
++ for (i = 1; i < needle_len; i++) {
++ for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++);
++@@ -77,7 +81,7 @@
++ return haystack+(right_end - M1);
++ }
++
++- sk = skip[haystack[right_end - i]];
+++ sk = skip[(int)haystack[right_end - i]];
++ sh = shift[i];
++ right_end = max(right_end - i + sk, right_end + sh);
++ }
++@@ -100,15 +104,12 @@
++ return NULL;
++ }
++
++-
++ static int
++ match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++- const void *hdr,
++- u_int16_t datalen,
++ int *hotdrop)
++ {
++ const struct ipt_string_info *info = matchinfo;
++@@ -158,61 +159,25 @@
++ return 1;
++ }
++
++-void string_freeup_data(void)
++-{
++- int c;
++-
++- if ( bm_string_data ) {
++- for(c=0; c<smp_num_cpus; c++) {
++- if ( bm_string_data[c].shift ) kfree(bm_string_data[c].shift);
++- if ( bm_string_data[c].skip ) kfree(bm_string_data[c].skip);
++- if ( bm_string_data[c].len ) kfree(bm_string_data[c].len);
++- }
++- kfree(bm_string_data);
++- }
++-}
+++static struct ipt_match string_match = {
+++ .name = "string",
+++ .match = &match,
+++ .checkentry = &checkentry,
+++ .me = THIS_MODULE
+++};
++
++-static struct ipt_match string_match
++-= { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE };
++
++ static int __init init(void)
++ {
++- int c;
++- size_t tlen;
++- size_t alen;
++-
++- tlen=sizeof(struct string_per_cpu)*smp_num_cpus;
++- alen=sizeof(int)*BM_MAX_HLEN;
++-
++- /* allocate array of structures */
++- if ( !(bm_string_data=kmalloc(tlen,GFP_KERNEL)) ) {
++- return 0;
++- }
++-
++- memset(bm_string_data, 0, tlen);
++-
++- /* allocate our skip/shift tables */
++- for(c=0; c<smp_num_cpus; c++) {
++- if ( !(bm_string_data[c].shift=kmalloc(alen, GFP_KERNEL)) )
++- goto alloc_fail;
++- if ( !(bm_string_data[c].skip=kmalloc(alen, GFP_KERNEL)) )
++- goto alloc_fail;
++- if ( !(bm_string_data[c].len=kmalloc(alen, GFP_KERNEL)) )
++- goto alloc_fail;
++- }
++-
++ return ipt_register_match(&string_match);
++-
++-alloc_fail:
++- string_freeup_data();
++- return 0;
++ }
++
++ static void __exit fini(void)
++ {
++ ipt_unregister_match(&string_match);
++- string_freeup_data();
++ }
++
++ module_init(init);
++ module_exit(fini);
+++
+++
++
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/raw.c linux-2.6.7-rc3/net/ipv4/raw.c
+--- linux-2.6.7-rc3.org/net/ipv4/raw.c 2004-06-07 21:14:25.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/raw.c 2004-06-08 10:38:46.000000000 +0200
+@@ -249,6 +249,7 @@
+ kfree_skb(skb);
+ return NET_RX_DROP;
+ }
++ nf_reset(skb);
+
+ skb_push(skb, skb->data - skb->nh.raw);
+
+@@ -307,7 +308,7 @@
+ }
+
+ err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+- dst_output);
++ ip_dst_output);
+ if (err > 0)
+ err = inet->recverr ? net_xmit_errno(err) : 0;
+ if (err)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/tcp_ipv4.c linux-2.6.7-rc3/net/ipv4/tcp_ipv4.c
+--- linux-2.6.7-rc3.org/net/ipv4/tcp_ipv4.c 2004-06-07 21:14:04.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/tcp_ipv4.c 2004-06-08 10:39:56.000000000 +0200
+@@ -1785,6 +1785,7 @@
+
+ if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
+ goto discard_and_relse;
++ nf_reset(skb);
+
+ if (sk_filter(sk, skb, 0))
+ goto discard_and_relse;
+@@ -2636,6 +2637,7 @@
+ EXPORT_SYMBOL(tcp_v4_connect);
+ EXPORT_SYMBOL(tcp_v4_do_rcv);
+ EXPORT_SYMBOL(tcp_v4_lookup_listener);
++EXPORT_SYMBOL(tcp_v4_lookup);
+ EXPORT_SYMBOL(tcp_v4_rebuild_header);
+ EXPORT_SYMBOL(tcp_v4_remember_stamp);
+ EXPORT_SYMBOL(tcp_v4_send_check);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/udp.c linux-2.6.7-rc3/net/ipv4/udp.c
+--- linux-2.6.7-rc3.org/net/ipv4/udp.c 2004-06-07 21:13:39.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/udp.c 2004-06-08 10:39:56.000000000 +0200
+@@ -1045,6 +1045,7 @@
+ kfree_skb(skb);
+ return -1;
+ }
++ nf_reset(skb);
+
+ if (up->encap_type) {
+ /*
+@@ -1210,6 +1211,7 @@
+
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto drop;
++ nf_reset(skb);
+
+ /* No socket. Drop packet silently, if checksum is wrong */
+ if (udp_checksum_complete(skb))
+@@ -1558,6 +1560,7 @@
+ EXPORT_SYMBOL(udp_port_rover);
+ EXPORT_SYMBOL(udp_prot);
+ EXPORT_SYMBOL(udp_sendmsg);
++EXPORT_SYMBOL(udp_v4_lookup);
+
+ #ifdef CONFIG_PROC_FS
+ EXPORT_SYMBOL(udp_proc_register);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv4/xfrm4_tunnel.c linux-2.6.7-rc3/net/ipv4/xfrm4_tunnel.c
+--- linux-2.6.7-rc3.org/net/ipv4/xfrm4_tunnel.c 2004-06-07 21:13:38.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv4/xfrm4_tunnel.c 2004-06-08 10:38:44.000000000 +0200
+@@ -77,6 +77,7 @@
+ err = -EHOSTUNREACH;
+ goto error_nolock;
+ }
++ IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
+ return NET_XMIT_BYPASS;
+
+ error_nolock:
+@@ -171,6 +172,7 @@
+ .handler = ipip_rcv,
+ .err_handler = ipip_err,
+ .no_policy = 1,
++ .xfrm_prot = 1,
+ };
+
+ static int __init ipip_init(void)
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/ip6_tunnel.c linux-2.6.7-rc3/net/ipv6/ip6_tunnel.c
+--- linux-2.6.7-rc3.org/net/ipv6/ip6_tunnel.c 2004-06-07 21:13:37.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/ip6_tunnel.c 2004-06-08 10:30:55.000000000 +0200
+@@ -715,13 +715,7 @@
+ ipv6h->nexthdr = proto;
+ ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
+ ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+ pkt_len = skb->len;
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
+ skb->dst->dev, dst_output);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/Kconfig linux-2.6.7-rc3/net/ipv6/netfilter/Kconfig
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/Kconfig 2004-06-07 21:14:58.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/Kconfig 2004-06-08 10:42:36.000000000 +0200
+@@ -230,5 +230,107 @@
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+ help
+
++config IP6_NF_TARGET_HL
++ tristate 'HL target support'
++ depends on IP6_NF_MANGLE
++ help
++ This option adds a `HL' target, which allows you to modify the value of
++ IPv6 Hop Limit field.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++config IP6_NF_TARGET_REJECT
++ tristate 'REJECT target support'
++ depends on IP6_NF_FILTER
++ help
++ The REJECT target allows a filtering rule to specify that an ICMPv6
++ error should be issued in response to an incoming packet, rather
++ than silently being dropped.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP6_NF_MATCH_FUZZY
++ tristate 'Fuzzy match support'
++ depends on IP6_NF_FILTER
++ help
++ This option adds a `fuzzy' match, which allows you to match
++ packets according to a fuzzy logic based law.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP6_NF_MATCH_NTH
++ tristate 'Nth match support'
++ depends on IP6_NF_IPTABLES
++ help
++ This option adds a `Nth' match, which allow you to make
++ rules that match every Nth packet. By default there are
++ 16 different counters.
++
++ [options]
++ --every Nth Match every Nth packet
++ [--counter] num Use counter 0-15 (default:0)
++ [--start] num Initialize the counter at the number 'num'
++ instead of 0. Must be between 0 and Nth-1
++ [--packet] num Match on 'num' packet. Must be between 0
++ and Nth-1.
++
++ If --packet is used for a counter than
++ there must be Nth number of --packet
++ rules, covering all values between 0 and
++ Nth-1 inclusively.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP6_NF_MATCH_RANDOM
++ tristate 'Random match support'
++ depends on IP6_NF_IPTABLES
++ help
++ This option adds a `random' match,
++ which allow you to match packets randomly
++ following a given probability.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
++config IP6_NF_TARGET_ROUTE
++ tristate ' ROUTE target support'
++ depends on IP6_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. The ROUTE target is also able to change the incoming interface
++ of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ Not working as a module.
++
++config IP6_NF_TARGET_TRACE
++ tristate 'TRACE target support'
++ depends on IP6_NF_RAW
++ help
++ The TRACE target allows packets to be traced as those
++ matches any subsequent rule in any table/rule. The matched
++ rule and the packet is logged with the prefix
++
++ TRACE: tablename/chainname/rulenum
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++config IP6_NF_MATCH_POLICY
++ tristate "IPsec policy match support"
++ depends on IP6_NF_IPTABLES && XFRM
++ help
++ Policy matching allows you to match packets based on the
++ IPsec policy that was used during decapsulation/will
++ be used during encapsulation.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ endmenu
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/Makefile linux-2.6.7-rc3/net/ipv6/netfilter/Makefile
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/Makefile 2004-06-07 21:14:33.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/Makefile 2004-06-08 10:42:36.000000000 +0200
+@@ -8,18 +8,28 @@
+ 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
+ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
+ obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
++obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
+ obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
+ obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
+ obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
+ 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_ROUTE) += ip6t_ROUTE.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_RANDOM) += ip6t_random.o
++
++obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
++obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
+ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
++obj-$(CONFIG_IP6_NF_TARGET_TRACE) += ip6t_TRACE.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6_tables.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6_tables.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6_tables.c 2004-06-07 21:14:58.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6_tables.c 2004-06-08 10:37:30.000000000 +0200
+@@ -38,6 +38,14 @@
+ #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
+ #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
+
++static const char *hook6names[] = {
++ [NF_IP6_PRE_ROUTING] "PREROUTING",
++ [NF_IP6_LOCAL_IN] "INPUT",
++ [NF_IP6_FORWARD] "FORWARD",
++ [NF_IP6_LOCAL_OUT] "OUTPUT",
++ [NF_IP6_POST_ROUTING] "POSTROUTING",
++};
++
+ /*#define DEBUG_IP_FIREWALL*/
+ /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
+ /*#define DEBUG_IP_FIREWALL_USER*/
+@@ -406,6 +414,12 @@
+
+ t = ip6t_get_target(e);
+ IP_NF_ASSERT(t->u.kernel.target);
++
++ /* The packet traced and the rule isn't an unconditional return/END. */
++ if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) {
++ nf_log_packet(PF_INET6, hook, *pskb, in, out, "TRACE: %s/%s/%u ",
++ table->name, e->chainname, e->rulenum);
++ }
+ /* Standard target? */
+ if (!t->u.kernel.target->target) {
+ int v;
+@@ -559,6 +573,29 @@
+ return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
+ }
+
++static inline int
++find_error_target(struct ip6t_entry *s,
++ struct ip6t_entry *e,
++ char **chainname)
++{
++ struct ip6t_entry_target *t;
++ static struct ip6t_entry *found = NULL;
++
++ if (s == e) {
++ if (!found)
++ return 0;
++ t = ip6t_get_target(found);
++ if (strcmp(t->u.user.name,
++ IP6T_ERROR_TARGET) == 0) {
++ *chainname = t->data;
++ return 1;
++ }
++ } else
++ found = s;
++
++ return 0;
++}
++
+ /* All zeroes == unconditional rule. */
+ static inline int
+ unconditional(const struct ip6t_ip6 *ipv6)
+@@ -578,6 +615,8 @@
+ mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
+ {
+ unsigned int hook;
++ char *chainname = NULL;
++ u_int32_t rulenum;
+
+ /* No recursion; use packet counter to save back ptrs (reset
+ to 0 as we leave), and comefrom to save source hook bitmask */
+@@ -591,6 +630,8 @@
+
+ /* Set initial back pointer. */
+ e->counters.pcnt = pos;
++ rulenum = 1;
++ chainname = (char *) hook6names[hook];
+
+ for (;;) {
+ struct ip6t_standard_target *t
+@@ -603,6 +644,8 @@
+ }
+ e->comefrom
+ |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
++ e->rulenum = rulenum++;
++ e->chainname = chainname;
+
+ /* Unconditional return/END. */
+ if (e->target_offset == sizeof(struct ip6t_entry)
+@@ -612,6 +655,10 @@
+ && unconditional(&e->ipv6)) {
+ unsigned int oldpos, size;
+
++ /* Set unconditional rulenum to zero. */
++ e->rulenum = 0;
++ e->counters.bcnt = 0;
++
+ /* Return: backtrack through the last
+ big jump. */
+ do {
+@@ -637,6 +684,11 @@
+ (newinfo->entries + pos);
+ } while (oldpos == pos + e->next_offset);
+
++ /* Restore chainname, rulenum. */
++ chainname = e->chainname;
++ rulenum = e->counters.bcnt;
++ e->counters.bcnt = 0;
++
+ /* Move along one */
+ size = e->next_offset;
+ e = (struct ip6t_entry *)
+@@ -652,6 +704,17 @@
+ /* This a jump; chase it. */
+ duprintf("Jump rule %u -> %u\n",
+ pos, newpos);
++ e->counters.bcnt = rulenum++;
++ rulenum = 1;
++ e = (struct ip6t_entry *)
++ (newinfo->entries + newpos);
++ if (IP6T_ENTRY_ITERATE(newinfo->entries,
++ newinfo->size,
++ find_error_target,
++ e, &chainname) == 0) {
++ printk("ip6_tables: table screwed up!\n");
++ return 0;
++ }
+ } else {
+ /* ... this is a fallthru */
+ newpos = pos + e->next_offset;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_HL.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_HL.c 2004-06-08 10:31:03.000000000 +0200
+@@ -0,0 +1,105 @@
++/*
++ * Hop Limit modification target for ip6tables
++ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
++ * Based on HW's TTL module
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_HL.h>
++
++MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
++MODULE_DESCRIPTION("IP tables Hop Limit modification module");
++MODULE_LICENSE("GPL");
++
++static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
++ const struct net_device *in, const struct net_device *out,
++ const void *targinfo, void *userinfo)
++{
++ struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
++ const struct ip6t_HL_info *info = targinfo;
++ u_int16_t diffs[2];
++ int new_hl;
++
++ switch (info->mode) {
++ case IP6T_HL_SET:
++ new_hl = info->hop_limit;
++ break;
++ case IP6T_HL_INC:
++ new_hl = ip6h->hop_limit + info->hop_limit;
++ if (new_hl > 255)
++ new_hl = 255;
++ break;
++ case IP6T_HL_DEC:
++ new_hl = ip6h->hop_limit + info->hop_limit;
++ if (new_hl < 0)
++ new_hl = 0;
++ break;
++ default:
++ new_hl = ip6h->hop_limit;
++ break;
++ }
++
++ if (new_hl != ip6h->hop_limit) {
++ diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
++ ip6h->hop_limit = new_hl;
++ diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
++ }
++
++ return IP6T_CONTINUE;
++}
++
++static int ip6t_hl_checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ip6t_HL_info *info = targinfo;
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
++ printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
++ targinfosize,
++ IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ if (info->mode > IP6T_HL_MAXMODE) {
++ printk(KERN_WARNING "HL: invalid or unknown Mode %u\n",
++ info->mode);
++ return 0;
++ }
++
++ if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
++ printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL",
++ ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ip6t_register_target(&ip6t_HL);
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_HL);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_REJECT.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_REJECT.c 2004-06-08 10:31:20.000000000 +0200
+@@ -0,0 +1,458 @@
++/*
++ * IP6 tables REJECT target module
++ * Linux INET6 implementation
++ *
++ * Copyright (C)2003 USAGI/WIDE Project
++ *
++ * Authors:
++ * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
++ *
++ * Based on net/ipv4/netfilter/ipt_REJECT.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/icmpv6.h>
++#include <net/ipv6.h>
++#include <net/tcp.h>
++#include <net/icmp.h>
++#include <net/ip6_fib.h>
++#include <net/ip6_route.h>
++#include <net/flow.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_REJECT.h>
++
++MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
++MODULE_DESCRIPTION("IP6 tables REJECT target module");
++MODULE_LICENSE("GPL");
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#if 0
++static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
++{
++ void (*attach)(struct sk_buff *, struct nf_ct_info *);
++ if (nfct && (attach = ip6_ct_attach) != NULL) {
++ mb();
++ attach(new_skb, nfct);
++ }
++}
++#endif
++
++static int maybe_reroute(struct sk_buff *skb)
++{
++ if (skb->nfcache & NFC_ALTERED){
++ if (ip6_route_me_harder(skb) != 0){
++ kfree_skb(skb);
++ return -EINVAL;
++ }
++ }
++
++ return dst_output(skb);
++}
++
++/* Send RST reply */
++static void send_reset(struct sk_buff *oldskb)
++{
++ struct sk_buff *nskb;
++ struct tcphdr otcph, *tcph;
++ unsigned int otcplen, tcphoff, hh_len;
++ int needs_ack;
++ struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
++ struct dst_entry *dst = NULL;
++ u8 proto;
++ struct flowi fl;
++ proto = oip6h->nexthdr;
++ int err;
++
++ if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
++ (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
++ DEBUGP("ip6t_REJECT: addr is not unicast.\n");
++ return;
++ }
++
++ tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
++ &proto, oldskb->len - ((u8*)(oip6h+1)
++ - oldskb->data));
++
++ if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
++ DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
++ return;
++ }
++
++ otcplen = oldskb->len - tcphoff;
++
++ /* IP header checks: fragment, too short. */
++ if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
++ DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
++ proto, otcplen);
++ return;
++ }
++
++ if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: Can't copy tcp header\n");
++ return;
++ }
++
++ /* No RST for RST. */
++ if (otcph.rst) {
++ DEBUGP("ip6t_REJECT: RST is set\n");
++ return;
++ }
++
++ /* Check checksum. */
++ if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
++ skb_checksum(oldskb, tcphoff, otcplen, 0))) {
++ DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
++ return;
++ }
++
++ memset(&fl, 0, sizeof(fl));
++ fl.proto = IPPROTO_TCP;
++ ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
++ ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
++ fl.fl_ip_sport = otcph.dest;
++ fl.fl_ip_dport = otcph.source;
++ err = ip6_dst_lookup(NULL, &dst, &fl);
++ if (err) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: can't find dst. err = %d\n", err);
++ return;
++ }
++
++ hh_len = (dst->dev->hard_header_len + 15)&~15;
++ nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
++ + sizeof(struct tcphdr) + dst->trailer_len,
++ GFP_ATOMIC);
++
++ if (!nskb) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: Can't alloc skb\n");
++ dst_release(dst);
++ return;
++ }
++
++ nskb->dst = dst;
++ dst_hold(dst);
++
++ skb_reserve(nskb, hh_len + dst->header_len);
++
++ ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
++ skb_put(nskb, sizeof(struct ipv6hdr));
++ ip6h->version = 6;
++ ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
++ ip6h->nexthdr = IPPROTO_TCP;
++ ip6h->payload_len = htons(sizeof(struct tcphdr));
++ ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
++ ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
++
++ tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
++ /* Truncate to length (no data) */
++ tcph->doff = sizeof(struct tcphdr)/4;
++ tcph->source = otcph.dest;
++ tcph->dest = otcph.source;
++
++ if (otcph.ack) {
++ needs_ack = 0;
++ tcph->seq = otcph.ack_seq;
++ tcph->ack_seq = 0;
++ } else {
++ needs_ack = 1;
++ tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
++ + otcplen - (otcph.doff<<2));
++ tcph->seq = 0;
++ }
++
++ /* Reset flags */
++ ((u_int8_t *)tcph)[13] = 0;
++ tcph->rst = 1;
++ tcph->ack = needs_ack;
++ tcph->window = 0;
++ tcph->urg_ptr = 0;
++ tcph->check = 0;
++
++ /* Adjust TCP checksum */
++ tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
++ &nskb->nh.ipv6h->daddr,
++ sizeof(struct tcphdr), IPPROTO_TCP,
++ csum_partial((char *)tcph,
++ sizeof(struct tcphdr), 0));
++
++#if 0
++ connection_attach(nskb, oldskb->nfct);
++#endif
++
++ NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++ maybe_reroute);
++
++ dst_release(dst);
++}
++
++static void send_unreach(struct sk_buff *skb_in, unsigned char code)
++{
++ struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
++ struct icmp6hdr *icmp6h;
++ struct dst_entry *dst = NULL;
++ struct rt6_info *rt;
++ int tmo;
++ __u32 csum;
++ unsigned int len, datalen, hh_len;
++ int saddr_type, daddr_type;
++ unsigned int ptr, ip6off;
++ u8 proto;
++ struct flowi fl;
++ struct sk_buff *nskb;
++ char *data;
++
++ saddr_type = ipv6_addr_type(&hdr->saddr);
++ daddr_type = ipv6_addr_type(&hdr->daddr);
++
++ if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
++ (!(daddr_type & IPV6_ADDR_UNICAST))) {
++ DEBUGP("ip6t_REJECT: addr is not unicast.\n");
++ return;
++ }
++
++ ip6off = skb_in->nh.raw - skb_in->data;
++ proto = hdr->nexthdr;
++ ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
++ skb_in->len - ip6off);
++
++ if ((ptr < 0) || (ptr > skb_in->len)) {
++ ptr = ip6off + sizeof(struct ipv6hdr);
++ proto = hdr->nexthdr;
++ } else if (proto == IPPROTO_ICMPV6) {
++ u8 type;
++
++ if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
++ icmp6_type), &type, 1)) {
++ DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
++ return;
++ }
++
++ if (!(type & ICMPV6_INFOMSG_MASK)) {
++ DEBUGP("ip6t_REJECT: no reply to icmp error\n");
++ return;
++ }
++ } else if (proto == IPPROTO_UDP) {
++ int plen = skb_in->len - (ptr - ip6off);
++ uint16_t check;
++
++ if (plen < sizeof(struct udphdr)) {
++ DEBUGP("ip6t_REJECT: too short\n");
++ return;
++ }
++
++ if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
++ &check, 2)) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: can't get copy from skb");
++ return;
++ }
++
++ if (check &&
++ csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
++ IPPROTO_UDP,
++ skb_checksum(skb_in, ptr, plen, 0))) {
++ DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
++ return;
++ }
++ }
++
++ memset(&fl, 0, sizeof(fl));
++ fl.proto = IPPROTO_ICMPV6;
++ ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
++ ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
++ fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
++ fl.fl_icmp_code = code;
++
++ if (ip6_dst_lookup(NULL, &dst, &fl)) {
++ return;
++ }
++
++ rt = (struct rt6_info *)dst;
++ tmo = 1*HZ;
++
++ if (rt->rt6i_dst.plen < 128)
++ tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
++
++ if (!xrlim_allow(dst, tmo)) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: rate limitted\n");
++ goto dst_release_out;
++ }
++
++ len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
++
++ if (len > dst_pmtu(dst))
++ len = dst_pmtu(dst);
++ if (len > IPV6_MIN_MTU)
++ len = IPV6_MIN_MTU;
++
++ datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
++ hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
++
++ nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
++ GFP_ATOMIC);
++
++ if (!nskb) {
++ if (net_ratelimit())
++ printk("ip6t_REJECT: can't alloc skb\n");
++ goto dst_release_out;
++ }
++
++ nskb->priority = 0;
++ nskb->dst = dst;
++ dst_hold(dst);
++
++ skb_reserve(nskb, hh_len + dst->header_len);
++
++ ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
++ skb_put(nskb, sizeof(struct ipv6hdr));
++ ip6h->version = 6;
++ ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
++ ip6h->nexthdr = IPPROTO_ICMPV6;
++ ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
++ ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
++ ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
++
++ icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
++ icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
++ icmp6h->icmp6_code = code;
++ icmp6h->icmp6_cksum = 0;
++
++ data = skb_put(nskb, datalen);
++
++ csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
++ csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
++ icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
++ datalen + sizeof(struct icmp6hdr),
++ IPPROTO_ICMPV6, csum);
++
++#if 0
++ connection_attach(nskb, skb_in->nfct);
++#endif
++ NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
++ maybe_reroute);
++
++dst_release_out:
++ dst_release(dst);
++}
++
++static unsigned int reject6_target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ip6t_reject_info *reject = targinfo;
++
++ DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
++ /* WARNING: This code causes reentry within ip6tables.
++ This means that the ip6tables jump stack is now crap. We
++ must return an absolute verdict. --RR */
++ switch (reject->with) {
++ case IP6T_ICMP6_NO_ROUTE:
++ send_unreach(*pskb, ICMPV6_NOROUTE);
++ break;
++ case IP6T_ICMP6_ADM_PROHIBITED:
++ send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
++ break;
++ case IP6T_ICMP6_NOT_NEIGHBOUR:
++ send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
++ break;
++ case IP6T_ICMP6_ADDR_UNREACH:
++ send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
++ break;
++ case IP6T_ICMP6_PORT_UNREACH:
++ send_unreach(*pskb, ICMPV6_PORT_UNREACH);
++ break;
++ case IP6T_ICMP6_ECHOREPLY:
++ /* Do nothing */
++ break;
++ case IP6T_TCP_RESET:
++ send_reset(*pskb);
++ break;
++ default:
++ if (net_ratelimit())
++ printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
++ break;
++ }
++
++ return NF_DROP;
++}
++
++static int check(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ const struct ip6t_reject_info *rejinfo = targinfo;
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
++ DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
++ return 0;
++ }
++
++ /* Only allow these for packet filtering. */
++ if (strcmp(tablename, "filter") != 0) {
++ DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
++ return 0;
++ }
++
++ if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
++ | (1 << NF_IP6_FORWARD)
++ | (1 << NF_IP6_LOCAL_OUT))) != 0) {
++ DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
++ return 0;
++ }
++
++ if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
++ printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
++ return 0;
++ } else if (rejinfo->with == IP6T_TCP_RESET) {
++ /* Must specify that it's a TCP packet */
++ if (e->ipv6.proto != IPPROTO_TCP
++ || (e->ipv6.invflags & IP6T_INV_PROTO)) {
++ DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_reject_reg = {
++ .name = "REJECT",
++ .target = reject6_target,
++ .checkentry = check,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ip6t_register_target(&ip6t_reject_reg))
++ return -EINVAL;
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_reject_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_ROUTE.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_ROUTE.c 2004-06-08 10:37:08.000000000 +0200
+@@ -0,0 +1,289 @@
++/*
++ * This implements the ROUTE v6 target, which enables you to setup unusual
++ * routes not supported by the standard kernel routing table.
++ *
++ * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * v 1.0 2003/08/05
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ipv6.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
++#include <linux/netdevice.h>
++#include <net/ipv6.h>
++#include <net/ndisc.h>
++#include <net/ip6_route.h>
++#include <linux/icmpv6.h>
++
++#if 1
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define NIP6(addr) \
++ ntohs((addr).s6_addr16[0]), \
++ ntohs((addr).s6_addr16[1]), \
++ ntohs((addr).s6_addr16[2]), \
++ ntohs((addr).s6_addr16[3]), \
++ ntohs((addr).s6_addr16[4]), \
++ ntohs((addr).s6_addr16[5]), \
++ ntohs((addr).s6_addr16[6]), \
++ ntohs((addr).s6_addr16[7])
++
++/* Route the packet according to the routing keys specified in
++ * route_info. Keys are :
++ * - ifindex :
++ * 0 if no oif preferred,
++ * otherwise set to the index of the desired oif
++ * - route_info->gw :
++ * 0 if no gateway specified,
++ * otherwise set to the next host to which the pkt must be routed
++ * If success, skb->dev is the output device to which the packet must
++ * be sent and skb->dst is not NULL
++ *
++ * RETURN: 1 if the packet was succesfully routed to the
++ * destination desired
++ * 0 if the kernel routing table could not route the packet
++ * according to the keys specified
++ */
++static int
++route6(struct sk_buff *skb,
++ unsigned int ifindex,
++ const struct ip6t_route_target_info *route_info)
++{
++ struct rt6_info *rt = NULL;
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++
++ DEBUGP("ip6t_ROUTE: called with: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
++ DEBUGP("OUT=%s\n", route_info->oif);
++
++ if (ipv6_addr_any(gw))
++ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
++ else
++ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
++
++ if (!rt)
++ goto no_route;
++
++ DEBUGP("ip6t_ROUTE: routing gives: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
++ DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
++
++ if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
++ goto wrong_route;
++
++ if (!rt->rt6i_nexthop) {
++ DEBUGP("ip6t_ROUTE: discovering neighbour\n");
++ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++ skb->dev = rt->rt6i_dev;
++ return 1;
++
++ wrong_route:
++ dst_release(&rt->u.dst);
++ no_route:
++ if (!net_ratelimit())
++ return 0;
++
++ printk("ip6t_ROUTE: no explicit route found ");
++ if (ifindex)
++ printk("via interface %s ", route_info->oif);
++ if (!ipv6_addr_any(gw))
++ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
++ printk("\n");
++ return 0;
++}
++
++
++/* Stolen from ip6_output_finish
++ * PRE : skb->dev is set to the device we are leaving by
++ * skb->dst is not NULL
++ * POST: the packet is sent with the link layer header pushed
++ * the packet is destroyed
++ */
++static void ip_direct_send(struct sk_buff *skb)
++{
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++
++ if (hh) {
++ read_lock_bh(&hh->hh_lock);
++ memcpy(skb->data - 16, hh->hh_data, 16);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
++}
++
++
++static unsigned int
++route6_oif(const struct ip6t_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++ else
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ if (route6(skb, ifindex, route_info)) {
++ dev_put(dev_out);
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
++}
++
++
++static unsigned int
++route6_gw(const struct ip6t_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ if (route6(skb, 0, route_info)) {
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
++}
++
++
++static unsigned int
++ip6t_route_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_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ goto do_it;
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP6_PRE_ROUTING ||
++ hooknum == NF_IP6_LOCAL_IN) {
++
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++
++ if (ipv6h->hop_limit <= 1) {
++ /* Force OUTPUT device used as source address */
++ skb->dev = skb->dst->dev;
++
++ icmpv6_send(skb, ICMPV6_TIME_EXCEED,
++ ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
++
++ return NF_DROP;
++ }
++
++ ipv6h->hop_limit--;
++ }
++
++
++ do_it:
++ if (route_info->oif[0])
++ return route6_oif(route_info, *pskb);
++
++ if (!ipv6_addr_any(gw))
++ return route6_gw(route_info, *pskb);
++
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
++
++ return IP6T_CONTINUE;
++}
++
++
++static int
++ip6t_route_checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
++ return 0;
++ }
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
++ printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static struct ip6t_target ip6t_route_reg = {
++ .name = "ROUTE",
++ .target = ip6t_route_target,
++ .checkentry = ip6t_route_checkentry,
++ .me = THIS_MODULE
++};
++
++
++static int __init init(void)
++{
++ printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
++ if (ip6t_register_target(&ip6t_route_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_route_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_TRACE.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_TRACE.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_TRACE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_TRACE.c 2004-06-08 10:37:30.000000000 +0200
+@@ -0,0 +1,65 @@
++/* This is a module which is used for setting
++ * the NFC_TRACE flag in the nfcache field of an skb.
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv6/ip6_tables.h>
++
++MODULE_LICENSE("GPL");
++
++static unsigned int
++target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ (*pskb)->nfcache |= NFC_TRACE;
++ return IP6T_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (targinfosize != 0) {
++ printk(KERN_WARNING "TRACE: targinfosize %u != 0\n",
++ targinfosize);
++ return 0;
++ }
++
++ if (strcmp(tablename, "raw") != 0) {
++ printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_trace_reg = {
++ .name = "TRACE",
++ .target = target,
++ .checkentry = checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ip6t_register_target(&ip6t_trace_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_trace_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_fuzzy.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_fuzzy.c 2004-06-08 10:31:37.000000000 +0200
+@@ -0,0 +1,189 @@
++/*
++ * This module implements a simple TSK FLC
++ * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
++ * to limit , in an adaptive and flexible way , the packet rate crossing
++ * a given stream . It serves as an initial and very simple (but effective)
++ * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
++ * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
++ * into our code in a precise , adaptive and efficient manner.
++ * The goal is very similar to that of "limit" match , but using techniques of
++ * Fuzzy Control , that allow us to shape the transfer functions precisely ,
++ * avoiding over and undershoots - and stuff like that .
++ *
++ *
++ * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
++ * 2002-08-17 : Changed to eliminate floating point operations .
++ * 2002-08-23 : Coding style changes .
++ * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ipv6.h>
++#include <linux/random.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
++
++/*
++ Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
++ Expressed in percentage
++*/
++
++#define PAR_LOW 1/100
++#define PAR_HIGH 1
++
++static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
++
++MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
++MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
++MODULE_LICENSE("GPL");
++
++static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++ if (tx >= maxi) return 100;
++
++ if (tx <= mini) return 0;
++
++ return ((100 * (tx-mini)) / (maxi-mini));
++}
++
++static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
++{
++ if (tx <= mini) return 100;
++
++ if (tx >= maxi) return 0;
++
++ return ((100 * (maxi - tx)) / (maxi - mini));
++
++}
++
++static int
++ip6t_fuzzy_match(const struct sk_buff *pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ /* From userspace */
++
++ struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
++
++ u_int8_t random_number;
++ unsigned long amount;
++ u_int8_t howhigh, howlow;
++
++
++ spin_lock_bh(&fuzzy_lock); /* Rise the lock */
++
++ info->bytes_total += pskb->len;
++ info->packets_total++;
++
++ info->present_time = jiffies;
++
++ if (info->present_time >= info->previous_time)
++ amount = info->present_time - info->previous_time;
++ else {
++ /* There was a transition : I choose to re-sample
++ and keep the old acceptance rate...
++ */
++
++ amount = 0;
++ info->previous_time = info->present_time;
++ info->bytes_total = info->packets_total = 0;
++ };
++
++ if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
++
++ info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
++ / amount);
++
++ info->previous_time = info->present_time;
++ info->bytes_total = info->packets_total = 0;
++
++ howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
++ howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
++
++ info->acceptance_rate = (u_int8_t) \
++ (howhigh * PAR_LOW + PAR_HIGH * howlow);
++
++ /* In fact, the above defuzzification would require a denominator
++ * proportional to (howhigh+howlow) but, in this particular case,
++ * that expression is constant.
++ * An imediate consequence is that it is not necessary to call
++ * both mf_high and mf_low - but to keep things understandable,
++ * I did so.
++ */
++
++ }
++
++ spin_unlock_bh(&fuzzy_lock); /* Release the lock */
++
++
++ if (info->acceptance_rate < 100)
++ {
++ get_random_bytes((void *)(&random_number), 1);
++
++ /* If within the acceptance , it can pass => don't match */
++ if (random_number <= (255 * info->acceptance_rate) / 100)
++ return 0;
++ else
++ return 1; /* It can't pass (It matches) */
++ };
++
++ return 0; /* acceptance_rate == 100 % => Everything passes ... */
++
++}
++
++static int
++ip6t_fuzzy_checkentry(const char *tablename,
++ const struct ip6t_ip6 *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++
++ const struct ip6t_fuzzy_info *info = matchinfo;
++
++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
++ printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
++ IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
++ return 0;
++ }
++
++ if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
++ || (info->minimum_rate >= info->maximum_rate)) {
++ printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_match ip6t_fuzzy_reg = {
++ {NULL, NULL},
++ "fuzzy",
++ ip6t_fuzzy_match,
++ ip6t_fuzzy_checkentry,
++ NULL,
++ THIS_MODULE };
++
++static int __init init(void)
++{
++ if (ip6t_register_match(&ip6t_fuzzy_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_match(&ip6t_fuzzy_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_nth.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_nth.c 2004-06-08 10:31:42.000000000 +0200
+@@ -0,0 +1,173 @@
++/*
++ This is a module which is used for match support for every Nth packet
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from:
++ ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++ 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++ 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
++ * added support for multiple counters
++ * added support for matching on individual packets
++ in the counter cycle
++ 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
++
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_nth.h>
++
++MODULE_LICENSE("GPL");
++
++/*
++ * State information.
++ */
++struct state {
++ spinlock_t lock;
++ u_int16_t number;
++};
++
++static struct state states[IP6T_NTH_NUM_COUNTERS];
++
++static int
++ip6t_nth_match(const struct sk_buff *pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ /* Parameters from userspace */
++ const struct ip6t_nth_info *info = matchinfo;
++ unsigned counter = info->counter;
++ if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
++ {
++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
++ return 0;
++ };
++
++ spin_lock(&states[counter].lock);
++
++ /* Are we matching every nth packet?*/
++ if (info->packet == 0xFF)
++ {
++ /* We're matching every nth packet and only every nth packet*/
++ /* Do we match or invert match? */
++ if (info->not == 0)
++ {
++ if (states[counter].number == 0)
++ {
++ ++states[counter].number;
++ goto match;
++ }
++ if (states[counter].number >= info->every)
++ states[counter].number = 0; /* reset the counter */
++ else
++ ++states[counter].number;
++ goto dontmatch;
++ }
++ else
++ {
++ if (states[counter].number == 0)
++ {
++ ++states[counter].number;
++ goto dontmatch;
++ }
++ if (states[counter].number >= info->every)
++ states[counter].number = 0;
++ else
++ ++states[counter].number;
++ goto match;
++ }
++ }
++ else
++ {
++ /* We're using the --packet, so there must be a rule for every value */
++ if (states[counter].number == info->packet)
++ {
++ /* only increment the counter when a match happens */
++ if (states[counter].number >= info->every)
++ states[counter].number = 0; /* reset the counter */
++ else
++ ++states[counter].number;
++ goto match;
++ }
++ else
++ goto dontmatch;
++ }
++
++ dontmatch:
++ /* don't match */
++ spin_unlock(&states[counter].lock);
++ return 0;
++
++ match:
++ spin_unlock(&states[counter].lock);
++ return 1;
++}
++
++static int
++ip6t_nth_checkentry(const char *tablename,
++ const struct ip6t_ip6 *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Parameters from userspace */
++ const struct ip6t_nth_info *info = matchinfo;
++ unsigned counter = info->counter;
++ if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
++ {
++ printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
++ return 0;
++ };
++
++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
++ printk("nth: matchsize %u != %u\n", matchsize,
++ IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
++ return 0;
++ }
++
++ states[counter].number = info->startat;
++
++ return 1;
++}
++
++static struct ip6t_match ip6t_nth_reg = {
++ {NULL, NULL},
++ "nth",
++ ip6t_nth_match,
++ ip6t_nth_checkentry,
++ NULL,
++ THIS_MODULE };
++
++static int __init init(void)
++{
++ unsigned counter;
++ memset(&states, 0, sizeof(states));
++ if (ip6t_register_match(&ip6t_nth_reg))
++ return -EINVAL;
++
++ for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++)
++ {
++ spin_lock_init(&(states[counter].lock));
++ };
++
++ printk("ip6t_nth match loaded\n");
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_match(&ip6t_nth_reg);
++ printk("ip6t_nth match unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_owner.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_owner.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_owner.c 2004-06-07 21:14:56.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_owner.c 2004-06-08 10:40:01.000000000 +0200
+@@ -21,6 +21,39 @@
+ MODULE_LICENSE("GPL");
+
+ static int
++match_comm(const struct sk_buff *skb, const char *comm)
++{
++ struct task_struct *p, *g;
++ struct files_struct *files;
++ int i;
++
++ read_lock(&tasklist_lock);
++ do_each_thread(g, p) {
++ if(strncmp(p->comm, comm, sizeof(p->comm)))
++ continue;
++
++ task_lock(p);
++ files = p->files;
++ if(files) {
++ read_lock(&files->file_lock);
++ for (i=0; i < files->max_fds; i++) {
++ if (fcheck_files(files, i) ==
++ skb->sk->sk_socket->file) {
++ read_unlock(&files->file_lock);
++ task_unlock(p);
++ read_unlock(&tasklist_lock);
++ return 1;
++ }
++ }
++ read_unlock(&files->file_lock);
++ }
++ task_unlock(p);
++ } while_each_thread(g, p);
++ read_unlock(&tasklist_lock);
++ return 0;
++}
++
++static int
+ match_pid(const struct sk_buff *skb, pid_t pid)
+ {
+ struct task_struct *p;
+@@ -125,6 +158,12 @@
+ return 0;
+ }
+
++ if(info->match & IP6T_OWNER_COMM) {
++ if (!match_comm(skb, info->comm) ^
++ !!(info->invert & IP6T_OWNER_COMM))
++ return 0;
++ }
++
+ return 1;
+ }
+
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_policy.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_policy.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_policy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_policy.c 2004-06-08 10:42:36.000000000 +0200
+@@ -0,0 +1,201 @@
++/* IP tables module for matching IPsec policy
++ *
++ * Copyright (c) 2004 Patrick McHardy, <kaber@trash.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <net/xfrm.h>
++
++#include <linux/netfilter_ipv6.h>
++#include <linux/netfilter_ipv6/ip6t_policy.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++
++MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
++MODULE_DESCRIPTION("IPtables IPsec policy matching module");
++MODULE_LICENSE("GPL");
++
++
++static inline int ip6_masked_addrcmp(struct in6_addr addr1,
++ struct in6_addr mask,
++ struct in6_addr addr2)
++{
++ int i;
++
++ for (i = 0; i < 16; i++) {
++ if ((addr1.s6_addr[i] & mask.s6_addr[i]) !=
++ (addr2.s6_addr[i] & mask.s6_addr[i]))
++ return 1;
++ }
++ return 0;
++}
++
++
++static inline int
++match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
++{
++#define MISMATCH(x,y) (e->match.x && ((e->x != (y)) ^ e->invert.x))
++
++ struct in6_addr xfrm_saddr, xfrm_daddr;
++
++ if ((e->match.saddr
++ && (ip6_masked_addrcmp(xfrm_saddr, e->saddr, e->smask))
++ ^ e->invert.saddr ) ||
++ (e->match.daddr
++ && (ip6_masked_addrcmp(xfrm_daddr, e->daddr, e->dmask))
++ ^ e->invert.daddr ) ||
++ MISMATCH(proto, x->id.proto) ||
++ MISMATCH(mode, x->props.mode) ||
++ MISMATCH(spi, x->id.spi) ||
++ MISMATCH(reqid, x->props.reqid))
++ return 0;
++ return 1;
++}
++
++static int
++match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
++{
++ const struct ip6t_policy_elem *e;
++ struct sec_path *sp = skb->sp;
++ int strict = info->flags & POLICY_MATCH_STRICT;
++ int i, pos;
++
++ if (sp == NULL)
++ return -1;
++ if (strict && info->len != sp->len)
++ return 0;
++
++ for (i = sp->len - 1; i >= 0; i--) {
++ pos = strict ? i - sp->len + 1 : 0;
++ if (pos >= info->len)
++ return 0;
++ e = &info->pol[pos];
++
++ if (match_xfrm_state(sp->x[i].xvec, e)) {
++ if (!strict)
++ return 1;
++ } else if (strict)
++ return 0;
++ }
++
++ return strict ? 1 : 0;
++}
++
++static int
++match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
++{
++ const struct ip6t_policy_elem *e;
++ struct dst_entry *dst = skb->dst;
++ int strict = info->flags & POLICY_MATCH_STRICT;
++ int i, pos;
++
++ if (dst->xfrm == NULL)
++ return -1;
++
++ for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
++ pos = strict ? i : 0;
++ if (pos >= info->len)
++ return 0;
++ e = &info->pol[pos];
++
++ if (match_xfrm_state(dst->xfrm, e)) {
++ if (!strict)
++ return 1;
++ } else if (strict)
++ return 0;
++ }
++
++ return strict ? 1 : 0;
++}
++
++static int match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ip6t_policy_info *info = matchinfo;
++ int ret;
++
++ if (info->flags & POLICY_MATCH_IN)
++ ret = match_policy_in(skb, info);
++ else
++ ret = match_policy_out(skb, info);
++
++ if (ret < 0) {
++ if (info->flags & POLICY_MATCH_NONE)
++ ret = 1;
++ else
++ ret = 0;
++ } else if (info->flags & POLICY_MATCH_NONE)
++ ret = 0;
++
++ return ret;
++}
++
++static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
++ void *matchinfo, unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ip6t_policy_info *info = matchinfo;
++
++ if (matchsize != IP6T_ALIGN(sizeof(*info))) {
++ printk(KERN_ERR "ip6t_policy: matchsize %u != %u\n",
++ matchsize, IP6T_ALIGN(sizeof(*info)));
++ return 0;
++ }
++ if (!(info->flags & (POLICY_MATCH_IN|POLICY_MATCH_OUT))) {
++ printk(KERN_ERR "ip6t_policy: neither incoming nor "
++ "outgoing policy selected\n");
++ return 0;
++ }
++ if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
++ && info->flags & POLICY_MATCH_OUT) {
++ printk(KERN_ERR "ip6t_policy: output policy not valid in "
++ "PRE_ROUTING and INPUT\n");
++ return 0;
++ }
++ if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
++ && info->flags & POLICY_MATCH_IN) {
++ printk(KERN_ERR "ip6t_policy: input policy not valid in "
++ "POST_ROUTING and OUTPUT\n");
++ return 0;
++ }
++ if (info->len > POLICY_MAX_ELEM) {
++ printk(KERN_ERR "ip6t_policy: too many policy elements\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_match policy_match =
++{
++ .name = "policy",
++ .match = match,
++ .checkentry = checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ return ip6t_register_match(&policy_match);
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_match(&policy_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_random.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_random.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6t_random.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6t_random.c 2004-06-08 10:31:56.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ This is a module which is used for a "random" match support.
++ 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-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
++ 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
++*/
++
++#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_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_random.h>
++
++MODULE_LICENSE("GPL");
++
++static int
++ip6t_rand_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_rand_info *info = matchinfo;
++ u_int8_t random_number;
++
++ /* get 1 random number from the kernel random number generation routine */
++ get_random_bytes((void *)(&random_number), 1);
++
++ /* Do we match ? */
++ if (random_number <= info->average)
++ return 1;
++ else
++ return 0;
++}
++
++static int
++ip6t_rand_checkentry(const char *tablename,
++ const struct ip6t_ip6 *e,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Parameters from userspace */
++ const struct ip6t_rand_info *info = matchinfo;
++
++ if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) {
++ printk("ip6t_random: matchsize %u != %u\n", matchsize,
++ IP6T_ALIGN(sizeof(struct ip6t_rand_info)));
++ return 0;
++ }
++
++ /* must be 1 <= average % <= 99 */
++ /* 1 x 2.55 = 2 */
++ /* 99 x 2.55 = 252 */
++ if ((info->average < 2) || (info->average > 252)) {
++ printk("ip6t_random: invalid average %u\n", info->average);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_match ip6t_rand_reg = {
++ {NULL, NULL},
++ "random",
++ ip6t_rand_match,
++ ip6t_rand_checkentry,
++ NULL,
++ THIS_MODULE };
++
++static int __init init(void)
++{
++ if (ip6t_register_match(&ip6t_rand_reg))
++ return -EINVAL;
++
++ printk("ip6t_random match loaded\n");
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_match(&ip6t_rand_reg);
++ printk("ip6t_random match unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_filter.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_filter.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_filter.c 2004-06-07 21:13:37.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_filter.c 2004-06-08 10:37:30.000000000 +0200
+@@ -58,7 +58,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+@@ -66,7 +66,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -74,7 +74,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } }
+ },
+@@ -83,7 +83,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_mangle.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_mangle.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_mangle.c 2004-06-07 21:14:05.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_mangle.c 2004-06-08 10:37:30.000000000 +0200
+@@ -73,7 +73,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_IN */
+@@ -81,7 +81,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* FORWARD */
+@@ -89,7 +89,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -97,7 +97,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* POST_ROUTING */
+@@ -105,7 +105,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } }
+ },
+@@ -114,7 +114,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_raw.c
+--- linux-2.6.7-rc3.org/net/ipv6/netfilter/ip6table_raw.c 2004-06-07 21:14:43.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/netfilter/ip6table_raw.c 2004-06-08 10:37:30.000000000 +0200
+@@ -52,7 +52,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ /* LOCAL_OUT */
+@@ -60,7 +60,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_standard),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+ -NF_ACCEPT - 1 } },
+ },
+@@ -69,7 +69,7 @@
+ 0,
+ sizeof(struct ip6t_entry),
+ sizeof(struct ip6t_error),
+- 0, { 0, 0 }, { } },
++ 0, NULL, 0, { 0, 0 }, { } },
+ { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
+ { } },
+ "ERROR"
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/ipv6/sit.c linux-2.6.7-rc3/net/ipv6/sit.c
+--- linux-2.6.7-rc3.org/net/ipv6/sit.c 2004-06-07 21:14:59.000000000 +0200
++++ linux-2.6.7-rc3/net/ipv6/sit.c 2004-06-08 10:30:55.000000000 +0200
+@@ -388,13 +388,7 @@
+ skb->dev = tunnel->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+ ipip6_ecn_decapsulate(iph, skb);
+ netif_rx(skb);
+ read_unlock(&ipip6_lock);
+@@ -580,13 +574,7 @@
+ if ((iph->ttl = tiph->ttl) == 0)
+ iph->ttl = iph6->hop_limit;
+
+-#ifdef CONFIG_NETFILTER
+- nf_conntrack_put(skb->nfct);
+- skb->nfct = NULL;
+-#ifdef CONFIG_NETFILTER_DEBUG
+- skb->nf_debug = 0;
+-#endif
+-#endif
++ nf_reset(skb);
+
+ IPTUNNEL_XMIT();
+ tunnel->recursion--;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/xfrm/xfrm_input.c linux-2.6.7-rc3/net/xfrm/xfrm_input.c
+--- linux-2.6.7-rc3.org/net/xfrm/xfrm_input.c 2004-06-07 21:13:35.000000000 +0200
++++ linux-2.6.7-rc3/net/xfrm/xfrm_input.c 2004-06-08 10:38:44.000000000 +0200
+@@ -29,6 +29,9 @@
+ if (!sp)
+ return NULL;
+
++#ifdef CONFIG_NETFILTER
++ sp->decap_done = 0;
++#endif
+ sp->len = 0;
+ if (src) {
+ int i;
+diff -Nur --exclude '*.orig' linux-2.6.7-rc3.org/net/xfrm/xfrm_policy.c linux-2.6.7-rc3/net/xfrm/xfrm_policy.c
+--- linux-2.6.7-rc3.org/net/xfrm/xfrm_policy.c 2004-06-07 21:14:24.000000000 +0200
++++ linux-2.6.7-rc3/net/xfrm/xfrm_policy.c 2004-06-08 10:38:46.000000000 +0200
+@@ -21,6 +21,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/notifier.h>
+ #include <linux/netdevice.h>
++#include <linux/netfilter.h>
+ #include <net/xfrm.h>
+ #include <net/ip.h>
+
+@@ -911,6 +912,7 @@
+
+ if (_decode_session(skb, &fl, family) < 0)
+ return 0;
++ nf_nat_decode_session(skb, &fl, family);
+
+ /* First, check used SA against their selectors. */
+ if (skb->sp) {