[netfilter-cvslog] r3260 - in trunk/patch-o-matic-ng/nf_conntrack:
. linux-2.6/include/linux/netfilter
linux-2.6/include/linux/netfilter_ipv4
linux-2.6/include/linux/netfilter_ipv6
linux-2.6/net/ipv4/netfilter linux-2.6/net/ipv6/netfilter
linux-2.6/net/netfilter
yasuyuki at netfilter.org
yasuyuki at netfilter.org
Mon Nov 1 08:39:00 CET 2004
Author: yasuyuki at netfilter.org
Date: 2004-11-01 08:38:59 +0100 (Mon, 01 Nov 2004)
New Revision: 3260
Added:
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_sctp.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_reasm.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_l3proto_generic.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_sctp.c
Removed:
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_frag6.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Makefile.ladd
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Kconfig.ladd
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Makefile.ladd
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_frag6.c
Modified:
trunk/patch-o-matic-ng/nf_conntrack/help
trunk/patch-o-matic-ng/nf_conntrack/info
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6.patch
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_core.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_l3proto.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_protocol.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tcp.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tuple.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_icmp.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_ipv4.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_icmpv6.h
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Kconfig
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Makefile
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_core.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_ftp.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_generic.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_tcp.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_udp.c
trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_standalone.c
Log:
- synchronized nf_conntrack with ip_conntrack in linux 2.6.10-rc1.
- deleted the processing which re-allocate conntrack from BASIC slab cache
and destroys HELPER slab cache when unloading all helper modules. All slab
caches are destroyed when unloading nf_conntrack.ko.
- re-implemented handling fragmented IPv6 packets.
Modified: trunk/patch-o-matic-ng/nf_conntrack/help
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/help 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/help 2004-11-01 07:38:59 UTC (rev 3260)
@@ -6,15 +6,15 @@
Note:
The new IPv4 connection tracking module (nf_conntrack_ipv4) cannot
work with ip_conntrack. If you want to try nf_conntrack_ipv4,
- please check off "Connection tracking (required for masq/NAT)".
+ please unload ip_conntrack.
On the other hand, you can use new IPv6 connection tracking module
(nf_conntrack_ipv6) with ip_conntrack.
TODO:
- allocate conntrack with various size dependent on features. (done)
- - handling fragmented packets (done)
- - getorigdst() (is this needed ?)
- - backport recent fixes to ip_conntrack. (done (from linux 2.4.7)).
+ - handling fragmented packets (implemented, but under discussion again)
+ - getorigdst() (done)
+ - backport recent fixes to ip_conntrack. (done (from linux 2.6.10-rc1)).
- wrapper for current ip_conntrack and ip_nat
- matches and targets working with connection tracking
Modified: trunk/patch-o-matic-ng/nf_conntrack/info
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/info 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/info 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,5 +1,5 @@
Author: Yasuyuki KOZAKAI @ USAGI/WIDE Project <yasuyuki.kozakai at toshiba.co.jp>
Status: Testing
Repository: extra
-Requires: linux >= 2.6.7
+Requires: linux >= 2.6.10-rc1
Recompile: kernel
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -63,15 +63,15 @@
#include <linux/netfilter/nf_conntrack_tcp.h>
#include <linux/netfilter_ipv4/nf_conntrack_icmp.h>
#include <linux/netfilter_ipv6/nf_conntrack_icmpv6.h>
-#include <linux/netfilter_ipv6/nf_conntrack_frag6.h>
+#include <linux/netfilter/nf_conntrack_sctp.h>
/* per conntrack: protocol private data */
union nf_conntrack_proto {
/* insert conntrack proto private data here */
+ struct nf_ct_sctp sctp;
struct nf_ct_tcp tcp;
struct nf_ct_icmp icmp;
struct nf_ct_icmpv6 icmpv6;
- struct nf_ct_frag6 frag6;
};
union nf_conntrack_expect_proto {
@@ -104,7 +104,7 @@
#include <linux/types.h>
#include <linux/skbuff.h>
-#ifdef CONFIG_NF_DEBUG
+#ifdef CONFIG_NETFILTER_DEBUG
#define NF_CT_ASSERT(x) \
do { \
if (!(x)) \
@@ -157,6 +157,12 @@
union nf_conntrack_expect_help help;
};
+struct nf_conntrack_counter
+{
+ u_int64_t packets;
+ u_int64_t bytes;
+};
+
struct nf_conntrack_helper;
#include <linux/netfilter_ipv4/nf_conntrack_ipv4.h>
@@ -166,6 +172,7 @@
plus 1 for any connection(s) we are `master' for */
struct nf_conntrack ct_general;
+ /* XXX should I move this to the tail ? - Y.K */
/* These are my tuples; original and reply */
struct nf_conntrack_tuple_hash tuplehash[NF_CT_DIR_MAX];
@@ -175,6 +182,11 @@
/* Timer function; drops refcnt when it goes off. */
struct timer_list timeout;
+#ifdef CONFIG_NF_CT_ACCT
+ /* Accounting Information (same cache line as other written members) */
+ struct nf_conntrack_counter counters[NF_CT_DIR_MAX];
+#endif
+
/* If we're expecting another related connection, this will be
in expected linked list */
struct list_head sibling_list;
@@ -188,10 +200,6 @@
/* Helper. if any */
struct nf_conntrack_helper *helper;
- /* Our various nf_ct_info structs specify *what* relation this
- packet has to the conntrack */
- struct nf_ct_info infos[NF_CT_NUMBER];
-
/* features - nat, helper, ... used by allocating system */
u_int32_t features;
@@ -199,6 +207,10 @@
union nf_conntrack_proto proto;
+#if defined(CONFIG_NF_CONNTRACK_MARK)
+ unsigned long mark;
+#endif
+
/* These members are dynamically allocated. */
union nf_conntrack_help *help;
@@ -226,8 +238,12 @@
const struct nf_conn *ignored_conntrack);
/* Return conntrack_info and tuple hash for given skb. */
-extern struct nf_conn *
-nf_ct_get(struct sk_buff *skb, enum nf_conntrack_info *ctinfo);
+static inline struct nf_conn *
+nf_ct_get(struct sk_buff *skb, enum nf_conntrack_info *ctinfo)
+{
+ *ctinfo = skb->nfctinfo;
+ return (struct nf_conn *)skb->nfct;
+}
/* decrement reference count on a conntrack */
extern inline void nf_ct_put(struct nf_conn *ct);
@@ -246,8 +262,10 @@
const struct nf_conntrack_tuple *orig);
/* Refresh conntrack for this many jiffies */
-extern void nf_ct_refresh(struct nf_conn *ct,
- unsigned long extra_jiffies);
+extern void nf_ct_refresh_acct(struct nf_conn *ct,
+ enum nf_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ unsigned long extra_jiffies);
/* These are for NAT. Icky. */
/* Call me when a conntrack is destroyed. */
@@ -256,9 +274,7 @@
/* Fake conntrack entry for untracked connections */
extern struct nf_conn nf_conntrack_untracked;
-/* Returns new sk_buff, or NULL */
-struct sk_buff *
-nf_ct_gather_frags(struct sk_buff *skb);
+extern int nf_ct_no_defrag;
/* Delete all conntracks which match. */
extern void
@@ -273,6 +289,27 @@
extern unsigned int nf_conntrack_htable_size;
+struct nf_conntrack_stat
+{
+ unsigned int searched;
+ unsigned int found;
+ unsigned int new;
+ unsigned int invalid;
+ unsigned int ignore;
+ unsigned int delete;
+ unsigned int delete_list;
+ unsigned int insert;
+ unsigned int insert_failed;
+ unsigned int drop;
+ unsigned int early_drop;
+ unsigned int error;
+ unsigned int expect_new;
+ unsigned int expect_create;
+ unsigned int expect_delete;
+};
+
+#define NF_CT_STAT_INC(count) (__get_cpu_var(nf_conntrack_stat).count++)
+
/* eg. PROVIDES_CONNTRACK(ftp); */
#define PROVIDES_CONNTRACK(name) \
int needs_nf_conntrack_##name; \
@@ -293,9 +330,7 @@
extern int
nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size,
- int (*init_conntrack)(struct nf_conn *, u_int32_t),
- int (*copy_conntrack)(struct nf_conn *,
- const struct nf_conn *));
+ int (*init_conntrack)(struct nf_conn *, u_int32_t));
extern void
nf_conntrack_unregister_cache(u_int32_t features);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_core.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_core.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_core.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -23,14 +23,6 @@
extern int nf_conntrack_init(void);
extern void nf_conntrack_cleanup(void);
-struct nf_conntrack_protocol;
-extern struct nf_conntrack_protocol *
-nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol);
-
-/* Like above, but you already have conntrack read lock. */
-extern struct nf_conntrack_protocol *
-__nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol);
-
extern struct list_head protocol_list;
struct nf_conntrack_l3proto;
@@ -39,6 +31,8 @@
extern struct nf_conntrack_l3proto *__nf_ct_find_l3proto(u_int16_t l3proto);
extern struct list_head l3proto_list;
+struct nf_conntrack_protocol;
+
extern int nf_ct_get_tuple(const struct sk_buff *skb,
unsigned int nhoff,
unsigned int dataoff,
@@ -58,9 +52,18 @@
nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
+extern int __nf_conntrack_confirm(struct sk_buff *skb);
+
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
-extern int nf_conntrack_confirm(struct sk_buff *skb);
+static inline int nf_conntrack_confirm(struct sk_buff *skb)
+{
+ if (skb->nfct
+ && !is_confirmed((struct nf_conn *)skb->nfct))
+ return __nf_conntrack_confirm(skb);
+ return NF_ACCEPT;
+}
+
extern struct list_head *nf_conntrack_hash;
extern struct list_head nf_conntrack_expect_list;
DECLARE_RWLOCK_EXTERN(nf_conntrack_lock);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_l3proto.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_l3proto.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_l3proto.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -26,6 +26,7 @@
/* Header for use in defining a given L3 protocol for connection tracking. */
#ifndef _NF_CONNTRACK_L3PROTO_H
#define _NF_CONNTRACK_L3PROTO_H
+#include <linux/seq_file.h>
#include <linux/netfilter/nf_conntrack.h>
struct nf_conntrack_l3proto
@@ -39,12 +40,6 @@
/* Protocol name */
const char *name;
- /* Initialization. ex) register hooks */
- int (*init)(void);
-
- /* Finalization. ex) unregister hooks */
- void (*fini)(void);
-
/*
* Try to fill in the third arg: nhoff is offset of l3 proto
* hdr. Return true if possible.
@@ -60,12 +55,11 @@
const struct nf_conntrack_tuple *orig);
/* Print out the per-protocol part of the tuple. */
- unsigned int (*print_tuple)(char *buffer,
- const struct nf_conntrack_tuple *);
+ int (*print_tuple)(struct seq_file *s,
+ const struct nf_conntrack_tuple *);
/* Print out the private part of the conntrack. */
- unsigned int (*print_conntrack)(char *buffer,
- const struct nf_conn *);
+ int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
/* Returns verdict for packet, or -1 for invalid. */
int (*packet)(struct nf_conn *conntrack,
@@ -95,11 +89,20 @@
struct module *me;
};
+extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX];
+
/* Protocol registration. */
extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+static inline struct nf_conntrack_l3proto *
+nf_ct_find_l3proto(u_int16_t l3proto)
+{
+ return nf_ct_l3protos[l3proto];
+}
+
/* Existing built-in protocols */
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
+extern struct nf_conntrack_l3proto nf_conntrack_generic_l3proto;
#endif /*_NF_CONNTRACK_L3PROTO_H*/
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_protocol.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_protocol.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_protocol.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -14,6 +14,8 @@
#define _NF_CONNTRACK_PROTOCOL_H
#include <linux/netfilter/nf_conntrack.h>
+struct seq_file;
+
struct nf_conntrack_protocol
{
/* Next pointer. */
@@ -31,8 +33,8 @@
/* Try to fill in the third arg: dataoff is offset past NF
hdr. Return true if possible. */
int (*pkt_to_tuple)(const struct sk_buff *skb,
- unsigned int dataoff,
- struct nf_conntrack_tuple *tuple);
+ unsigned int dataoff,
+ struct nf_conntrack_tuple *tuple);
/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
* Some packets can't be inverted: return 0 in that case.
@@ -40,19 +42,19 @@
int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
- /* Print out the per-protocol part of the tuple. */
- unsigned int (*print_tuple)(char *buffer,
- const struct nf_conntrack_tuple *);
+ /* Print out the per-protocol part of the tuple. Return like seq_* */
+ int (*print_tuple)(struct seq_file *s,
+ const struct nf_conntrack_tuple *);
/* Print out the private part of the conntrack. */
- unsigned int (*print_conntrack)(char *buffer,
- const struct nf_conn *);
+ int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
/* Returns verdict for packet, or -1 for invalid. */
int (*packet)(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff,
enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum);
/* Called when a new connection for this protocol found;
@@ -68,15 +70,44 @@
const struct sk_buff *skb,
unsigned int dataoff);
+ int (*error)(struct sk_buff *skb, unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf, unsigned int hooknum);
+
/* Module (if any) which this is connected to. */
struct module *me;
};
+/* Existing built-in protocols */
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
+extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
+
+#define MAX_NF_CT_PROTO 256
+extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
+
+extern struct nf_conntrack_protocol *
+nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol);
+
/* Protocol registration. */
extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto);
extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto);
-/* Existing built-in protocols */
-extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp;
-extern struct nf_conntrack_protocol nf_conntrack_protocol_udp;
+/* Log invalid packets */
+extern unsigned int nf_ct_log_invalid;
+
+#ifdef CONFIG_SYSCTL
+#ifdef DEBUG_INVALID_PACKETS
+#define LOG_INVALID(proto) \
+ (nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW)
+#else
+#define LOG_INVALID(proto) \
+ ((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \
+ && net_ratelimit())
+#endif
+#else
+#define LOG_INVALID(proto) 0
+#endif /* CONFIG_SYSCTL */
+
#endif /*_NF_CONNTRACK_PROTOCOL_H*/
Added: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_sctp.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_sctp.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_sctp.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -0,0 +1,25 @@
+#ifndef _NF_CONNTRACK_SCTP_H
+#define _NF_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 nf_ct_sctp
+{
+ enum sctp_conntrack state;
+
+ u_int32_t vtag[NF_CT_DIR_MAX];
+ u_int32_t ttag[NF_CT_DIR_MAX];
+};
+
+#endif /* _NF_CONNTRACK_SCTP_H */
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tcp.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tcp.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tcp.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -15,25 +15,50 @@
enum tcp_conntrack {
TCP_CONNTRACK_NONE,
- TCP_CONNTRACK_ESTABLISHED,
TCP_CONNTRACK_SYN_SENT,
TCP_CONNTRACK_SYN_RECV,
+ TCP_CONNTRACK_ESTABLISHED,
TCP_CONNTRACK_FIN_WAIT,
+ TCP_CONNTRACK_CLOSE_WAIT,
+ TCP_CONNTRACK_LAST_ACK,
TCP_CONNTRACK_TIME_WAIT,
TCP_CONNTRACK_CLOSE,
- TCP_CONNTRACK_CLOSE_WAIT,
- TCP_CONNTRACK_LAST_ACK,
TCP_CONNTRACK_LISTEN,
- TCP_CONNTRACK_MAX
+ TCP_CONNTRACK_MAX,
+ TCP_CONNTRACK_IGNORE
};
+/* Window scaling is advertised by the sender */
+#define NF_CT_TCP_STATE_FLAG_WINDOW_SCALE 0x01
+
+/* SACK is permitted by the sender */
+#define NF_CT_TCP_FLAG_SACK_PERM 0x02
+
+struct nf_ct_tcp_state {
+ u_int32_t td_end; /* max of seq + len */
+ u_int32_t td_maxend; /* max of ack + max(win, 1) */
+ u_int32_t td_maxwin; /* max(win) */
+ u_int8_t td_scale; /* window scale factor */
+ u_int8_t loose; /* used when connection picked up from the middle */
+ u_int8_t flags; /* per direction state flags */
+ };
+
struct nf_ct_tcp
{
- enum tcp_conntrack state;
-
- /* Poor man's window tracking: sequence number of valid ACK
- handshake completion packet */
- u_int32_t handshake_ack;
+ struct nf_ct_tcp_state seen[2]; /* connection parameters per direction */
+ u_int8_t state; /* state of the connection (enum tcp_conntrack) */
+ /* For detecting stale connections */
+ u_int8_t last_dir; /* Direction of the last packet (enum nf_conntrack_dir) */
+ u_int8_t retrans; /* Number of retransmitted packets */
+ u_int8_t last_index; /* Index of the last packet */
+ u_int32_t last_seq; /* Last sequence number seen in dir */
+ u_int32_t last_end; /* Last seq + len */
};
+/* Update TCP window tracking data when NAT mangles the packet */
+extern int nf_conntrack_tcp_update(struct sk_buff *skb,
+ unsigned int dataoff,
+ struct nf_conn *conntrack,
+ int dir);
+
#endif /* _NF_CONNTRACK_TCP_H */
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tuple.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tuple.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter/nf_conntrack_tuple.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -47,8 +47,8 @@
u_int16_t id;
} icmp;
struct {
- u_int32_t id;
- } frag6;
+ u_int16_t port;
+ } sctp;
};
/* The manipulable part of the tuple. */
@@ -86,8 +86,8 @@
u_int8_t type, code;
} icmp;
struct {
- u_int16_t orig;
- } frag6;
+ u_int16_t port;
+ } sctp;
} u;
/* The protocol. */
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_icmp.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_icmp.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_icmp.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -20,5 +20,4 @@
atomic_t count;
};
-extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
#endif /* _NF_CONNTRACK_ICMP_H */
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_ipv4.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_ipv4.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv4/nf_conntrack_ipv4.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -35,4 +35,8 @@
#endif
};
+/* Returns new sk_buff, or NULL */
+struct sk_buff *
+nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
+
#endif /*_NF_CONNTRACK_IPV4_H*/
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_frag6.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_frag6.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_frag6.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,53 +0,0 @@
-/*
- * nf_conntrack_frag6.h
- *
- * Definitions and Declarations for Fragment Header tracking.
- *
- * Derived from include/linux/netfiter_ipv4/ip_conntrack_frag6.h
- *
- * 16 Dec 2003: Yasuyuki Kozakai @ USAGI <yasuyuki.kozakai at toshiba.co.jp>
- * - enable working with L3 protocol independent connection tracking.
- */
-
-#ifndef _NF_CONNTRACK_FRAG6_H
-#define _NF_CONNTRACK_FRAG6_H
-/* Fragment Header tracking. */
-
-/* used by last_in */
-#define NF_CT_FRAG6_FIRST_IN 1 /* first fragment is already received */
-#define NF_CT_FRAG6_LAST_IN 2 /* last fragment is already received */
-#define NF_CT_FRAG6_COMPLETE 4 /* no need to wait fragments any more */
-
-struct nf_ct_frag6
-{
- /* fragmented packets */
- struct sk_buff *fragments;
- struct sk_buff *orig_list;
-
- /* protect fragments list */
- spinlock_t lock;
-
- /* reassembled packet */
- struct sk_buff *reasm;
- int len;
- int meat;
- int iif;
- struct timeval stamp;
- unsigned int csum;
- __u8 last_in;
-};
-
-/* get reassembled packet */
-extern struct sk_buff *nf_ct_frag6_get_reasm(const struct sk_buff *skb);
-
-/* pass the reserved fragmented packets to next hook */
-extern unsigned int
-nf_ct_frag6_confirm(struct sk_buff *skb);
-
-extern unsigned int
-nf_ct_frag6_reinject(unsigned int hooknum, struct sk_buff *skb,
- struct net_device *in, struct net_device *out,
- int (*okfn)(struct sk_buff *));
-
-extern struct nf_conntrack_protocol nf_conntrack_protocol_frag6;
-#endif /* _NF_CONNTRACK_FRAG6_H */
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_icmpv6.h
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_icmpv6.h 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/include/linux/netfilter_ipv6/nf_conntrack_icmpv6.h 2004-11-01 07:38:59 UTC (rev 3260)
@@ -15,10 +15,10 @@
#include <asm/atomic.h>
#ifndef ICMPV6_NI_QUERY
-#define ICMPV6_NI_QUERY 139
+#define ICMPV6_NI_QUERY 139
#endif
#ifndef ICMPV6_NI_REPLY
-#define ICMPV6_NI_REPLY 140
+#define ICMPV6_NI_REPLY 140
#endif
struct nf_ct_icmpv6
@@ -27,5 +27,4 @@
atomic_t count;
};
-extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6;
#endif /* _NF_CONNTRACK_ICMPV6_H */
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Kconfig.ladd 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Kconfig.ladd 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,29 +0,0 @@
-config NF_CONNTRACK_IPV4
- tristate "IPv4 support on new connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL && !IP_NF_CONNTRACK
- select NF_CONNTRACK
- ---help---
- Connection tracking keeps a record of what packets have passed
- through your machine, in order to figure out how they are related
- into connections.
-
- This is IPv4 support on Layer 3 independent connection tracking.
- Layer 3 independent connection tracking is experimental scheme
- which generalize ip_conntrack to support other layer 3 protocols.
-
- To compile it as a module, choose M here. If unsure, say N.
-
-config NF_CONNTRACK_IPV4_FTP
- tristate "FTP support on new connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK_IPV4
- select NF_CONNTRACK_FTP
- help
- Tracking FTP connections is problematic: special helpers are
- required for tracking them, and doing masquerading and other forms
- of Network Address Translation on them.
-
- This is FTP support on Layer 3 independent connection tracking.
- Layer 3 independent connection tracking is experimental scheme
- which generalize ip_conntrack to support other layer 3 protocols.
-
- To compile it as a module, choose M here. If unsure, say N.
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Makefile.ladd
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Makefile.ladd 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/Makefile.ladd 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,7 +0,0 @@
-obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
-
-# objects for l3 independent conntrack
-nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
-
-# l3 independent conntrack
-obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -28,7 +28,7 @@
#include <linux/netfilter/nf_conntrack_protocol.h>
#include <linux/netfilter/nf_conntrack_l3proto.h>
#include <linux/netfilter/nf_conntrack_core.h>
-#include <linux/netfilter_ipv4/nf_conntrack_icmp.h>
+#include <linux/netfilter_ipv4/nf_conntrack_ipv4.h>
#if 0
#define DEBUGP printk
@@ -36,10 +36,11 @@
#define DEBUGP(format, args...)
#endif
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
-
if (skb_copy_bits(skb, nhoff + offsetof(struct iphdr, saddr),
&tuple->src.u3.ip, sizeof(tuple->src.u3.ip)))
return 0;
@@ -60,31 +61,36 @@
return 1;
}
-static unsigned int
-ipv4_print_tuple(char *buffer, const struct nf_conntrack_tuple *tuple)
+static int ipv4_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- int len;
-
- len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
- NIPQUAD(tuple->src.u3.ip), NIPQUAD(tuple->dst.u3.ip));
-
- return len;
+ return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
+ NIPQUAD(tuple->src.u3.ip),
+ NIPQUAD(tuple->dst.u3.ip));
}
-static unsigned int
-ipv4_print_conntrack(char *buffer, const struct nf_conn *conntrack)
+static int ipv4_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
return 0;
}
+static int nf_ct_ipv4_no_defrag;
+
/* Returns new sk_buff, or NULL */
-struct sk_buff *
-ip_ct_gather_frags(struct sk_buff *skb)
+static struct sk_buff *
+nf_ct_ipv4_gather_frags(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
#ifdef CONFIG_NETFILTER_DEBUG
unsigned int olddebug = skb->nf_debug;
#endif
+
+ if (unlikely(nf_ct_ipv4_no_defrag)) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
if (sk) {
sock_hold(sk);
skb_orphan(skb);
@@ -114,100 +120,16 @@
return skb;
}
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
-/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
-struct nf_conn *
-icmp_error_track(struct sk_buff *skb,
- enum nf_conntrack_info *ctinfo,
- unsigned int hooknum)
-{
- struct nf_conntrack_tuple innertuple, origtuple;
- struct {
- struct icmphdr icmp;
- struct iphdr ip;
- } inside;
- struct nf_conntrack_protocol *innerproto;
- struct nf_conntrack_tuple_hash *h;
- int dataoff;
-
- NF_CT_ASSERT(skb->nfct == NULL);
-
- /* Not enough header? */
- if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
- return NULL;
-
- if (inside.icmp.type != ICMP_DEST_UNREACH
- && inside.icmp.type != ICMP_SOURCE_QUENCH
- && inside.icmp.type != ICMP_TIME_EXCEEDED
- && inside.icmp.type != ICMP_PARAMETERPROB
- && inside.icmp.type != ICMP_REDIRECT)
- return NULL;
-
- /* Ignore ICMP's containing fragments (shouldn't happen) */
- if (inside.ip.frag_off & htons(IP_OFFSET)) {
- DEBUGP("icmp_error_track: fragment of proto %u\n",
- inside.ip.protocol);
- return NULL;
- }
-
- innerproto = nf_ct_find_proto(PF_INET, inside.ip.protocol);
- dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp);
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside.ip.ihl*4, PF_INET,
- inside.ip.protocol, &origtuple,
- &nf_conntrack_l3proto_ipv4, innerproto)) {
- DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
- return NULL;
- }
-
- /* Ordinarily, we'd expect the inverted tupleproto, but it's
- been preserved inside the ICMP. */
- if (!nf_ct_invert_tuple(&innertuple, &origtuple,
- &nf_conntrack_l3proto_ipv4, innerproto)) {
- DEBUGP("icmp_error_track: Can't invert tuple\n");
- return NULL;
- }
-
- *ctinfo = NF_CT_RELATED;
-
- h = nf_conntrack_find_get(&innertuple, NULL);
- if (!h) {
- /* Locally generated ICMPs will match inverted if they
- haven't been SNAT'ed yet */
- /* FIXME: NAT code has to handle half-done double NAT --RR */
- if (hooknum == NF_IP_LOCAL_OUT)
- h = nf_conntrack_find_get(&origtuple, NULL);
-
- if (!h) {
- DEBUGP("icmp_error_track: no match\n");
- return NULL;
- }
- /* Reverse direction from that found */
- if (NF_CT_DIRECTION(h) != NF_CT_DIR_REPLY)
- *ctinfo += NF_CT_IS_REPLY;
- } else {
- if (NF_CT_DIRECTION(h) == NF_CT_DIR_REPLY)
- *ctinfo += NF_CT_IS_REPLY;
- }
-
- /* Update skb to refer to this connection */
- skb->nfct = &h->ctrack->infos[*ctinfo];
- return h->ctrack;
-}
-
static int
ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
u_int8_t *protonum, int *ret)
{
- enum nf_conntrack_info ctinfo;
-
/* Never happen */
if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
(*pskb)->nh.iph->protocol, hooknum);
}
-
*ret = NF_DROP;
return 0;
}
@@ -215,20 +137,6 @@
/* FIXME: Do this right please. --RR */
(*pskb)->nfcache |= NFC_UNKNOWN;
- /* Previously seen (loopback or untracked)? Ignore. */
- if ((*pskb)->nfct) {
- DEBUGP("loopback or untracked, nfct=0x%p\n", (*pskb)->nfct);
- *ret = NF_ACCEPT;
- return 0;
- }
-
- /* It may be an icmp error... */
- if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
- && icmp_error_track(*pskb, &ctinfo, hooknum)) {
- *ret = NF_ACCEPT;
- return 0;
- }
-
*dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4;
*protonum = (*pskb)->nh.iph->protocol;
@@ -245,10 +153,10 @@
}
static unsigned int ipv4_confirm(unsigned int hooknum,
- struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
{
/* We've seen it coming out the other side: confirm it */
DEBUGP("ipv4_confirm\n");
@@ -256,10 +164,10 @@
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
- struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
{
/* Previously seen (loopback)? Ignore. Do this before
fragment check. */
@@ -269,7 +177,7 @@
/* Gather fragments. */
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
- *pskb = ip_ct_gather_frags(*pskb);
+ *pskb = nf_ct_ipv4_gather_frags(*pskb);
if (!*pskb)
return NF_STOLEN;
}
@@ -293,7 +201,8 @@
/* Local packets are never produced too large for their
interface. We degfragment them at LOCAL_OUT, however,
so we have to refragment them here. */
- if ((*pskb)->len > dst_pmtu(&rt->u.dst)) {
+ if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
+ !skb_shinfo(*pskb)->tso_size) {
/* No hook can be after us, so this should be OK. */
ip_fragment(*pskb, okfn);
return NF_STOLEN;
@@ -346,6 +255,14 @@
.priority = NF_IP_PRI_CONNTRACK,
};
+static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
+ .hook = ipv4_conntrack_defrag,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_IP_LOCAL_OUT,
+ .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
+};
+
static struct nf_hook_ops ipv4_conntrack_local_out_ops = {
.hook = ipv4_conntrack_local,
.owner = THIS_MODULE,
@@ -363,14 +280,6 @@
.priority = NF_IP_PRI_LAST,
};
-static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
- .hook = ipv4_conntrack_defrag,
- .owner = THIS_MODULE,
- .pf = PF_INET,
- .hooknum = NF_IP_LOCAL_OUT,
- .priority = NF_IP_PRI_CONNTRACK_DEFRAG,
-};
-
static struct nf_hook_ops ipv4_conntrack_local_in_ops = {
.hook = ipv4_confirm,
.owner = THIS_MODULE,
@@ -416,8 +325,8 @@
{ .ctl_name = 0 }
};
#endif
-/* Fast function for those who don't want to parse /proc (and I don't
+/* Fast function for those who don't want to parse /proc (and I don't
blame them). */
/* Reversing the socket's dst/src point of view gives us the reply
mapping. */
@@ -480,49 +389,61 @@
.get = &getorigdst,
};
-static struct nf_conntrack_protocol tcp, udp, icmp;
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
+ .l3proto = PF_INET,
+ .name = "ipv4",
+ .pkt_to_tuple = ipv4_pkt_to_tuple,
+ .invert_tuple = ipv4_invert_tuple,
+ .print_tuple = ipv4_print_tuple,
+ .print_conntrack = ipv4_print_conntrack,
+ .prepare = ipv4_prepare,
+ .get_features = ipv4_get_features,
+ .me = THIS_MODULE,
+};
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
static int init_or_cleanup(int init)
{
int ret = 0;
- struct nf_conntrack_protocol *proto;
if (!init) goto cleanup;
ret = nf_register_sockopt(&so_getorigdst);
- if (ret != 0) {
+ if (ret < 0) {
printk(KERN_ERR "Unable to register netfilter socket option\n");
goto cleanup_nothing;
}
- memcpy(&tcp, &nf_conntrack_protocol_tcp, sizeof(tcp));
- tcp.l3proto = PF_INET;
- ret = nf_conntrack_protocol_register(&tcp);
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register tcp.\n");
goto cleanup_sockopt;
}
- memcpy(&udp, &nf_conntrack_protocol_udp, sizeof(udp));
- udp.l3proto = PF_INET;
- ret = nf_conntrack_protocol_register(&udp);
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register udp.\n");
goto cleanup_tcp;
}
- memcpy(&icmp, &nf_conntrack_protocol_icmp, sizeof(icmp));
- icmp.l3proto = PF_INET;
- ret = nf_conntrack_protocol_register(&icmp);
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register icmp.\n");
goto cleanup_udp;
}
+ ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
+ if (ret < 0) {
+ printk("nf_conntrack_ipv4: can't register ipv4\n");
+ goto cleanup_icmp;
+ }
+
ret = nf_register_hook(&ipv4_conntrack_defrag_ops);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n");
- goto cleanup_icmp;
+ goto cleanup_ipv4;
}
ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops);
if (ret < 0) {
@@ -565,13 +486,11 @@
return ret;
-
cleanup:
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
-#endif
-
cleanup_localinops:
+#endif
nf_unregister_hook(&ipv4_conntrack_local_in_ops);
cleanup_inoutandlocalops:
nf_unregister_hook(&ipv4_conntrack_out_ops);
@@ -582,81 +501,42 @@
cleanup_defraglocalops:
nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops);
cleanup_defragops:
+ /* Frag queues may hold fragments with skb->dst == NULL */
+ nf_ct_ipv4_no_defrag = 1;
+ synchronize_net();
+ local_bh_disable();
+ ipfrag_flush();
+ local_bh_enable();
nf_unregister_hook(&ipv4_conntrack_defrag_ops);
+ cleanup_ipv4:
+ nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
cleanup_icmp:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET, IPPROTO_ICMP);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
cleanup_udp:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET, IPPROTO_UDP);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
cleanup_tcp:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET, IPPROTO_TCP);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
cleanup_sockopt:
nf_unregister_sockopt(&so_getorigdst);
cleanup_nothing:
return ret;
}
-static int ipv4_init(void)
-{
- need_nf_conntrack();
- return init_or_cleanup(1);
-}
-
-static void ipv4_fini(void)
-{
- init_or_cleanup(0);
-}
-
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
- { NULL, NULL }, /* list */
- PF_INET, /* l3proto */
- "ipv4", /* name */
- ipv4_init, /* init */
- ipv4_fini, /* fini */
- ipv4_pkt_to_tuple, /* pkt_to_tuple */
- ipv4_invert_tuple, /* invert_tuple */
- ipv4_print_tuple, /* print_tuple */
- ipv4_print_conntrack, /* print_conntrack */
- NULL, /* packet */
- NULL, /* new */
- NULL, /* destroy */
- ipv4_prepare, /* prepare */
- ipv4_get_features, /* get_features */
- THIS_MODULE /* me */
-};
-
MODULE_LICENSE("GPL");
static int __init init(void)
{
- int ret;
-
need_nf_conntrack();
- ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
- if (ret < 0) {
- printk("nf_conntrack_ipv4: can't register l3 proto module\n");
- }
- return ret;
+ return init_or_cleanup(1);
}
static void __exit fini(void)
{
- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
+ init_or_cleanup(0);
}
module_init(init);
module_exit(fini);
PROVIDES_CONNTRACK(ipv4);
-EXPORT_SYMBOL(ip_ct_gather_frags);
+EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv4/netfilter/nf_conntrack_proto_icmp.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -15,12 +15,16 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/timer.h>
-#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/in.h>
#include <linux/icmp.h>
+#include <linux/seq_file.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/nf_conntrack_tuple.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
+#include <linux/netfilter/nf_conntrack_core.h>
unsigned long nf_ct_icmp_timeout = 30*HZ;
@@ -34,14 +38,15 @@
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
- struct icmphdr hdr;
+ struct icmphdr _hdr, *hp;
- if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0)
+ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
return 0;
- tuple->dst.u.icmp.type = hdr.type;
- tuple->src.u.icmp.id = hdr.un.echo.id;
- tuple->dst.u.icmp.code = hdr.code;
+ tuple->dst.u.icmp.type = hp->type;
+ tuple->src.u.icmp.id = hp->un.echo.id;
+ tuple->dst.u.icmp.code = hp->code;
return 1;
}
@@ -71,18 +76,18 @@
}
/* Print out the per-protocol part of the tuple. */
-static unsigned int icmp_print_tuple(char *buffer,
- const struct nf_conntrack_tuple *tuple)
+static int icmp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return sprintf(buffer, "type=%u code=%u id=%u ",
- tuple->dst.u.icmp.type,
- tuple->dst.u.icmp.code,
- ntohs(tuple->src.u.icmp.id));
+ return seq_printf(s, "type=%u code=%u id=%u ",
+ tuple->dst.u.icmp.type,
+ tuple->dst.u.icmp.code,
+ ntohs(tuple->src.u.icmp.id));
}
/* Print out the private part of the conntrack. */
-static unsigned int icmp_print_conntrack(char *buffer,
- const struct nf_conn *conntrack)
+static int icmp_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
return 0;
}
@@ -92,6 +97,7 @@
const struct sk_buff *skb,
unsigned int dataoff,
enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum)
{
/* Try to delete connection immediately after all replies:
@@ -104,7 +110,7 @@
ct->timeout.function((unsigned long)ct);
} else {
atomic_inc(&ct->proto.icmp.count);
- nf_ct_refresh(ct, nf_ct_icmp_timeout);
+ nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
}
return NF_ACCEPT;
@@ -132,9 +138,164 @@
return 1;
}
-struct nf_conntrack_protocol nf_conntrack_protocol_icmp
-= { { NULL, NULL }, PF_INET, IPPROTO_ICMP, "icmp",
- icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
- icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
+/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
+static int
+icmp_error_message(struct sk_buff *skb,
+ enum nf_conntrack_info *ctinfo,
+ unsigned int hooknum)
+{
+ struct nf_conntrack_tuple innertuple, origtuple;
+ struct {
+ struct icmphdr icmp;
+ struct iphdr ip;
+ } _in, *inside;
+ struct nf_conntrack_protocol *innerproto;
+ struct nf_conntrack_tuple_hash *h;
+ int dataoff;
+ NF_CT_ASSERT(skb->nfct == NULL);
+
+ /* Not enough header? */
+ inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
+ if (inside == NULL)
+ return NF_ACCEPT;
+
+ /* Ignore ICMP's containing fragments (shouldn't happen) */
+ if (inside->ip.frag_off & htons(IP_OFFSET)) {
+ DEBUGP("icmp_error_message: fragment of proto %u\n",
+ inside->ip.protocol);
+ return NF_ACCEPT;
+ }
+
+ innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol);
+ dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
+ inside->ip.protocol, &origtuple,
+ &nf_conntrack_l3proto_ipv4, innerproto)) {
+ DEBUGP("icmp_error_message: ! get_tuple p=%u",
+ inside->ip.protocol);
+ return NF_ACCEPT;
+ }
+
+ /* Ordinarily, we'd expect the inverted tupleproto, but it's
+ been preserved inside the ICMP. */
+ if (!nf_ct_invert_tuple(&innertuple, &origtuple,
+ &nf_conntrack_l3proto_ipv4, innerproto)) {
+ DEBUGP("icmp_error_message: no match\n");
+ return NF_ACCEPT;
+ }
+
+ *ctinfo = NF_CT_RELATED;
+
+ h = nf_conntrack_find_get(&innertuple, NULL);
+ if (!h) {
+ /* Locally generated ICMPs will match inverted if they
+ haven't been SNAT'ed yet */
+ /* FIXME: NAT code has to handle half-done double NAT --RR */
+ if (hooknum == NF_IP_LOCAL_OUT)
+ h = nf_conntrack_find_get(&origtuple, NULL);
+
+ if (!h) {
+ DEBUGP("icmp_error_message: no match\n");
+ return NF_ACCEPT;
+ }
+
+ /* Reverse direction from that found */
+ if (NF_CT_DIRECTION(h) == NF_CT_DIR_REPLY)
+ *ctinfo += NF_CT_IS_REPLY;
+ } else {
+ if (NF_CT_DIRECTION(h) == NF_CT_DIR_REPLY)
+ *ctinfo += NF_CT_IS_REPLY;
+ }
+
+ /* Update skb to refer to this connection */
+ skb->nfct = &h->ctrack->ct_general;
+ skb->nfctinfo = *ctinfo;
+ return -NF_ACCEPT;
+}
+
+/* Small and modified version of icmp_rcv */
+static int
+icmp_error(struct sk_buff *skb, unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+{
+ struct icmphdr _ih, *icmph;
+
+ /* Not enough header? */
+ icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
+ if (icmph == NULL) {
+ if (LOG_INVALID(IPPROTO_ICMP))
+ nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+ "nf_ct_icmp: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ /* See ip_conntrack_proto_tcp.c */
+ if (hooknum != NF_IP_PRE_ROUTING)
+ goto checksum_skipped;
+
+ switch (skb->ip_summed) {
+ case CHECKSUM_HW:
+ if (!(u16)csum_fold(skb->csum))
+ break;
+ if (LOG_INVALID(IPPROTO_ICMP))
+ nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+ "nf_ct_icmp: bad HW ICMP checksum ");
+ return -NF_ACCEPT;
+ case CHECKSUM_NONE:
+ if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
+ if (LOG_INVALID(IPPROTO_ICMP))
+ nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+ "nf_ct_icmp: bad ICMP checksum ");
+ return -NF_ACCEPT;
+ }
+ default:
+ break;
+ }
+
+checksum_skipped:
+ /*
+ * 18 is the highest 'known' ICMP type. Anything else is a mystery
+ *
+ * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently
+ * discarded.
+ */
+ if (icmph->type > NR_ICMP_TYPES) {
+ if (LOG_INVALID(IPPROTO_ICMP))
+ nf_log_packet(PF_INET, 0, skb, NULL, NULL,
+ "nf_ct_icmp: invalid ICMP type ");
+ return -NF_ACCEPT;
+ }
+
+ /* Need to track icmp error message? */
+ if (icmph->type != ICMP_DEST_UNREACH
+ && icmph->type != ICMP_SOURCE_QUENCH
+ && icmph->type != ICMP_TIME_EXCEEDED
+ && icmph->type != ICMP_PARAMETERPROB
+ && icmph->type != ICMP_REDIRECT)
+ return NF_ACCEPT;
+
+ return icmp_error_message(skb, ctinfo, hooknum);
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
+{
+ .list = { NULL, NULL },
+ .l3proto = PF_INET,
+ .proto = IPPROTO_ICMP,
+ .name = "icmp",
+ .pkt_to_tuple = icmp_pkt_to_tuple,
+ .invert_tuple = icmp_invert_tuple,
+ .print_tuple = icmp_print_tuple,
+ .print_conntrack = icmp_print_conntrack,
+ .packet = icmp_packet,
+ .new = icmp_new,
+ .error = icmp_error,
+ .destroy = NULL,
+ .exp_matches_pkt = NULL,
+ .me = NULL
+};
+
EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Kconfig.ladd
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Kconfig.ladd 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Kconfig.ladd 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,29 +0,0 @@
-config NF_CONNTRACK_IPV6
- tristate "IPv6 support on new connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- select NF_CONNTRACK
- ---help---
- Connection tracking keeps a record of what packets have passed
- through your machine, in order to figure out how they are related
- into connections.
-
- This is IPv6 support on Layer 3 independent connection tracking.
- Layer 3 independent connection tracking is experimental scheme
- which generalize ip_conntrack to support other layer 3 protocols.
-
- To compile it as a module, choose M here. If unsure, say N.
-
-config NF_CONNTRACK_IPV6_FTP
- tristate "FTP support on new connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK_IPV6
- select NF_CONNTRACK_FTP
- help
- Tracking FTP connections is problematic: special helpers are
- required for tracking them, and doing masquerading and other forms
- of Network Address Translation on them.
-
- This is FTP support on Layer 3 independent connection tracking.
- Layer 3 independent connection tracking is experimental scheme
- which generalize ip_conntrack to support other layer 3 protocols.
-
- To compile it as a module, choose M here. If unsure, say N.
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Makefile.ladd
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Makefile.ladd 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/Makefile.ladd 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,7 +0,0 @@
-obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
-
-# objects for l3 independent conntrack
-nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_proto_frag6.o
-
-# l3 independent conntrack
-obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -33,15 +33,12 @@
#include <linux/icmp.h>
#include <linux/sysctl.h>
#include <net/ipv6.h>
-#include <net/checksum.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/nf_conntrack.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
#include <linux/netfilter/nf_conntrack_l3proto.h>
#include <linux/netfilter/nf_conntrack_core.h>
-#include <linux/netfilter_ipv6/nf_conntrack_icmpv6.h>
-#include <linux/netfilter_ipv6/nf_conntrack_frag6.h>
#if 0
#define DEBUGP printk
@@ -49,6 +46,8 @@
#define DEBUGP(format, args...)
#endif
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
@@ -66,26 +65,24 @@
static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
- memcpy(&tuple->src.u3.ip6, &orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6));
- memcpy(&tuple->dst.u3.ip6, &orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6));
+ memcpy(&tuple->src.u3.ip6, &orig->dst.u3.ip6,
+ sizeof(tuple->src.u3.ip6));
+ memcpy(&tuple->dst.u3.ip6, &orig->src.u3.ip6,
+ sizeof(tuple->dst.u3.ip6));
return 1;
}
-static unsigned int
-ipv6_print_tuple(char *buffer, const struct nf_conntrack_tuple *tuple)
+static int ipv6_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- int len;
-
- len = sprintf(buffer, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
- NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
- NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
-
- return len;
+ return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
+ NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
+ NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
}
-static unsigned int
-ipv6_print_conntrack(char *buffer, const struct nf_conn *conntrack)
+static int ipv6_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
return 0;
}
@@ -111,8 +108,8 @@
* - Note also special handling of AUTH header. Thanks to IPsec wizards.
*/
-static int ip6_ct_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
- int len)
+int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
+ int len)
{
u8 nexthdr = *nexthdrp;
@@ -142,98 +139,6 @@
return start;
}
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
-struct nf_conn *
-icmpv6_error_track(struct sk_buff *skb,
- unsigned int icmp6off,
- enum nf_conntrack_info *ctinfo,
- unsigned int hooknum)
-{
- struct nf_conntrack_tuple intuple, origtuple;
- struct nf_conntrack_tuple_hash *h;
- struct ipv6hdr *ip6h;
- struct icmp6hdr hdr;
- unsigned int inip6off;
- struct nf_conntrack_protocol *inproto;
- u_int8_t inprotonum;
- unsigned int inprotoff;
-
- NF_CT_ASSERT(skb->nfct == NULL);
-
- ip6h = skb->nh.ipv6h;
- if (skb_copy_bits(skb, icmp6off, &hdr, sizeof(hdr)) != 0) {
- DEBUGP("icmpv6_error_track: Can't copy ICMPv6 hdr.\n");
- return NULL;
- }
-
- if (hdr.icmp6_type >= 128)
- return NULL;
-
- /*
- * Should I ignore invalid ICMPv6 error here ?
- * ex) ICMPv6 error in ICMPv6 error, Fragmented packet, and so on.
- * - YK
- */
-
- /* Ignore it if the checksum's bogus. */
- if (csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb->len - icmp6off,
- IPPROTO_ICMPV6,
- skb_checksum(skb, icmp6off,
- skb->len - icmp6off, 0))) {
- DEBUGP("icmpv6_error_track: ICMPv6 checksum failed\n");
- return NULL;
- }
-
- inip6off = icmp6off + sizeof(hdr);
- if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
- &inprotonum, sizeof(inprotonum)) != 0) {
- DEBUGP("icmpv6_error_track: Can't copy nexthdr field in inner IPv6 hdr.\n");
- return NULL;
- }
- inprotoff = ip6_ct_skip_exthdr(skb, inip6off + sizeof(struct ipv6hdr),
- &inprotonum,
- skb->len - inip6off
- - sizeof(struct ipv6hdr));
-
- if ((inprotoff < 0) || (inprotoff > skb->len) ||
- (inprotonum == NEXTHDR_FRAGMENT)) {
- DEBUGP("icmpv6_error_track: Can't find protocol header in ICMPv6 payload.\n");
- return NULL;
- }
-
- inproto = nf_ct_find_proto(PF_INET6, inprotonum);
-
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
- &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
- DEBUGP("icmpv6_error_track: Can't get tuple\n");
- return NULL;
- }
-
- /* Ordinarily, we'd expect the inverted tupleproto, but it's
- been preserved inside the ICMP. */
- if (!nf_ct_invert_tuple(&intuple, &origtuple,
- &nf_conntrack_l3proto_ipv6, inproto)) {
- DEBUGP("icmpv6_error_track: Can't invert tuple\n");
- return NULL;
- }
-
- *ctinfo = NF_CT_RELATED;
-
- h = nf_conntrack_find_get(&intuple, NULL);
- if (!h) {
- DEBUGP("icmpv6_error_track: no match\n");
- return NULL;
- } else {
- if (NF_CT_DIRECTION(h) == NF_CT_DIR_REPLY)
- *ctinfo += NF_CT_IS_REPLY;
- }
-
- /* Update skb to refer to this connection */
- skb->nfct = &h->ctrack->infos[*ctinfo];
- return h->ctrack;
-}
-
static int
ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
u_int8_t *protonum, int *ret)
@@ -241,13 +146,12 @@
unsigned int extoff;
unsigned char pnum;
int protoff;
- enum nf_conntrack_info ctinfo;
- extoff = (u8*)((*pskb)->nh.ipv6h+1) - (*pskb)->data;
+ extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data;
pnum = (*pskb)->nh.ipv6h->nexthdr;
- protoff = ip6_ct_skip_exthdr(*pskb, extoff, &pnum,
- (*pskb)->len - extoff);
+ protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+ (*pskb)->len - extoff);
/*
* (protoff == (*pskb)->len) mean that the packet doesn't have no data
@@ -255,16 +159,14 @@
*/
if ((protoff < 0) || (protoff > (*pskb)->len)) {
DEBUGP("ip6_conntrack_core: can't find proto in pkt\n");
+ NF_CT_STAT_INC(error);
+ NF_CT_STAT_INC(invalid);
*ret = NF_ACCEPT;
return 0;
}
- /* It may be an icmp error... */
- if ((pnum == IPPROTO_ICMPV6) &&
- icmpv6_error_track(*pskb, protoff, &ctinfo, hooknum)) {
- *ret = NF_ACCEPT;
- return 0;
- }
+ /* FIXME: Do this right please. --RR */
+ (*pskb)->nfcache |= NFC_UNKNOWN;
*dataoff = protoff;
*protonum = pnum;
@@ -282,33 +184,66 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- DEBUGP("ipv6_confirm, %p\n", (*pskb));
-
/* We've seen it coming out the other side: confirm it */
- return nf_ct_frag6_confirm(*pskb);
+ return nf_conntrack_confirm(*pskb);
}
+extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb);
+extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+ struct net_device *in,
+ struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+static unsigned int ipv6_defrag(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct sk_buff *reasm;
+
+ /* Previously seen (loopback)? */
+ if ((*pskb)->nfct)
+ return NF_ACCEPT;
+
+ reasm = nf_ct_frag6_gather(*pskb);
+
+ /* queued */
+ if (reasm == NULL)
+ return NF_STOLEN;
+
+ /* error occured or not fragmented */
+ if (reasm == *pskb)
+ return NF_ACCEPT;
+
+ nf_ct_frag6_output(hooknum, reasm, in, out, okfn);
+
+ return NF_STOLEN;
+}
+
static unsigned int ipv6_conntrack_in(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- unsigned int ret;
+ struct sk_buff *reasm = (*pskb)->reasm;
- DEBUGP("ipv6_conntrack_in, %p\n", (*pskb));
+ /* This packet is fragmented and has reassembled packet. */
+ if (reasm) {
+ /* Reassembled packet isn't parsed yet ? */
+ if (!reasm->nfct) {
+ unsigned int ret;
- if ((*pskb)->nfct)
+ ret = nf_conntrack_in(PF_INET6, hooknum, &reasm);
+ if (ret != NF_ACCEPT)
+ return ret;
+ }
+ nf_conntrack_get(reasm->nfct);
+ (*pskb)->nfct = reasm->nfct;
return NF_ACCEPT;
+ }
- ret = nf_conntrack_in(PF_INET6, hooknum, pskb);
-
- if (ret != NF_ACCEPT || (*pskb)->nfct == NULL)
- return ret;
-
- /* XXX discards qualifiers */
- return nf_ct_frag6_reinject(hooknum, (*pskb), (struct net_device *)in,
- (struct net_device *)out, okfn);
+ return nf_conntrack_in(PF_INET6, hooknum, pskb);
}
static unsigned int ipv6_conntrack_local(unsigned int hooknum,
@@ -317,8 +252,6 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- DEBUGP("ipv6_conntrack_local, %p\n", (*pskb));
-
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct ipv6hdr)) {
if (net_ratelimit())
@@ -330,6 +263,14 @@
/* Connection tracking may drop packets, but never alters them, so
make it the first hook. */
+static struct nf_hook_ops ipv6_conntrack_defrag_ops = {
+ .hook = ipv6_defrag,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_PRE_ROUTING,
+ .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
+};
+
static struct nf_hook_ops ipv6_conntrack_in_ops = {
.hook = ipv6_conntrack_in,
.owner = THIS_MODULE,
@@ -346,6 +287,14 @@
.priority = NF_IP6_PRI_CONNTRACK,
};
+static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = {
+ .hook = ipv6_defrag,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_LOCAL_OUT,
+ .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,
+};
+
/* Refragmenter; last chance. */
static struct nf_hook_ops ipv6_conntrack_out_ops = {
.hook = ipv6_confirm,
@@ -368,7 +317,7 @@
/* From nf_conntrack_proto_icmpv6.c */
extern unsigned long nf_ct_icmpv6_timeout;
-/* From nf_conntrack_proto_frag6.c */
+/* From nf_conntrack_frag6.c */
extern unsigned long nf_ct_frag6_timeout;
extern unsigned long nf_ct_frag6_low_thresh;
extern unsigned long nf_ct_frag6_high_thresh;
@@ -432,51 +381,145 @@
};
#endif
-static struct nf_conntrack_protocol tcp, udp, icmpv6, frag6;
+/* Fast function for those who don't want to parse /proc (and I don't
+ blame them). */
+/* Reversing the socket's dst/src point of view gives us the reply
+ mapping. */
+static int
+getorigdst(struct sock *sk, int optval, void *user, int *len)
+{
+ struct inet_opt *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct nf_conntrack_tuple_hash *h;
+ struct nf_conntrack_tuple tuple;
+ memset(&tuple, 0, sizeof(tuple));
+ ipv6_addr_copy((struct in6_addr *)tuple.src.u3.ip6, &np->rcv_saddr);
+ ipv6_addr_copy((struct in6_addr *)tuple.dst.u3.ip6, &np->daddr);
+ tuple.src.u.tcp.port = inet->sport;
+ tuple.dst.u.tcp.port = inet->dport;
+ tuple.dst.protonum = IPPROTO_TCP;
+
+ /* We only do TCP at the moment: is there a better way? */
+ if (strcmp(sk->sk_prot->name, "TCP")) {
+ DEBUGP("IPV6 ORIGINAL_DST: Not a TCP socket\n");
+ return -ENOPROTOOPT;
+ }
+
+ if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
+ DEBUGP("IPV6 ORIGINAL_DST: len %u not %u\n",
+ *len, sizeof(struct sockaddr_in));
+ return -EINVAL;
+ }
+
+ h = nf_conntrack_find_get(&tuple, NULL);
+ if (h) {
+ struct sockaddr_in6 sin;
+
+ sin.sin6_family = AF_INET6;
+ sin.sin6_port = h->ctrack->tuplehash[NF_CT_DIR_ORIGINAL]
+ .tuple.dst.u.tcp.port;
+ ipv6_addr_copy(&sin.sin6_addr,
+ (struct in6_addr *)h->ctrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.u3.ip6);
+
+ DEBUGP("IPV6 ORIGINAL_DST: %x:%x:%x:%x:%x:%x:%x:%x %u\n",
+ NIP6(sin.sin6_addr), ntohs(sin.sin6_port));
+ nf_ct_put(h->ctrack);
+ if (copy_to_user(user, &sin, sizeof(sin)) != 0)
+ return -EFAULT;
+ else
+ return 0;
+ }
+ DEBUGP("IPV6 ORIGINAL_DST: Can't find %x:%x:%x:%x:%x:%x:%x:%x/%u-%x:%x:%x:%x:%x:%x:%x:%x/%u.\n",
+ NIP6((struct in6_addr *)tuple.src.u3.ip6),
+ ntohs(tuple.src.u.tcp.port),
+ NIP6((struct in6_addr *)tuple.dst.u3.ip6),
+ ntohs(tuple.dst.u.tcp.port));
+ return -ENOENT;
+}
+
+static struct nf_sockopt_ops so_getorigdst = {
+ .pf = PF_INET6,
+ .get_optmin = SO_ORIGINAL_DST,
+ .get_optmax = SO_ORIGINAL_DST+1,
+ .get = &getorigdst,
+};
+
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
+ .l3proto = PF_INET6,
+ .name = "ipv6",
+ .pkt_to_tuple = ipv6_pkt_to_tuple,
+ .invert_tuple = ipv6_invert_tuple,
+ .print_tuple = ipv6_print_tuple,
+ .print_conntrack = ipv6_print_conntrack,
+ .prepare = ipv6_prepare,
+ .get_features = ipv6_get_features,
+ .me = THIS_MODULE,
+};
+
+extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
+extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6;
+extern int nf_ct_frag6_init(void);
+extern void nf_ct_frag6_cleanup(void);
static int init_or_cleanup(int init)
{
int ret = 0;
- struct nf_conntrack_protocol *proto;
if (!init) goto cleanup;
- memcpy(&tcp, &nf_conntrack_protocol_tcp, sizeof(tcp));
- tcp.l3proto = PF_INET6;
- ret = nf_conntrack_protocol_register(&tcp);
+ ret = nf_register_sockopt(&so_getorigdst);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register tcp.\n");
+ printk(KERN_ERR "Unable to register netfilter socket option\n");
goto cleanup_nothing;
}
+ ret = nf_ct_frag6_init();
+ if (ret < 0) {
+ printk("nf_conntrack_ipv6: can't initialize frag6.\n");
+ goto cleanup_sockopt;
+ }
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6);
+ if (ret < 0) {
+ printk("nf_conntrack_ipv6: can't register tcp.\n");
+ goto cleanup_frag6;
+ }
- memcpy(&udp, &nf_conntrack_protocol_udp, sizeof(udp));
- udp.l3proto = PF_INET6;
- ret = nf_conntrack_protocol_register(&udp);
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp6);
if (ret < 0) {
printk("nf_conntrack_ipv6: can't register udp.\n");
goto cleanup_tcp;
}
- memcpy(&icmpv6, &nf_conntrack_protocol_icmpv6, sizeof(icmpv6));
- icmpv6.l3proto = PF_INET6;
- ret = nf_conntrack_protocol_register(&icmpv6);
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmpv6);
if (ret < 0) {
printk("nf_conntrack_ipv6: can't register icmpv6.\n");
goto cleanup_udp;
}
- memcpy(&frag6, &nf_conntrack_protocol_frag6, sizeof(frag6));
- frag6.l3proto = PF_INET6;
- ret = nf_conntrack_protocol_register(&frag6);
+ ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register frag6.\n");
+ printk("nf_conntrack_ipv6: can't register ipv6\n");
goto cleanup_icmpv6;
}
+ ret = nf_register_hook(&ipv6_conntrack_defrag_ops);
+ if (ret < 0) {
+ printk("nf_conntrack_ipv6: can't register pre-routing defrag "
+ "hook.\n");
+ goto cleanup_ipv6;
+ }
+
+ ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops);
+ if (ret < 0) {
+ printk("nf_conntrack_ipv6: can't register local_out defrag "
+ "hook.\n");
+ goto cleanup_defragops;
+ }
+
ret = nf_register_hook(&ipv6_conntrack_in_ops);
if (ret < 0) {
printk("nf_conntrack_ipv6: can't register pre-routing hook.\n");
- goto cleanup_frag6;
+ goto cleanup_defraglocalops;
}
ret = nf_register_hook(&ipv6_conntrack_local_out_ops);
@@ -505,14 +548,13 @@
goto cleanup_localinops;
}
#endif
-
return ret;
cleanup:
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
-#endif
cleanup_localinops:
+#endif
nf_unregister_hook(&ipv6_conntrack_local_in_ops);
cleanup_inoutandlocalops:
nf_unregister_hook(&ipv6_conntrack_out_ops);
@@ -520,80 +562,37 @@
nf_unregister_hook(&ipv6_conntrack_local_out_ops);
cleanup_inops:
nf_unregister_hook(&ipv6_conntrack_in_ops);
- cleanup_frag6:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET6, NEXTHDR_FRAGMENT);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ cleanup_defraglocalops:
+ nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops);
+ cleanup_defragops:
+ nf_unregister_hook(&ipv6_conntrack_defrag_ops);
+ cleanup_ipv6:
+ nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
cleanup_icmpv6:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET6, IPPROTO_ICMPV6);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6);
cleanup_udp:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET6, IPPROTO_UDP);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6);
cleanup_tcp:
- READ_LOCK(&nf_conntrack_lock);
- proto = __nf_ct_find_proto(PF_INET6, IPPROTO_TCP);
- READ_UNLOCK(&nf_conntrack_lock);
- if (proto)
- nf_conntrack_protocol_unregister(proto);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6);
+ cleanup_frag6:
+ nf_ct_frag6_cleanup();
+ cleanup_sockopt:
+ nf_unregister_sockopt(&so_getorigdst);
cleanup_nothing:
return ret;
}
-static int ipv6_init(void)
-{
- return init_or_cleanup(1);
-}
-
-static void ipv6_fini(void)
-{
- init_or_cleanup(0);
-}
-
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
- { NULL, NULL }, /* list */
- PF_INET6, /* l3proto */
- "ipv6", /* name */
- ipv6_init, /* init */
- ipv6_fini, /* fini */
- ipv6_pkt_to_tuple, /* pkt_to_tuple */
- ipv6_invert_tuple, /* invert_tuple */
- ipv6_print_tuple, /* print_tuple */
- ipv6_print_conntrack, /* print_conntrack */
- NULL, /* packet */
- NULL, /* new */
- NULL, /* destroy */
- ipv6_prepare, /* prepare */
- ipv6_get_features, /* get_features */
- THIS_MODULE /* me */
-};
-
MODULE_LICENSE("GPL");
static int __init init(void)
{
- int ret;
-
need_nf_conntrack();
- ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
- if (ret < 0) {
- printk("nf_conntrack_ipv6: can't register l3 proto module\n");
- }
-
- return ret;
+ return init_or_cleanup(1);
}
static void __exit fini(void)
{
- nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
+ init_or_cleanup(0);
}
module_init(init);
Deleted: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_frag6.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_frag6.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_frag6.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,845 +0,0 @@
-/*
- * Copyright (C)2004 USAGI/WIDE Project
- *
- * 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
- *
- * some parts are derived from net/ipv6/reassembly.c
- *
- * Authors:
- * Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
- *
- */
-
-/* handling fragmented IPv6 packets */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/module.h>
-#include <linux/random.h>
-#include <linux/netfilter.h>
-#include <net/ipv6.h>
-#include <net/checksum.h>
-#include <linux/icmpv6.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv6.h>
-
-/* This rwlock protects the main hash table, protocol/helper/expected
- registrations, conntrack timers*/
-#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&nf_conntrack_lock)
-#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&nf_conntrack_lock)
-
-#include <linux/netfilter/nf_conntrack.h>
-#include <linux/netfilter/nf_conntrack_core.h>
-#include <linux/netfilter/nf_conntrack_tuple.h>
-#include <linux/netfilter/nf_conntrack_protocol.h>
-#include <linux/netfilter_ipv4/listhelp.h>
-#include <linux/netfilter_ipv4/lockhelp.h>
-#include <linux/netfilter_ipv6/nf_conntrack_frag6.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-
-unsigned long nf_ct_frag6_timeout = 30*HZ;
-unsigned long nf_ct_frag6_high_thresh = 256*1024;
-unsigned long nf_ct_frag6_low_thresh = 192*1024;
-
-struct frag6_skb_cb
-{
- struct inet6_skb_parm h;
- int offset;
- struct sk_buff *orig;
-};
-
-struct orig_skb_cb
-{
- struct inet6_skb_parm h;
- struct sk_buff *next;
-};
-
-#define ORIG_CB(skb) ((struct orig_skb_cb*)((skb)->cb))
-#define FRAG6_CB(skb) ((struct frag6_skb_cb*)((skb)->cb))
-
-static atomic_t frag6_mem = ATOMIC_INIT(0);
-
-/* Memory Tracking Functions. */
-static inline void frag6_kfree_skb(struct sk_buff *skb)
-{
- atomic_sub(skb->truesize, &frag6_mem);
- if (FRAG6_CB(skb)->orig)
- kfree_skb(FRAG6_CB(skb)->orig);
-
- kfree_skb(skb);
-}
-
-static int
-evictor_candidate(const struct nf_conntrack_tuple_hash *i,
- const struct nf_conntrack_tuple *ignored)
-{
-
- return (i->tuple.dst.protonum == NEXTHDR_FRAGMENT) &&
- (!(i->ctrack->proto.frag6.last_in & NF_CT_FRAG6_COMPLETE)) &&
- (!nf_ct_tuple_equal(&i->tuple, ignored));
-}
-
-static void frag6_evictor(const struct nf_conntrack_tuple *ignored)
-{
- struct nf_conntrack_tuple_hash *h;
- unsigned int hash;
- unsigned int i;
-
- DEBUGP("frag6_evictor\n");
- get_random_bytes(&hash, 4);
- hash %= nf_conntrack_htable_size;
-
- i = hash;
- if ((++i) >= nf_conntrack_htable_size)
- i = 0;
-
- while (atomic_read(&frag6_mem) > nf_ct_frag6_low_thresh) {
- WRITE_LOCK(&nf_conntrack_lock);
-
- h = LIST_FIND_B(&nf_conntrack_hash[i], evictor_candidate,
- struct nf_conntrack_tuple_hash *, ignored);
-
- if (!h) {
- if ((++i) >= nf_conntrack_htable_size)
- i = 0;
-
- if (i == hash) {
- WRITE_UNLOCK(&nf_conntrack_lock);
- break;
- }
- WRITE_UNLOCK(&nf_conntrack_lock);
- continue;
- }
-
- nf_conntrack_get(&h->ctrack->infos[0]);
- WRITE_UNLOCK(&nf_conntrack_lock);
-
- if (del_timer(&h->ctrack->timeout))
- h->ctrack->timeout.function((unsigned long)h->ctrack);
- nf_conntrack_put(&h->ctrack->infos[0]);
- }
-}
-
-/*
- * find the header just before Fragment Header.
- *
- * if success return 0 and set ...
- * (*prevhdrp): the value of "Next Header Field" in the header
- * just before Fragment Header.
- * (*prevhoff): the offset of "Next Header Field" in the header
- * just before Fragment Header.
- * (*fhoff) : the offset of Fragment Header.
- *
- * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
- *
- */
-static int
-frag6_find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff,
- int *fhoff)
-{
- u8 nexthdr = skb->nh.ipv6h->nexthdr;
- int prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
- int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
- int len = skb->len - start;
- u8 prevhdr = NEXTHDR_IPV6;
-
- while (nexthdr != NEXTHDR_FRAGMENT) {
- struct ipv6_opt_hdr hdr;
- int hdrlen;
-
- if (!ipv6_ext_hdr(nexthdr)) {
- return -1;
- }
- if (len < (int)sizeof(struct ipv6_opt_hdr)) {
- DEBUGP("too short\n");
- return -1;
- }
- if (nexthdr == NEXTHDR_NONE) {
- DEBUGP("next header is none\n");
- return -1;
- }
- if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
- BUG();
- if (nexthdr == NEXTHDR_AUTH)
- hdrlen = (hdr.hdrlen+2)<<2;
- else
- hdrlen = ipv6_optlen(&hdr);
-
- prevhdr = nexthdr;
- prev_nhoff = start;
-
- nexthdr = hdr.nexthdr;
- len -= hdrlen;
- start += hdrlen;
- }
-
- if (len < 0)
- return -1;
-
- *prevhdrp = prevhdr;
- *prevhoff = prev_nhoff;
- *fhoff = start;
-
- return 0;
-}
-
-/* derived from net/ipv6/reassembly.c */
-
-static int
-frag6_queue(struct nf_conn *conntrack, struct sk_buff *skb,
- struct frag_hdr *fhdr)
-{
- struct sk_buff *prev, *next;
- int offset, end;
- struct nf_ct_frag6 *fq = &conntrack->proto.frag6;
-
- offset = ntohs(fhdr->frag_off) & ~0x7;
- end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
- ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
-
- DEBUGP("frag6_queue: end = %d\n", end);
-
- if ((unsigned int)end > IPV6_MAXPLEN) {
-
- DEBUGP("frag6_queue: offset too big. offset = %u, payload_len = %u, end = %u\n",
- offset, ntohs(skb->nh.ipv6h->payload_len), end);
- return -1;
- }
-
- if (skb->ip_summed == CHECKSUM_HW)
- skb->csum = csum_sub(skb->csum,
- csum_partial(skb->nh.raw,
- (u8*)(fhdr + 1) - skb->nh.raw,
- 0));
-
- /* Is this the final fragment? */
- if (!(fhdr->frag_off & htons(IP6_MF))) {
- /* If we already have some bits beyond end
- * or have different end, the segment is corrupted.
- */
- if (end < fq->len ||
- ((fq->last_in & NF_CT_FRAG6_LAST_IN) && end != fq->len)) {
- DEBUGP("frag6_queue: final fragment. but bad offset\n");
- goto err;
- }
- fq->last_in |= NF_CT_FRAG6_LAST_IN;
- fq->len = end;
- } else {
- /* Check if the fragment is rounded to 8 bytes.
- * Required by the RFC.
- */
- if (end & 0x7) {
- DEBUGP("frag6_queue: bad offset\n");
- return -1;
- }
- if (end > fq->len) {
- /* Some bits beyond end -> corruption. */
- if (fq->last_in & NF_CT_FRAG6_LAST_IN) {
- DEBUGP("frag6_queue: end of payload is too big\n");
- goto err;
- }
- fq->len = end;
- }
- }
-
- if (end == offset) {
- DEBUGP("frag6_queue: invaild payload length or offset=%d\n",
- offset);
- goto err;
- }
-
- /* Point into the IP datagram 'data' part. */
- if (!pskb_pull(skb, (u8 *)(fhdr + 1) - skb->data)) {
- DEBUGP("frag6_queue: too short\n");
- goto err;
- }
- if (end - offset < skb->len) {
- if (pskb_trim(skb, end - offset)) {
- DEBUGP("can't trim\n");
- goto err;
- }
- if (skb->ip_summed != CHECKSUM_UNNECESSARY)
- skb->ip_summed = CHECKSUM_NONE;
- }
-
- /* Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
- prev = NULL;
- for(next = fq->fragments; next != NULL; next = next->next) {
- if (FRAG6_CB(next)->offset >= offset)
- break; /* bingo! */
- prev = next;
- }
-
- /* We found where to put this one. Check for overlap with
- * preceding fragment, and, if needed, align things so that
- * any overlaps are eliminated.
- */
- if (prev) {
- int i = (FRAG6_CB(prev)->offset + prev->len) - offset;
-
- if (i > 0) {
- offset += i;
- if (end <= offset) {
- DEBUGP("this packet is coverd with other packets in queue\n");
- goto err;
- }
- if (!pskb_pull(skb, i)) {
- DEBUGP("overrupped and can't pull\n");
- goto err;
- }
- if (skb->ip_summed != CHECKSUM_UNNECESSARY)
- skb->ip_summed = CHECKSUM_NONE;
- }
- }
-
- /* Look for overlap with succeeding segments.
- * If we can merge fragments, do it.
- */
- while (next && FRAG6_CB(next)->offset < end) {
- int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */
-
- if (i < next->len) {
- /* Eat head of the next overlapped fragment
- * and leave the loop. The next ones cannot overlap.
- */
- if (!pskb_pull(next, i)) {
- DEBUGP("can't pull\n");
- goto err;
- }
- FRAG6_CB(next)->offset += i; /* next fragment */
- fq->meat -= i;
- if (next->ip_summed != CHECKSUM_UNNECESSARY)
- next->ip_summed = CHECKSUM_NONE;
- break;
- } else {
- struct sk_buff *free_it = next;
-
- /* Old fragment is completely overridden with
- * new one drop it.
- */
- next = next->next;
-
- if (prev)
- prev->next = next;
- else
- fq->fragments = next;
-
- fq->meat -= free_it->len;
- frag6_kfree_skb(free_it);
- }
- }
-
- FRAG6_CB(skb)->offset = offset;
-
- /* Insert this fragment in the chain of fragments. */
- skb->next = next;
- if (prev)
- prev->next = skb;
- else
- fq->fragments = skb;
-
- if (skb->dev)
- fq->iif = skb->dev->ifindex;
- fq->stamp = skb->stamp;
- fq->meat += skb->len;
- atomic_add(skb->truesize, &frag6_mem);
-
- if (offset == 0)
- fq->last_in |= NF_CT_FRAG6_FIRST_IN;
-
- return 0;
-
-err:
- return -1;
-}
-
-static int
-frag6_reasm(struct nf_conn *conntrack, struct net_device *dev)
-{
- struct nf_ct_frag6 *fq = &conntrack->proto.frag6;
- struct sk_buff *fp, *head = fq->fragments;
- int payload_len;
- u8 prevhdr;
- int prevnhoff, fhoff;
-
- BUG_TRAP(head != NULL);
- BUG_TRAP(FRAG6_CB(head)->offset == 0);
-
- /* Unfragmented part is taken from the first segment. */
- payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr)
- + fq->len - sizeof(struct frag_hdr);
- if (payload_len > IPV6_MAXPLEN)
- goto out_oversize;
-
- if (frag6_find_prev_fhdr(head, &prevhdr, &prevnhoff, &fhoff) < 0)
- goto out_fail;
-
- /* Head of list must not be cloned. */
- if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
- DEBUGP("can't copy head of cloned skb\n");
- goto out_oom;
- }
-
- /* If the first fragment is fragmented itself, we split
- * it to two chunks: the first with data and paged part
- * and the second, holding only fragments. */
- if (skb_shinfo(head)->frag_list) {
- struct sk_buff *clone;
- int i, plen = 0;
-
- if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
- goto out_oom;
-
- clone->next = head->next;
- head->next = clone;
- skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
- skb_shinfo(head)->frag_list = NULL;
- for (i=0; i < skb_shinfo(head)->nr_frags; i++)
- plen += skb_shinfo(head)->frags[i].size;
- clone->len = clone->data_len = head->data_len - plen;
- head->data_len -= clone->len;
- head->len -= clone->len;
- clone->csum = 0;
- clone->ip_summed = head->ip_summed;
- atomic_add(clone->truesize, &frag6_mem);
- }
-
- /* We have to remove fragment header from datagram and to relocate
- * header in order to calculate ICV correctly. */
-
- head->data[prevnhoff] = head->data[fhoff];
- memmove(head->head + sizeof(struct frag_hdr), head->head,
- (head->data - head->head) - sizeof(struct frag_hdr));
- head->mac.raw += sizeof(struct frag_hdr);
- head->nh.raw += sizeof(struct frag_hdr);
- if (head->h.raw && head->h.raw < head->data - sizeof(struct frag_hdr))
- head->h.raw += sizeof(struct frag_hdr);
-
- skb_shinfo(head)->frag_list = head->next;
- skb_push(head, head->data - head->nh.raw);
- atomic_sub(head->truesize, &frag6_mem);
-
- for (fp=head->next; fp; fp = fp->next) {
- head->data_len += fp->len;
- head->len += fp->len;
- if (head->ip_summed != fp->ip_summed)
- head->ip_summed = CHECKSUM_NONE;
- else if (head->ip_summed == CHECKSUM_HW)
- head->csum = csum_add(head->csum, fp->csum);
- head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &frag6_mem);
- }
-
- head->next = NULL;
- head->dev = dev;
- head->stamp = fq->stamp;
- head->nh.ipv6h->payload_len = ntohs(payload_len);
-
- /* Yes, and fold redundant checksum back. 8) */
- if (head->ip_summed == CHECKSUM_HW)
- head->csum = csum_partial(head->nh.raw,
- head->h.raw - head->nh.raw,
- head->csum);
-
- fq->fragments = NULL;
- fq->reasm = head;
- return 0;
-
-out_oversize:
- if (net_ratelimit())
- printk(KERN_DEBUG "ip6_frag_reasm: payload len = %d\n",
- payload_len);
- goto out_fail;
-out_oom:
- if (net_ratelimit())
- printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
-out_fail:
- return -1;
-}
-
-/*
- * delete fragment header and change "Next Header" field in the previous
- * header
- */
-static int
-ip6_del_fraghdr(struct sk_buff *skb)
-{
- u8 prevhdr;
- int prevnhoff, fhoff;
-
- if (frag6_find_prev_fhdr(skb, &prevhdr, &prevnhoff, &fhoff) < 0)
- return -1;
-
- if (!pskb_may_pull(skb, fhoff + sizeof(struct frag_hdr))) {
- DEBUGP("packet too short\n");
- return -1;
- }
-
- if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC) < 0) {
- DEBUGP("can't copy head of cloned skb\n");
- return -1;
- }
-
- skb->data[prevnhoff] = skb->data[fhoff];
- memmove(skb->head + sizeof(struct frag_hdr), skb->head,
- (skb->data - skb->head) + fhoff);
- skb->mac.raw += sizeof(struct frag_hdr);
- skb->nh.raw += sizeof(struct frag_hdr);
- if (skb->h.raw && skb->h.raw < skb->data - sizeof(struct frag_hdr))
- skb->h.raw += sizeof(struct frag_hdr);
-
- return 0;
-}
-
-unsigned int
-nf_ct_frag6_confirm(struct sk_buff *skb)
-{
- struct nf_conn *conntrack;
- enum nf_conntrack_info ctinfo;
-
- conntrack = nf_ct_get(skb, &ctinfo);
-
- if (conntrack == NULL ||
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.protonum
- != NEXTHDR_FRAGMENT)
- /* this is not fragmented packet. */
- return nf_conntrack_confirm(skb);
- else
- return nf_conntrack_confirm(conntrack->proto.frag6.reasm);
-}
-
-/* pass the reserved fragmented packets to next hook */
-unsigned int
-nf_ct_frag6_reinject(unsigned int hooknum, struct sk_buff *skb,
- struct net_device *in, struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- struct nf_conn *conntrack;
- struct nf_ct_frag6 *fq;
- struct sk_buff *frag, *frag_list;
- enum nf_conntrack_info ctinfo;
-
- conntrack = nf_ct_get(skb, &ctinfo);
-
- if (conntrack == NULL ||
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.protonum
- != NEXTHDR_FRAGMENT)
- /* this is not fragmented packet. */
- return NF_ACCEPT;
-
- fq = &conntrack->proto.frag6;
-
- spin_lock(&fq->lock);
- frag_list = fq->orig_list;
- fq->orig_list = NULL;
- spin_unlock(&fq->lock);
-
- if (frag_list== NULL) {
- if (net_ratelimit())
- printk("already out ?\n");
-
- return NF_STOLEN;
- }
-
- for (frag = frag_list; frag;) {
- struct sk_buff *next = ORIG_CB(frag)->next;
- NF_HOOK_THRESH(PF_INET6, hooknum, frag, in, out, okfn,
- NF_IP6_PRI_CONNTRACK+1);
- frag = next;
- }
-
- return NF_STOLEN;
-}
-
-/* return reassembled packet */
-struct sk_buff *
-nf_ct_frag6_get_reasm(const struct sk_buff *skb)
-{
- if (skb->nfct && (struct nf_conn *)skb->nfct->master)
- return ((struct nf_conn *)skb->nfct->master)->proto.frag6.reasm;
-
- return NULL;
-}
-
-/* protocol module definitions */
-
-static int
-frag6_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
- struct nf_conntrack_tuple *tuple)
-{
- struct frag_hdr hdr;
-
- /* Actually only need first 8 bytes. */
- if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
- return 0;
-
- tuple->src.u.frag6.id = hdr.identification;
- tuple->dst.u.frag6.orig = 1;
-
- return 1;
-}
-
-static int
-frag6_invert_tuple(struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_tuple *orig)
-{
- tuple->src.u.frag6.id = orig->src.u.frag6.id;
- tuple->dst.u.frag6.orig = !orig->dst.u.frag6.orig;
- return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static unsigned int
-frag6_print_tuple(char *buffer, const struct nf_conntrack_tuple *tuple)
-{
- if (tuple->dst.u.frag6.orig)
- return sprintf(buffer, "id=%08x", tuple->src.u.frag6.id);
- else
- return 0;
-}
-
-/* Print out the private part of the conntrack. */
-static unsigned int
-frag6_print_conntrack(char *buffer, const struct nf_conn *conntrack)
-{
- return 0;
-}
-
-/* gather fragmented packets, reassemble them, and track reassembled packet. */
-static int
-frag6_packet(struct nf_conn *conntrack,
- const struct sk_buff *skb,
- unsigned int dataoff,
- enum nf_conntrack_info ctinfo,
- unsigned int hooknum)
-{
- struct sk_buff *orig = (struct sk_buff *)skb; /* XXX */
- struct sk_buff *clone;
- struct frag_hdr *fhdr;
- struct nf_ct_frag6 *fq = &conntrack->proto.frag6;
- struct net_device *dev = orig->dev;
- struct sk_buff *frag;
- int ret = -1;
-
- if (NFCTINFO2DIR(ctinfo) == NF_CT_DIR_REPLY) {
- DEBUGP("frag6_packet: unexpected reply packet\n");
- return -1;
- }
-
- clone = skb_clone(orig, GFP_ATOMIC);
- if (clone == NULL) {
- DEBUGP("can't clone skb\n");
- return -1;
- }
- FRAG6_CB(clone)->orig = orig;
- nf_conntrack_put(clone->nfct);
- clone->nfct = NULL;
-
- /* Jumbo payload inhibits frag. header */
- if (clone->nh.ipv6h->payload_len==0) {
- DEBUGP("frag6_packet: Jumbo payload\n");
- goto free_clone;
- }
- if (!pskb_may_pull(clone, dataoff + sizeof(struct frag_hdr))) {
- DEBUGP("frag6_packet: packet too short\n");
- goto free_clone;
- }
-
- if (atomic_read(&frag6_mem) > nf_ct_frag6_high_thresh)
- frag6_evictor(&conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple);
-
- spin_lock(&fq->lock);
-
- if (fq->last_in & NF_CT_FRAG6_COMPLETE) {
- spin_unlock(&fq->lock);
- DEBUGP("already all fragmented packets are gathered\n");
- goto free_clone;
- }
-
- fhdr = (struct frag_hdr *)(clone->data + dataoff);
- DEBUGP("fra6_packet: offset = %u\n", ntohs(fhdr->frag_off) & ~0x7);
-
- if (!(fhdr->frag_off & htons(0xFFF9)) && fq->fragments == NULL) {
- /*
- * this packet is not fragmented. but we handle it as fragmented
- * packet.
- */
-
- if (ip6_del_fraghdr(clone) < 0) {
- spin_unlock(&fq->lock);
- goto free_clone;
- }
-
- fq->orig_list = orig;
- ORIG_CB(orig)->next = NULL;
- fq->reasm = clone;
- fq->meat = fq->len = skb->len;
- fq->last_in |= NF_CT_FRAG6_FIRST_IN | NF_CT_FRAG6_LAST_IN |
- NF_CT_FRAG6_COMPLETE;
-
- } else {
- ret = frag6_queue(conntrack, clone, fhdr);
- if (ret == -1) {
- spin_unlock(&fq->lock);
- goto free_clone;
- }
-
- DEBUGP("frag6_packet: meat = %d, len = %d\n", fq->meat, fq->len);
-
- nf_conntrack_confirm(orig);
-
- if (fq->last_in != (NF_CT_FRAG6_FIRST_IN | NF_CT_FRAG6_LAST_IN)
- || fq->meat != fq->len) {
- /* not gathered all packet yet */
- spin_unlock(&fq->lock);
- /* put conntrack so that it is destroyed when timeout */
- nf_conntrack_put(orig->nfct);
- orig->nfct = NULL;
- ret = NF_STOLEN;
- goto out;
- }
-
- /* all packets have be gatherd. let's reassemble */
- fq->last_in |= NF_CT_FRAG6_COMPLETE;
-
- /* at first, reserve original packets. */
- for (frag = fq->fragments; frag; frag = frag->next) {
- struct sk_buff *tmp_skb = FRAG6_CB(frag)->orig;
-
- ORIG_CB(tmp_skb)->next = fq->orig_list;
- fq->orig_list = tmp_skb;
- }
-
- ret = frag6_reasm(conntrack, dev);
-
- /*
- * timer is not needed any more.
- * conntrack is not destroyed yet because orig still grub it.
- */
- if (del_timer(&conntrack->timeout))
- conntrack->timeout.function((unsigned long)conntrack);
-
- if (ret == -1) {
- spin_unlock(&fq->lock);
- nf_conntrack_put(orig->nfct);
- orig->nfct = NULL;
- ret = NF_STOLEN;
- goto out;
- }
- }
- fq->fragments = NULL;
-
- spin_unlock(&fq->lock);
-
- set_bit(NF_S_ASSURED_BIT, &conntrack->status);
- ret = nf_conntrack_in(PF_INET6, hooknum, &fq->reasm);
-
- spin_lock(&fq->lock);
- if (ret == NF_ACCEPT) {
- for (frag = fq->orig_list; frag;) {
- struct sk_buff *next = ORIG_CB(frag)->next;
-
- frag->nfct = &conntrack->infos[NF_S_ASSURED];
- nf_conntrack_get(frag->nfct);
- frag = next;
- }
-
- /* this skb grub conntrack twice. so put once */
- nf_conntrack_put(orig->nfct);
- } else {
- for (frag = fq->orig_list; frag;) {
- struct sk_buff *next = ORIG_CB(frag)->next;
-
- if (orig != frag)
- kfree_skb(frag);
- frag = next;
- }
- fq->orig_list = NULL;
- ret = NF_DROP;
- }
- spin_unlock(&fq->lock);
-
- return ret;
-
-free_clone:
- kfree_skb(clone);
-out:
- return ret;
-}
-
-/* Called when a new connection for this protocol found. */
-static int
-frag6_new(struct nf_conn *conntrack, const struct sk_buff *skb,
- unsigned int dataoff)
-{
- spin_lock_init(&conntrack->proto.frag6.lock);
- nf_ct_refresh(conntrack, nf_ct_frag6_timeout);
- return 1;
-}
-
-/* destroy all fragmented packets in this conntrack */
-static void
-frag6_destroy(struct nf_conn *conntrack)
-{
- struct sk_buff *skb;
- struct nf_ct_frag6 *fq = &conntrack->proto.frag6;
-
- /* Send error only if the first segment arrived. */
- if ((fq->last_in & NF_CT_FRAG6_FIRST_IN) &&
- (!(fq->last_in & NF_CT_FRAG6_COMPLETE)) && fq->fragments) {
- struct net_device *dev = dev_get_by_index(fq->iif);
-
- /*
- But use as source device on which LAST ARRIVED
- segment was received.
- */
- if (dev) {
- fq->fragments->dev = dev;
- icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED,
- ICMPV6_EXC_FRAGTIME, 0, dev);
- dev_put(dev);
- }
- }
- skb = fq->fragments;
- while (skb) {
- struct sk_buff *next = skb->next;
-
- frag6_kfree_skb(skb);
- skb = next;
- }
-
- if (fq->reasm)
- kfree_skb(fq->reasm);
-}
-
-struct nf_conntrack_protocol nf_conntrack_protocol_frag6
-= { { NULL, NULL }, PF_UNSPEC, NEXTHDR_FRAGMENT, "fragment",
- frag6_pkt_to_tuple, frag6_invert_tuple, frag6_print_tuple,
- frag6_print_conntrack, frag6_packet, frag6_new, frag6_destroy, NULL, NULL };
-
-EXPORT_SYMBOL(nf_conntrack_protocol_frag6);
-EXPORT_SYMBOL(nf_ct_frag6_get_reasm);
-EXPORT_SYMBOL(nf_ct_frag6_confirm);
-EXPORT_SYMBOL(nf_ct_frag6_reinject);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -19,8 +19,13 @@
#include <linux/netfilter.h>
#include <linux/in6.h>
#include <linux/icmpv6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/seq_file.h>
+#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/nf_conntrack_tuple.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
+#include <linux/netfilter/nf_conntrack_core.h>
#include <linux/netfilter_ipv6/nf_conntrack_icmpv6.h>
unsigned long nf_ct_icmpv6_timeout = 30*HZ;
@@ -35,13 +40,14 @@
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
- struct icmp6hdr hdr;
+ struct icmp6hdr _hdr, *hp;
- if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0)
+ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
return 0;
- tuple->dst.u.icmp.type = hdr.icmp6_type;
- tuple->src.u.icmp.id = hdr.icmp6_identifier;
- tuple->dst.u.icmp.code = hdr.icmp6_code;
+ tuple->dst.u.icmp.type = hp->icmp6_type;
+ tuple->src.u.icmp.id = hp->icmp6_identifier;
+ tuple->dst.u.icmp.code = hp->icmp6_code;
return 1;
}
@@ -68,18 +74,18 @@
}
/* Print out the per-protocol part of the tuple. */
-static unsigned int icmpv6_print_tuple(char *buffer,
- const struct nf_conntrack_tuple *tuple)
+static int icmpv6_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return sprintf(buffer, "type=%u code=%u id=%u ",
- tuple->dst.u.icmp.type,
- tuple->dst.u.icmp.code,
- ntohs(tuple->src.u.icmp.id));
+ return seq_printf(s, "type=%u code=%u id=%u ",
+ tuple->dst.u.icmp.type,
+ tuple->dst.u.icmp.code,
+ ntohs(tuple->src.u.icmp.id));
}
/* Print out the private part of the conntrack. */
-static unsigned int icmpv6_print_conntrack(char *buffer,
- const struct nf_conn *conntrack)
+static int icmpv6_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
return 0;
}
@@ -89,6 +95,7 @@
const struct sk_buff *skb,
unsigned int dataoff,
enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum)
{
/* Try to delete connection immediately after all replies:
@@ -101,13 +108,12 @@
ct->timeout.function((unsigned long)ct);
} else {
atomic_inc(&ct->proto.icmp.count);
- nf_ct_refresh(ct, nf_ct_icmpv6_timeout);
+ nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
}
return NF_ACCEPT;
}
-
/* Called when a new connection for this protocol found. */
static int icmpv6_new(struct nf_conn *conntrack,
const struct sk_buff *skb,
@@ -130,9 +136,131 @@
return 1;
}
-struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6
-= { { NULL, NULL }, PF_INET6, IPPROTO_ICMPV6, "icmpv6",
- icmpv6_pkt_to_tuple, icmpv6_invert_tuple, icmpv6_print_tuple,
- icmpv6_print_conntrack, icmpv6_packet, icmpv6_new, NULL, NULL, NULL };
+extern int
+nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len);
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
+static int
+icmpv6_error_message(struct sk_buff *skb,
+ unsigned int icmp6off,
+ enum nf_conntrack_info *ctinfo,
+ unsigned int hooknum)
+{
+ struct nf_conntrack_tuple intuple, origtuple;
+ struct nf_conntrack_tuple_hash *h;
+ struct icmp6hdr _hdr, *hp;
+ unsigned int inip6off;
+ struct nf_conntrack_protocol *inproto;
+ u_int8_t inprotonum;
+ unsigned int inprotoff;
+ NF_CT_ASSERT(skb->nfct == NULL);
+
+ hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
+ if (hp == NULL) {
+ DEBUGP("icmpv6_error: Can't get ICMPv6 hdr.\n");
+ return NF_ACCEPT;
+ }
+
+ inip6off = icmp6off + sizeof(_hdr);
+ if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
+ &inprotonum, sizeof(inprotonum)) != 0) {
+ DEBUGP("icmpv6_error: Can't get nexthdr in inner IPv6 header.\n");
+ return NF_ACCEPT;
+ }
+ inprotoff = nf_ct_ipv6_skip_exthdr(skb,
+ inip6off + sizeof(struct ipv6hdr),
+ &inprotonum,
+ skb->len - inip6off
+ - sizeof(struct ipv6hdr));
+
+ if ((inprotoff < 0) || (inprotoff > skb->len) ||
+ (inprotonum == NEXTHDR_FRAGMENT)) {
+ DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n");
+ return NF_ACCEPT;
+ }
+
+ inproto = nf_ct_find_proto(PF_INET6, inprotonum);
+
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
+ &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
+ DEBUGP("icmpv6_error: Can't get tuple\n");
+ return NF_ACCEPT;
+ }
+
+ /* Ordinarily, we'd expect the inverted tupleproto, but it's
+ been preserved inside the ICMP. */
+ if (!nf_ct_invert_tuple(&intuple, &origtuple,
+ &nf_conntrack_l3proto_ipv6, inproto)) {
+ DEBUGP("icmpv6_error: Can't invert tuple\n");
+ return NF_ACCEPT;
+ }
+
+ *ctinfo = NF_CT_RELATED;
+
+ h = nf_conntrack_find_get(&intuple, NULL);
+ if (!h) {
+ DEBUGP("icmpv6_error: no match\n");
+ return NF_ACCEPT;
+ } else {
+ if (NF_CT_DIRECTION(h) == NF_CT_DIR_REPLY)
+ *ctinfo += NF_CT_IS_REPLY;
+ }
+
+ /* Update skb to refer to this connection */
+ skb->nfct = &h->ctrack->ct_general;
+ skb->nfctinfo = *ctinfo;
+ return -NF_ACCEPT;
+}
+
+static int
+icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo, int pf, unsigned int hooknum)
+{
+ struct icmp6hdr _ih, *icmp6h;
+
+ icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
+ if (icmp6h == NULL) {
+ if (LOG_INVALID(IPPROTO_ICMPV6))
+ nf_log_packet(PF_INET6, 0, skb, NULL, NULL,
+ "nf_ct_icmpv6: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ if (hooknum != NF_IP6_PRE_ROUTING)
+ goto skipped;
+
+ /* Ignore it if the checksum's bogus. */
+ if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+ skb->len - dataoff, IPPROTO_ICMPV6,
+ skb_checksum(skb, dataoff,
+ skb->len - dataoff, 0))) {
+ nf_log_packet(PF_INET6, 0, skb, NULL, NULL,
+ "nf_ct_icmpv6: ICMPv6 checksum failed\n");
+ return -NF_ACCEPT;
+ }
+
+skipped:
+
+ /* is not error message ? */
+ if (icmp6h->icmp6_type >= 128)
+ return NF_ACCEPT;
+
+ return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
+{
+ .l3proto = PF_INET6,
+ .proto = IPPROTO_ICMPV6,
+ .name = "icmpv6",
+ .pkt_to_tuple = icmpv6_pkt_to_tuple,
+ .invert_tuple = icmpv6_invert_tuple,
+ .print_tuple = icmpv6_print_tuple,
+ .print_conntrack = icmpv6_print_conntrack,
+ .packet = icmpv6_packet,
+ .new = icmpv6_new,
+ .error = icmpv6_error,
+};
+
EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6);
Added: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_reasm.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_reasm.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/ipv6/netfilter/nf_conntrack_reasm.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -0,0 +1,890 @@
+/*
+ * IPv6 fragment reassembly for connection tracking
+ * Linux INET6 implementation
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Authors:
+ * Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
+ *
+ * Based on: net/ipv6/reassembly.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/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/jiffies.h>
+#include <linux/net.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <linux/sysctl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */
+#define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */
+#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
+
+int nf_ct_frag6_high_thresh = 256*1024;
+int nf_ct_frag6_low_thresh = 192*1024;
+int nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT;
+
+struct nf_ct_frag6_skb_cb
+{
+ struct inet6_skb_parm h;
+ int offset;
+ struct sk_buff *orig;
+};
+
+#define NFCT_FRAG6_CB(skb) ((struct nf_ct_frag6_skb_cb*)((skb)->cb))
+
+struct nf_ct_frag6_queue
+{
+ struct nf_ct_frag6_queue *next;
+ struct list_head lru_list; /* lru list member */
+
+ __u32 id; /* fragment id */
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+
+ spinlock_t lock;
+ atomic_t refcnt;
+ struct timer_list timer; /* expire timer */
+ struct sk_buff *fragments;
+ int len;
+ int meat;
+ struct timeval stamp;
+ unsigned int csum;
+ __u8 last_in; /* has first/last segment arrived? */
+#define COMPLETE 4
+#define FIRST_IN 2
+#define LAST_IN 1
+ __u16 nhoffset;
+ struct nf_ct_frag6_queue **pprev;
+};
+
+/* Hash table. */
+
+#define FRAG6Q_HASHSZ 64
+
+static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ];
+static rwlock_t nf_ct_frag6_lock = RW_LOCK_UNLOCKED;
+static u32 nf_ct_frag6_hash_rnd;
+static LIST_HEAD(nf_ct_frag6_lru_list);
+int nf_ct_frag6_nqueues = 0;
+
+static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
+{
+ if (fq->next)
+ fq->next->pprev = fq->pprev;
+ *fq->pprev = fq->next;
+ list_del(&fq->lru_list);
+ nf_ct_frag6_nqueues--;
+}
+
+static __inline__ void fq_unlink(struct nf_ct_frag6_queue *fq)
+{
+ write_lock(&nf_ct_frag6_lock);
+ __fq_unlink(fq);
+ write_unlock(&nf_ct_frag6_lock);
+}
+
+static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
+ struct in6_addr *daddr)
+{
+ u32 a, b, c;
+
+ a = saddr->s6_addr32[0];
+ b = saddr->s6_addr32[1];
+ c = saddr->s6_addr32[2];
+
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += nf_ct_frag6_hash_rnd;
+ __jhash_mix(a, b, c);
+
+ a += saddr->s6_addr32[3];
+ b += daddr->s6_addr32[0];
+ c += daddr->s6_addr32[1];
+ __jhash_mix(a, b, c);
+
+ a += daddr->s6_addr32[2];
+ b += daddr->s6_addr32[3];
+ c += id;
+ __jhash_mix(a, b, c);
+
+ return c & (FRAG6Q_HASHSZ - 1);
+}
+
+static struct timer_list nf_ct_frag6_secret_timer;
+int nf_ct_frag6_secret_interval = 10 * 60 * HZ;
+
+static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
+{
+ unsigned long now = jiffies;
+ int i;
+
+ write_lock(&nf_ct_frag6_lock);
+ get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
+ for (i = 0; i < FRAG6Q_HASHSZ; i++) {
+ struct nf_ct_frag6_queue *q;
+
+ q = nf_ct_frag6_hash[i];
+ while (q) {
+ struct nf_ct_frag6_queue *next = q->next;
+ unsigned int hval = ip6qhashfn(q->id,
+ &q->saddr,
+ &q->daddr);
+
+ if (hval != i) {
+ /* Unlink. */
+ if (q->next)
+ q->next->pprev = q->pprev;
+ *q->pprev = q->next;
+
+ /* Relink to new hash chain. */
+ if ((q->next = nf_ct_frag6_hash[hval]) != NULL)
+ q->next->pprev = &q->next;
+ nf_ct_frag6_hash[hval] = q;
+ q->pprev = &nf_ct_frag6_hash[hval];
+ }
+
+ q = next;
+ }
+ }
+ write_unlock(&nf_ct_frag6_lock);
+
+ mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval);
+}
+
+atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0);
+
+/* Memory Tracking Functions. */
+static inline void frag_kfree_skb(struct sk_buff *skb)
+{
+ atomic_sub(skb->truesize, &nf_ct_frag6_mem);
+ if (NFCT_FRAG6_CB(skb)->orig)
+ kfree_skb(NFCT_FRAG6_CB(skb)->orig);
+
+ kfree_skb(skb);
+}
+
+static inline void frag_free_queue(struct nf_ct_frag6_queue *fq)
+{
+ atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+ kfree(fq);
+}
+
+static inline struct nf_ct_frag6_queue *frag_alloc_queue(void)
+{
+ struct nf_ct_frag6_queue *fq = kmalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC);
+
+ if (!fq)
+ return NULL;
+ atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+ return fq;
+}
+
+/* Destruction primitives. */
+
+/* Complete destruction of fq. */
+static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq)
+{
+ struct sk_buff *fp;
+
+ BUG_TRAP(fq->last_in&COMPLETE);
+ BUG_TRAP(del_timer(&fq->timer) == 0);
+
+ /* Release all fragment data. */
+ fp = fq->fragments;
+ while (fp) {
+ struct sk_buff *xp = fp->next;
+
+ frag_kfree_skb(fp);
+ fp = xp;
+ }
+
+ frag_free_queue(fq);
+}
+
+static __inline__ void fq_put(struct nf_ct_frag6_queue *fq)
+{
+ if (atomic_dec_and_test(&fq->refcnt))
+ nf_ct_frag6_destroy(fq);
+}
+
+/* Kill fq entry. It is not destroyed immediately,
+ * because caller (and someone more) holds reference count.
+ */
+static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
+{
+ if (del_timer(&fq->timer))
+ atomic_dec(&fq->refcnt);
+
+ if (!(fq->last_in & COMPLETE)) {
+ fq_unlink(fq);
+ atomic_dec(&fq->refcnt);
+ fq->last_in |= COMPLETE;
+ }
+}
+
+static void nf_ct_frag6_evictor(void)
+{
+ struct nf_ct_frag6_queue *fq;
+ struct list_head *tmp;
+
+ for (;;) {
+ if (atomic_read(&nf_ct_frag6_mem) <= nf_ct_frag6_low_thresh)
+ return;
+ read_lock(&nf_ct_frag6_lock);
+ if (list_empty(&nf_ct_frag6_lru_list)) {
+ read_unlock(&nf_ct_frag6_lock);
+ return;
+ }
+ tmp = nf_ct_frag6_lru_list.next;
+ fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list);
+ atomic_inc(&fq->refcnt);
+ read_unlock(&nf_ct_frag6_lock);
+
+ spin_lock(&fq->lock);
+ if (!(fq->last_in&COMPLETE))
+ fq_kill(fq);
+ spin_unlock(&fq->lock);
+
+ fq_put(fq);
+ }
+}
+
+static void nf_ct_frag6_expire(unsigned long data)
+{
+ struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data;
+
+ spin_lock(&fq->lock);
+
+ if (fq->last_in & COMPLETE)
+ goto out;
+
+ fq_kill(fq);
+
+out:
+ spin_unlock(&fq->lock);
+ fq_put(fq);
+}
+
+/* Creation primitives. */
+
+
+static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
+ struct nf_ct_frag6_queue *fq_in)
+{
+ struct nf_ct_frag6_queue *fq;
+
+ write_lock(&nf_ct_frag6_lock);
+#ifdef CONFIG_SMP
+ for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+ if (fq->id == fq_in->id &&
+ !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
+ !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
+ atomic_inc(&fq->refcnt);
+ write_unlock(&nf_ct_frag6_lock);
+ fq_in->last_in |= COMPLETE;
+ fq_put(fq_in);
+ return fq;
+ }
+ }
+#endif
+ fq = fq_in;
+
+ if (!mod_timer(&fq->timer, jiffies + nf_ct_frag6_timeout))
+ atomic_inc(&fq->refcnt);
+
+ atomic_inc(&fq->refcnt);
+ if ((fq->next = nf_ct_frag6_hash[hash]) != NULL)
+ fq->next->pprev = &fq->next;
+ nf_ct_frag6_hash[hash] = fq;
+ fq->pprev = &nf_ct_frag6_hash[hash];
+ INIT_LIST_HEAD(&fq->lru_list);
+ list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+ nf_ct_frag6_nqueues++;
+ write_unlock(&nf_ct_frag6_lock);
+ return fq;
+}
+
+
+static struct nf_ct_frag6_queue *
+nf_ct_frag6_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst)
+{
+ struct nf_ct_frag6_queue *fq;
+
+ if ((fq = frag_alloc_queue()) == NULL) {
+ DEBUGP("Can't alloc new queue\n");
+ goto oom;
+ }
+
+ memset(fq, 0, sizeof(struct nf_ct_frag6_queue));
+
+ fq->id = id;
+ ipv6_addr_copy(&fq->saddr, src);
+ ipv6_addr_copy(&fq->daddr, dst);
+
+ init_timer(&fq->timer);
+ fq->timer.function = nf_ct_frag6_expire;
+ fq->timer.data = (long) fq;
+ fq->lock = SPIN_LOCK_UNLOCKED;
+ atomic_set(&fq->refcnt, 1);
+
+ return nf_ct_frag6_intern(hash, fq);
+
+oom:
+ return NULL;
+}
+
+static __inline__ struct nf_ct_frag6_queue *
+fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
+{
+ struct nf_ct_frag6_queue *fq;
+ unsigned int hash = ip6qhashfn(id, src, dst);
+
+ read_lock(&nf_ct_frag6_lock);
+ for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+ if (fq->id == id &&
+ !ipv6_addr_cmp(src, &fq->saddr) &&
+ !ipv6_addr_cmp(dst, &fq->daddr)) {
+ atomic_inc(&fq->refcnt);
+ read_unlock(&nf_ct_frag6_lock);
+ return fq;
+ }
+ }
+ read_unlock(&nf_ct_frag6_lock);
+
+ return nf_ct_frag6_create(hash, id, src, dst);
+}
+
+
+static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
+ struct frag_hdr *fhdr, int nhoff)
+{
+ struct sk_buff *prev, *next;
+ int offset, end;
+
+ if (fq->last_in & COMPLETE) {
+ DEBUGP("Allready completed\n");
+ goto err;
+ }
+
+ offset = ntohs(fhdr->frag_off) & ~0x7;
+ end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
+ ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+
+ if ((unsigned int)end > IPV6_MAXPLEN) {
+ DEBUGP("offset is too large.\n");
+ return -1;
+ }
+
+ if (skb->ip_summed == CHECKSUM_HW)
+ skb->csum = csum_sub(skb->csum,
+ csum_partial(skb->nh.raw,
+ (u8*)(fhdr + 1) - skb->nh.raw,
+ 0));
+
+ /* Is this the final fragment? */
+ if (!(fhdr->frag_off & htons(IP6_MF))) {
+ /* If we already have some bits beyond end
+ * or have different end, the segment is corrupted.
+ */
+ if (end < fq->len ||
+ ((fq->last_in & LAST_IN) && end != fq->len)) {
+ DEBUGP("already received last fragment\n");
+ goto err;
+ }
+ fq->last_in |= LAST_IN;
+ fq->len = end;
+ } else {
+ /* Check if the fragment is rounded to 8 bytes.
+ * Required by the RFC.
+ */
+ if (end & 0x7) {
+ /* RFC2460 says always send parameter problem in
+ * this case. -DaveM
+ */
+ DEBUGP("the end of this fragment is not rounded to 8 bytes.\n");
+ return -1;
+ }
+ if (end > fq->len) {
+ /* Some bits beyond end -> corruption. */
+ if (fq->last_in & LAST_IN) {
+ DEBUGP("last packet already reached.\n");
+ goto err;
+ }
+ fq->len = end;
+ }
+ }
+
+ if (end == offset)
+ goto err;
+
+ /* Point into the IP datagram 'data' part. */
+ if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {
+ DEBUGP("queue: message is too short.\n");
+ goto err;
+ }
+ if (end-offset < skb->len) {
+ if (pskb_trim(skb, end - offset)) {
+ DEBUGP("Can't trim\n");
+ goto err;
+ }
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ /* Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
+ */
+ prev = NULL;
+ for (next = fq->fragments; next != NULL; next = next->next) {
+ if (NFCT_FRAG6_CB(next)->offset >= offset)
+ break; /* bingo! */
+ prev = next;
+ }
+
+ /* We found where to put this one. Check for overlap with
+ * preceding fragment, and, if needed, align things so that
+ * any overlaps are eliminated.
+ */
+ if (prev) {
+ int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset;
+
+ if (i > 0) {
+ offset += i;
+ if (end <= offset) {
+ DEBUGP("overlap\n");
+ goto err;
+ }
+ if (!pskb_pull(skb, i)) {
+ DEBUGP("Can't pull\n");
+ goto err;
+ }
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ }
+
+ /* Look for overlap with succeeding segments.
+ * If we can merge fragments, do it.
+ */
+ while (next && NFCT_FRAG6_CB(next)->offset < end) {
+ /* overlap is 'i' bytes */
+ int i = end - NFCT_FRAG6_CB(next)->offset;
+
+ if (i < next->len) {
+ /* Eat head of the next overlapped fragment
+ * and leave the loop. The next ones cannot overlap.
+ */
+ DEBUGP("Eat head of the overlapped parts.: %d", i);
+ if (!pskb_pull(next, i))
+ goto err;
+
+ /* next fragment */
+ NFCT_FRAG6_CB(next)->offset += i;
+ fq->meat -= i;
+ if (next->ip_summed != CHECKSUM_UNNECESSARY)
+ next->ip_summed = CHECKSUM_NONE;
+ break;
+ } else {
+ struct sk_buff *free_it = next;
+
+ /* Old fragmnet is completely overridden with
+ * new one drop it.
+ */
+ next = next->next;
+
+ if (prev)
+ prev->next = next;
+ else
+ fq->fragments = next;
+
+ fq->meat -= free_it->len;
+ frag_kfree_skb(free_it);
+ }
+ }
+
+ NFCT_FRAG6_CB(skb)->offset = offset;
+
+ /* Insert this fragment in the chain of fragments. */
+ skb->next = next;
+ if (prev)
+ prev->next = skb;
+ else
+ fq->fragments = skb;
+
+ skb->dev = NULL;
+ fq->stamp = skb->stamp;
+ fq->meat += skb->len;
+ atomic_add(skb->truesize, &nf_ct_frag6_mem);
+
+ /* The first fragment.
+ * nhoffset is obtained from the first fragment, of course.
+ */
+ if (offset == 0) {
+ fq->nhoffset = nhoff;
+ fq->last_in |= FIRST_IN;
+ }
+ write_lock(&nf_ct_frag6_lock);
+ list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+ write_unlock(&nf_ct_frag6_lock);
+ return 0;
+
+err:
+ return -1;
+}
+
+/*
+ * Check if this packet is complete.
+ * Returns NULL on failure by any reason, and pointer
+ * to current nexthdr field in reassembled frame.
+ *
+ * It is called with locked fq, and caller must check that
+ * queue is eligible for reassembly i.e. it is not COMPLETE,
+ * the last and the first frames arrived and all the bits are here.
+ */
+static struct sk_buff *
+nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
+{
+ struct sk_buff *fp, *op, *head = fq->fragments;
+ int payload_len;
+
+ fq_kill(fq);
+
+ BUG_TRAP(head != NULL);
+ BUG_TRAP(NFCT_FRAG6_CB(head)->offset == 0);
+
+ /* Unfragmented part is taken from the first segment. */
+ payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);
+ if (payload_len > IPV6_MAXPLEN) {
+ DEBUGP("payload len is too large.\n");
+ goto out_oversize;
+ }
+
+ /* Head of list must not be cloned. */
+ if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
+ DEBUGP("skb is cloned but can't expand head");
+ goto out_oom;
+ }
+
+ /* If the first fragment is fragmented itself, we split
+ * it to two chunks: the first with data and paged part
+ * and the second, holding only fragments. */
+ if (skb_shinfo(head)->frag_list) {
+ struct sk_buff *clone;
+ int i, plen = 0;
+
+ if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) {
+ DEBUGP("Can't alloc skb\n");
+ goto out_oom;
+ }
+ clone->next = head->next;
+ head->next = clone;
+ skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+ skb_shinfo(head)->frag_list = NULL;
+ for (i=0; i<skb_shinfo(head)->nr_frags; i++)
+ plen += skb_shinfo(head)->frags[i].size;
+ clone->len = clone->data_len = head->data_len - plen;
+ head->data_len -= clone->len;
+ head->len -= clone->len;
+ clone->csum = 0;
+ clone->ip_summed = head->ip_summed;
+
+ NFCT_FRAG6_CB(clone)->orig = NULL;
+ atomic_add(clone->truesize, &nf_ct_frag6_mem);
+ }
+
+ /* We have to remove fragment header from datagram and to relocate
+ * header in order to calculate ICV correctly. */
+ head->nh.raw[fq->nhoffset] = head->h.raw[0];
+ memmove(head->head + sizeof(struct frag_hdr), head->head,
+ (head->data - head->head) - sizeof(struct frag_hdr));
+ head->mac.raw += sizeof(struct frag_hdr);
+ head->nh.raw += sizeof(struct frag_hdr);
+
+ skb_shinfo(head)->frag_list = head->next;
+ head->h.raw = head->data;
+ skb_push(head, head->data - head->nh.raw);
+ atomic_sub(head->truesize, &nf_ct_frag6_mem);
+
+ for (fp=head->next; fp; fp = fp->next) {
+ head->data_len += fp->len;
+ head->len += fp->len;
+ if (head->ip_summed != fp->ip_summed)
+ head->ip_summed = CHECKSUM_NONE;
+ else if (head->ip_summed == CHECKSUM_HW)
+ head->csum = csum_add(head->csum, fp->csum);
+ head->truesize += fp->truesize;
+ atomic_sub(fp->truesize, &nf_ct_frag6_mem);
+ }
+
+ head->next = NULL;
+ head->dev = dev;
+ head->stamp = fq->stamp;
+ head->nh.ipv6h->payload_len = htons(payload_len);
+
+ /* Yes, and fold redundant checksum back. 8) */
+ if (head->ip_summed == CHECKSUM_HW)
+ head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+
+ fq->fragments = NULL;
+
+ /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
+ fp = skb_shinfo(head)->frag_list;
+ if (NFCT_FRAG6_CB(fp)->orig == NULL)
+ /* at above code, head skb is divided into two skbs. */
+ fp = fp->next;
+
+ op = NFCT_FRAG6_CB(head)->orig;
+ for (; fp; fp = fp->next) {
+ struct sk_buff *orig = NFCT_FRAG6_CB(fp)->orig;
+
+ op->next = orig;
+ op = orig;
+ NFCT_FRAG6_CB(fp)->orig = NULL;
+ }
+
+ return head;
+
+out_oversize:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "nf_ct_frag6_reasm: payload len = %d\n", payload_len);
+ goto out_fail;
+out_oom:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "nf_ct_frag6_reasm: no memory for reassembly\n");
+out_fail:
+ return NULL;
+}
+
+/*
+ * find the header just before Fragment Header.
+ *
+ * if success return 0 and set ...
+ * (*prevhdrp): the value of "Next Header Field" in the header
+ * just before Fragment Header.
+ * (*prevhoff): the offset of "Next Header Field" in the header
+ * just before Fragment Header.
+ * (*fhoff) : the offset of Fragment Header.
+ *
+ * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
+ *
+ */
+static int
+find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
+{
+ u8 nexthdr = skb->nh.ipv6h->nexthdr;
+ u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
+ int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
+ int len = skb->len - start;
+ u8 prevhdr = NEXTHDR_IPV6;
+
+ while (nexthdr != NEXTHDR_FRAGMENT) {
+ struct ipv6_opt_hdr hdr;
+ int hdrlen;
+
+ if (!ipv6_ext_hdr(nexthdr)) {
+ return -1;
+ }
+ if (len < (int)sizeof(struct ipv6_opt_hdr)) {
+ DEBUGP("too short\n");
+ return -1;
+ }
+ if (nexthdr == NEXTHDR_NONE) {
+ DEBUGP("next header is none\n");
+ return -1;
+ }
+ if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+ BUG();
+ if (nexthdr == NEXTHDR_AUTH)
+ hdrlen = (hdr.hdrlen+2)<<2;
+ else
+ hdrlen = ipv6_optlen(&hdr);
+
+ prevhdr = nexthdr;
+ prev_nhoff = start;
+
+ nexthdr = hdr.nexthdr;
+ len -= hdrlen;
+ start += hdrlen;
+ }
+
+ if (len < 0)
+ return -1;
+
+ *prevhdrp = prevhdr;
+ *prevhoff = prev_nhoff;
+ *fhoff = start;
+
+ return 0;
+}
+
+struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
+{
+ struct sk_buff *clone;
+ struct net_device *dev = skb->dev;
+ struct frag_hdr *fhdr;
+ struct nf_ct_frag6_queue *fq;
+ struct ipv6hdr *hdr;
+ int fhoff, nhoff;
+ u8 prevhdr;
+ struct sk_buff *ret_skb = NULL;
+
+ /* Jumbo payload inhibits frag. header */
+ if (skb->nh.ipv6h->payload_len == 0) {
+ DEBUGP("payload len = 0\n");
+ return skb;
+ }
+
+ if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
+ return skb;
+
+ clone = skb_clone(skb, GFP_ATOMIC);
+ if (clone == NULL) {
+ DEBUGP("Can't clone skb\n");
+ return skb;
+ }
+
+ NFCT_FRAG6_CB(clone)->orig = skb;
+
+ if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {
+ DEBUGP("message is too short.\n");
+ goto ret_orig;
+ }
+
+ clone->h.raw = clone->data + fhoff;
+ hdr = clone->nh.ipv6h;
+ fhdr = (struct frag_hdr *)clone->h.raw;
+
+ if (!(fhdr->frag_off & htons(0xFFF9))) {
+ DEBUGP("Invalid fragment offset\n");
+ /* It is not a fragmented frame */
+ goto ret_orig;
+ }
+
+ if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh)
+ nf_ct_frag6_evictor();
+
+ fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
+ if (fq == NULL) {
+ DEBUGP("Can't find and can't create new queue\n");
+ goto ret_orig;
+ }
+
+ spin_lock(&fq->lock);
+
+ if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
+ spin_unlock(&fq->lock);
+ DEBUGP("Can't insert skb to queue\n");
+ fq_put(fq);
+ goto ret_orig;
+ }
+
+ if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {
+ ret_skb = nf_ct_frag6_reasm(fq, dev);
+ if (ret_skb == NULL)
+ DEBUGP("Can't reassemble fragmented packets\n");
+ }
+ spin_unlock(&fq->lock);
+
+ fq_put(fq);
+ return ret_skb;
+
+ret_orig:
+ kfree_skb(clone);
+ return skb;
+}
+
+void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+ struct net_device *in, struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct sk_buff *s, *s2;
+
+ for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
+ nf_conntrack_put(s->nfct);
+ nf_conntrack_get(skb->nfct);
+ s->nfct = skb->nfct;
+ s->nfcache = skb->nfcache;
+
+ nf_conntrack_put_reasm(s->reasm);
+ nf_conntrack_get_reasm(skb);
+ s->reasm = skb;
+
+ s2 = s->next;
+ NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,
+ NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+ s = s2;
+ }
+}
+
+int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
+{
+ struct sk_buff *s, *s2;
+
+ for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) {
+
+ s2 = s->next;
+ kfree_skb(s);
+ }
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
+int nf_ct_frag6_init(void)
+{
+ nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+ (jiffies ^ (jiffies >> 6)));
+
+ init_timer(&nf_ct_frag6_secret_timer);
+ nf_ct_frag6_secret_timer.function = nf_ct_frag6_secret_rebuild;
+ nf_ct_frag6_secret_timer.expires = jiffies
+ + nf_ct_frag6_secret_interval;
+ add_timer(&nf_ct_frag6_secret_timer);
+
+ return 0;
+}
+
+void nf_ct_frag6_cleanup(void)
+{
+ del_timer(&nf_ct_frag6_secret_timer);
+ nf_ct_frag6_evictor();
+}
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Kconfig
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Kconfig 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Kconfig 2004-11-01 07:38:59 UTC (rev 3260)
@@ -2,12 +2,66 @@
# protocol independent part of netfilter configuration
#
+menu "Generic Netfilter Configuration"
+ depends on INET && NETFILTER
+
config NF_CONNTRACK
- tristate
+ tristate "Layer 3 Independent Connection tracking (EXPERIMENTAL)"
depends on EXPERIMENTAL && NET
default n
+ ---help---
+ Connection tracking keeps a record of what packets have passed
+ through your machine, in order to figure out how they are related
+ into connections.
-config NF_CONNTRACK_FTP
- tristate
+ Layer 3 independent connection tracking is experimental scheme
+ which generalize ip_conntrack to support other layer 3 protocols.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config NF_CT_ACCT
+ bool "Connection tracking flow accounting"
+ depends on NF_CONNTRACK
+ help
+ If this option is enabled, the connection tracking code will
+ keep per-flow packet and byte counters.
+
+ Those counters can be used for flow-based accounting or the
+ `connbytes' match.
+
+ If unsure, say `N'.
+
+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 NF_CT_PROTO_SCTP
+ tristate 'SCTP protocol on new connection tracking support (EXPERIMENTAL)'
depends on EXPERIMENTAL && NET && NF_CONNTRACK
default n
+ help
+ With this option enabled, the layer 3 independent connection
+ tracking code will be able to do state tracking on SCTP connections.
+
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
+config NF_CONNTRACK_FTP
+ tristate "FTP support on new connection tracking (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && NF_CONNTRACK
+ help
+ Tracking FTP connections is problematic: special helpers are
+ required for tracking them, and doing masquerading and other forms
+ of Network Address Translation on them.
+
+ This is FTP support on Layer 3 independent connection tracking.
+ Layer 3 independent connection tracking is experimental scheme
+ which generalize ip_conntrack to support other layer 3 protocols.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+endmenu
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Makefile
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Makefile 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/Makefile 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,4 +1,7 @@
-nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
+nf_conntrack-objs := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
+
+# SCTP protocol connection tracking
+obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_core.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_core.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_core.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -31,12 +31,16 @@
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
-#include <net/checksum.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/jhash.h>
#include <linux/err.h>
+#include <linux/percpu.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
/* This rwlock protects the main hash table, protocol/helper/expected
registrations, conntrack timers*/
@@ -61,18 +65,23 @@
DECLARE_RWLOCK(nf_conntrack_lock);
DECLARE_RWLOCK(nf_conntrack_expect_tuple_lock);
+/* nf_conntrack_standalone needs this */
+atomic_t nf_conntrack_count = ATOMIC_INIT(0);
+
void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL;
LIST_HEAD(nf_conntrack_expect_list);
-LIST_HEAD(l3proto_list);
-LIST_HEAD(protocol_list);
+struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
+struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX];
static LIST_HEAD(helpers);
unsigned int nf_conntrack_htable_size = 0;
int nf_conntrack_max;
-static atomic_t nf_conntrack_count = ATOMIC_INIT(0);
struct list_head *nf_conntrack_hash;
+static kmem_cache_t *nf_conntrack_expect_cachep;
struct nf_conn nf_conntrack_untracked;
+unsigned int nf_ct_log_invalid;
-extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
+DEFINE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
/*
* This scheme offers various size of "struct nf_conn" dependent on
@@ -91,87 +100,34 @@
kmem_cache_t *cachep;
/* allocated slab cache + modules which uses this slab cache */
- atomic_t use;
+ int use;
/* Initialization */
int (*init_conntrack)(struct nf_conn *, u_int32_t);
- /* copying */
- int (*copy_conntrack)(struct nf_conn *, const struct nf_conn *);
} nf_ct_cache[NF_CT_F_NUM];
/* protect members of nf_ct_cache except of "use" */
DECLARE_RWLOCK(nf_ct_cache_lock);
-static inline int
-proto_cmpfn(const struct nf_conntrack_protocol *curr, u_int16_t l3proto,
- u_int8_t protocol)
-{
- return ((l3proto == curr->l3proto) && (protocol == curr->proto));
-}
+/* This avoids calling kmem_cache_create() with same name simultaneously */
+DECLARE_MUTEX(nf_ct_cache_mutex);
+extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
struct nf_conntrack_protocol *
-__nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol)
-{
- struct nf_conntrack_protocol *p;
-
- MUST_BE_READ_LOCKED(&nf_conntrack_lock);
- p = LIST_FIND(&protocol_list, proto_cmpfn,
- struct nf_conntrack_protocol *, l3proto, protocol);
- if (!p)
- p = &nf_conntrack_generic_protocol;
-
- return p;
-}
-
-struct nf_conntrack_protocol *
nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol)
{
- struct nf_conntrack_protocol *p;
+ if (unlikely(nf_ct_protos[l3proto] == NULL))
+ return &nf_conntrack_generic_protocol;
- READ_LOCK(&nf_conntrack_lock);
- p = __nf_ct_find_proto(l3proto, protocol);
- READ_UNLOCK(&nf_conntrack_lock);
- return p;
+ return nf_ct_protos[l3proto][protocol];
}
-static inline int l3proto_cmpfn(const struct nf_conntrack_l3proto *curr,
- u_int16_t protocol)
-{
- return protocol == curr->l3proto;
-}
-
-struct nf_conntrack_l3proto *
-__nf_ct_find_l3proto(u_int16_t protocol)
-{
- struct nf_conntrack_l3proto *p;
-
- MUST_BE_READ_LOCKED(&nf_conntrack_lock);
- p = LIST_FIND(&l3proto_list, l3proto_cmpfn,
- struct nf_conntrack_l3proto *, protocol);
-
- return p;
-}
-
-struct nf_conntrack_l3proto *
-nf_ct_find_l3proto(u_int16_t protocol)
-{
- struct nf_conntrack_l3proto *p;
-
- READ_LOCK(&nf_conntrack_lock);
- p = __nf_ct_find_l3proto(protocol);
- READ_UNLOCK(&nf_conntrack_lock);
- return p;
-}
-
inline void
nf_ct_put(struct nf_conn *ct)
{
NF_CT_ASSERT(ct);
- NF_CT_ASSERT(ct->infos[0].master);
- /* nf_conntrack_put wants to go via an info struct, so feed it
- one at random. */
- nf_conntrack_put(&ct->infos[0]);
+ nf_conntrack_put(&ct->ct_general);
}
static int nf_conntrack_hash_rnd_initted;
@@ -193,7 +149,7 @@
READ_LOCK(&nf_ct_cache_lock);
- if (!nf_ct_cache[features].cachep) {
+ if (!nf_ct_cache[features].use) {
DEBUGP("alloc_conntrack: not supported features = 0x%x\n",
features);
goto out;
@@ -229,212 +185,6 @@
kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
}
-/* copy conntrack. don't set timer and don't copy sibling list */
-static int
-copy_conntrack(struct nf_conn *dst, const struct nf_conn *src)
-{
- int i;
-
- DEBUGP("copy_conntarck: src=%p, dst=%p\n", src, dst);
-
- atomic_set(&dst->ct_general.use, atomic_read(&src->ct_general.use));
- dst->ct_general.destroy = src->ct_general.destroy;
- memcpy(&dst->tuplehash[NF_CT_DIR_ORIGINAL].tuple,
- &src->tuplehash[NF_CT_DIR_ORIGINAL].tuple,
- sizeof(struct nf_conntrack_tuple));
- dst->tuplehash[NF_CT_DIR_ORIGINAL].ctrack = dst;
- memcpy(&dst->tuplehash[NF_CT_DIR_REPLY].tuple,
- &src->tuplehash[NF_CT_DIR_REPLY].tuple,
- sizeof(struct nf_conntrack_tuple));
- dst->tuplehash[NF_CT_DIR_REPLY].ctrack = dst;
- dst->status = src->status;
- init_timer(&dst->timeout);
- dst->timeout.data = (unsigned long)dst;
- dst->timeout.function = src->timeout.function;
- INIT_LIST_HEAD(&dst->sibling_list);
- dst->expecting = src->expecting;
- dst->master = src->master;
- dst->helper = src->helper;
- for (i=0; i < NF_CT_NUMBER; i++)
- dst->infos[i].master = &dst->ct_general;
- dst->proto = src->proto;
-
- /* copy other parts if needed */
- if (nf_ct_cache[dst->features].copy_conntrack)
- return nf_ct_cache[dst->features].copy_conntrack(dst, src);
-
- return 0;
-}
-
-/* meaningful in only reallocate_conntrack() */
-static int
-replace_conntrack(struct nf_conn *to, struct nf_conn *from)
-{
- u_int32_t ho, hr;
- struct list_head *exp_entry;
- struct nf_conntrack_expect *exp;
-
- MUST_BE_READ_LOCKED(&nf_conntrack_lock);
-
- DEBUGP("replace_conntrack: from = %p, to = %p\n", from, to);
-
- to->timeout.expires = from->timeout.expires;
-
- /* destroyed soon ? */
- if (!del_timer(&from->timeout)) {
- DEBUGP("replace_conntrack: already timer has be expired\n");
- return -1;
- }
-
- ho = hash_conntrack(&from->tuplehash[NF_CT_DIR_ORIGINAL].tuple);
- hr = hash_conntrack(&from->tuplehash[NF_CT_DIR_REPLY].tuple);
- LIST_DELETE(&nf_conntrack_hash[ho],
- &from->tuplehash[NF_CT_DIR_ORIGINAL]);
- LIST_DELETE(&nf_conntrack_hash[hr],
- &from->tuplehash[NF_CT_DIR_REPLY]);
-
- WRITE_LOCK(&nf_conntrack_expect_tuple_lock);
-
- list_for_each(exp_entry, &from->sibling_list) {
- exp = list_entry(exp_entry, struct nf_conntrack_expect,
- expected_list);
- if (exp->expectant)
- exp->expectant = to;
- }
-
- list_add(&to->sibling_list, &from->sibling_list);
- list_del(&from->sibling_list);
-
- if (from->master) {
- to->master = from->master;
- to->master->sibling = to;
- }
-
- WRITE_UNLOCK(&nf_conntrack_expect_tuple_lock);
-
- add_timer(&to->timeout);
-
- list_prepend(&nf_conntrack_hash[ho],
- &to->tuplehash[NF_CT_DIR_ORIGINAL]);
- list_prepend(&nf_conntrack_hash[hr],
- &to->tuplehash[NF_CT_DIR_REPLY]);
-
- return 0;
-}
-
-/* reallocate conntrack from other slab */
-static int reallocate_conntrack(struct nf_conn *conntrack)
-{
- struct nf_conntrack_l3proto *l3proto;
- struct nf_conn *tmp_conntrack;
- u_int32_t features;
-
- MUST_BE_READ_LOCKED(&nf_conntrack_lock);
-
- DEBUGP("reallocate_conntrack: conntrack=%p\n", conntrack);
- /* find features needed by this conntrack. */
- l3proto = __nf_ct_find_l3proto(conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.src.l3num);
- NF_CT_ASSERT(l3proto);
- features = l3proto->get_features(
- &conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple);
-
- if (nf_ct_find_helper(&conntrack->tuplehash[NF_CT_DIR_REPLY].tuple))
- features |= NF_CT_F_HELP;
-
- if (conntrack->features == features) {
- DEBUGP("reallocate_conntrack: same features required\n");
- return -1;
- }
-
- tmp_conntrack = alloc_conntrack(features);
- if (!tmp_conntrack) {
- DEBUGP("reallocate_conntrack: Can't allocate conntrack.\n");
- return -1;
- }
-
- if (copy_conntrack(tmp_conntrack, conntrack) < 0) {
- DEBUGP("reallocate_conntrack: Can't copy conntrack.\n");
- free_conntrack(tmp_conntrack);
- return -1;
- }
-
- if (replace_conntrack(tmp_conntrack, conntrack) < 0) {
- DEBUGP("reallocate_conntrack: Can't replace conntrack.\n");
- free_conntrack(tmp_conntrack);
- return -1;
- }
-
- free_conntrack(conntrack);
-
- return 0;
-}
-
-static void
-nf_conntrack_destroy_cache(u_int32_t features)
-{
- kmem_cache_t *cachep;
- char *name;
- int i;
- struct nf_conntrack_tuple_hash *hash, *next_hash;
- struct list_head *hash_entry, *next;
-
- DEBUGP("nf_conntrack_destroy_cache: features=0x%x\n", features);
- NF_CT_ASSERT(atomic_read(&nf_ct_cache[features].use));
-
- synchronize_net();
-
- /* reallocate conntrack from other slab caches. */
- WRITE_LOCK(&nf_conntrack_lock);
-
- for (i = 0; i < nf_conntrack_htable_size; i++) {
- list_for_each_safe(hash_entry, next, &nf_conntrack_hash[i]) {
- hash = list_entry(hash_entry,
- struct nf_conntrack_tuple_hash,
- list);
-
- /* prevent "next" from grabbing inverse tuple_hash of
- the same conntrack. */
- next_hash = list_entry(next,
- struct nf_conntrack_tuple_hash,
- list);
- if (hash->ctrack == next_hash->ctrack) {
- DEBUGP("next conntrack is same as this one.\n");
- next = next->next;
- }
-
- if (hash->ctrack->features != features)
- continue;
-
- if (reallocate_conntrack(hash->ctrack) < 0) {
- DEBUGP("failed to realloc\n");
- nf_ct_put(hash->ctrack);
- }
- }
- }
- WRITE_UNLOCK(&nf_conntrack_lock);
-
- WRITE_LOCK(&nf_ct_cache_lock);
- cachep = nf_ct_cache[features].cachep;
- name = nf_ct_cache[features].name;
- nf_ct_cache[features].cachep = NULL;
- nf_ct_cache[features].name = NULL;
- nf_ct_cache[features].init_conntrack = NULL;
- nf_ct_cache[features].copy_conntrack = NULL;
- nf_ct_cache[features].size = 0;
- WRITE_UNLOCK(&nf_ct_cache_lock);
-
- kmem_cache_destroy(cachep);
- kfree(name);
-}
-
-static void
-nf_conntrack_put_cache(u_int32_t features)
-{
- if (atomic_dec_and_test(&nf_ct_cache[features].use))
- nf_conntrack_destroy_cache(features);
-}
-
/* Initialize "struct nf_conn" which has spaces for helper */
static int
init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features)
@@ -447,27 +197,9 @@
return 0;
}
-/* copy "struct nf_conn" which has spaces for helper */
-static int
-copy_conntrack_for_helper(struct nf_conn *dst, const struct nf_conn *src)
-{
- NF_CT_ASSERT(dst->help);
-
- if (!src->help) {
- DEBUGP("copy_conntrack_for_helper: helper dependent data is none.\n");
- return 0;
- }
-
- memcpy(dst->help, src->help, sizeof(union nf_conntrack_help));
-
- return 0;
-}
-
int nf_conntrack_register_cache(u_int32_t features, const char *name,
size_t size,
- int (*init)(struct nf_conn *, u_int32_t),
- int (*copy)(struct nf_conn *,
- const struct nf_conn *))
+ int (*init)(struct nf_conn *, u_int32_t))
{
int ret = 0;
char *cache_name;
@@ -479,84 +211,108 @@
if (features < NF_CT_F_BASIC || features >= NF_CT_F_NUM) {
DEBUGP("nf_conntrack_register_cache: invalid features.: 0x%x\n",
features);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
+ down(&nf_ct_cache_mutex);
+
+ WRITE_LOCK(&nf_ct_cache_lock);
+ /* e.g: multiple helpers are loaded */
+ if (nf_ct_cache[features].use > 0) {
+ DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
+ if ((!strncmp(nf_ct_cache[features].name, name,
+ NF_CT_FEATURES_NAMELEN))
+ && nf_ct_cache[features].size == size
+ && nf_ct_cache[features].init_conntrack == init) {
+ DEBUGP("nf_conntrack_register_cache: reusing.\n");
+ nf_ct_cache[features].use++;
+ ret = 0;
+ } else
+ ret = -EBUSY;
+
+ WRITE_UNLOCK(&nf_ct_cache_lock);
+ up(&nf_ct_cache_mutex);
+ return ret;
+ }
+ WRITE_UNLOCK(&nf_ct_cache_lock);
+
/*
- * There are some restrictions to call kmem_cache_create().
- * 1. The memory space for name of slab cache must be alive until
- * cache is destroyed.
- * 2. kmem_cache_create() can't be called while locking since it may
- * sleep.
+ * The memory space for name of slab cache must be alive until
+ * cache is destroyed.
*/
cache_name = kmalloc(sizeof(char)*NF_CT_FEATURES_NAMELEN, GFP_ATOMIC);
if (cache_name == NULL) {
- DEBUGP("can't alloc for cache_name\n");
+ DEBUGP("nf_conntrack_register_cache: can't alloc cache_name\n");
ret = -ENOMEM;
- goto out;
+ goto out_up_mutex;
}
- strlcpy(cache_name, name, NF_CT_FEATURES_NAMELEN);
+ if (strlcpy(cache_name, name, NF_CT_FEATURES_NAMELEN)
+ >= NF_CT_FEATURES_NAMELEN) {
+ printk("nf_conntrack_register_cache: name too long\n");
+ ret = -EINVAL;
+ goto out_free_name;
+ }
+
cachep = kmem_cache_create(cache_name, size, 0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!cachep) {
- printk("Can't create slab cache for the features = 0x%x\n",
- features);
+ printk("nf_conntrack_register_cache: Can't create slab cache "
+ "for the features = 0x%x\n", features);
ret = -ENOMEM;
goto out_free_name;
}
WRITE_LOCK(&nf_ct_cache_lock);
- /* e.g: multiple helpers are loaded */
- if (nf_ct_cache[features].cachep) {
- DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
- if (strncmp(nf_ct_cache[features].name, name,
- NF_CT_FEATURES_NAMELEN)
- && nf_ct_cache[features].size == size
- && nf_ct_cache[features].init_conntrack == init
- && nf_ct_cache[features].copy_conntrack == copy) {
- DEBUGP("nf_conntrack_register_cache: reusing.\n");
- atomic_inc(&nf_ct_cache[features].use);
- ret = 0;
- goto out_unlock;
- }
- ret = -EBUSY;
- goto out_unlock;
- }
-
- atomic_set(&nf_ct_cache[features].use, 1);
+ nf_ct_cache[features].use = 1;
nf_ct_cache[features].size = size;
nf_ct_cache[features].init_conntrack = init;
- nf_ct_cache[features].copy_conntrack = copy;
nf_ct_cache[features].cachep = cachep;
nf_ct_cache[features].name = cache_name;
-
WRITE_UNLOCK(&nf_ct_cache_lock);
- return ret;
-out_unlock:
- WRITE_UNLOCK(&nf_ct_cache_lock);
- kmem_cache_destroy(cachep);
+ goto out_up_mutex;
+
out_free_name:
kfree(cache_name);
-out:
+out_up_mutex:
+ up(&nf_ct_cache_mutex);
return ret;
}
-/* slab cache may not be destroyed bacause some conntracks are still alive. */
-void
-nf_conntrack_unregister_cache(u_int32_t features)
+/* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
+void nf_conntrack_unregister_cache(u_int32_t features)
{
- READ_LOCK(&nf_ct_cache_lock);
- if (!nf_ct_cache[features].cachep) {
- DEBUGP("nf_conntrack_unregister_cache: not registered features. : 0x%x\n",
- features);
- READ_UNLOCK(&nf_ct_cache_lock);
+ kmem_cache_t *cachep;
+ char *name;
+
+ /*
+ * This assures that kmem_cache_create() isn't called before destroying
+ * slab cache.
+ */
+ DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features);
+ down(&nf_ct_cache_mutex);
+
+ WRITE_LOCK(&nf_ct_cache_lock);
+ if (--nf_ct_cache[features].use > 0) {
+ WRITE_UNLOCK(&nf_ct_cache_lock);
+ up(&nf_ct_cache_mutex);
return;
}
- READ_UNLOCK(&nf_ct_cache_lock);
- nf_conntrack_put_cache(features);
+ cachep = nf_ct_cache[features].cachep;
+ name = nf_ct_cache[features].name;
+ nf_ct_cache[features].cachep = NULL;
+ nf_ct_cache[features].name = NULL;
+ nf_ct_cache[features].init_conntrack = NULL;
+ nf_ct_cache[features].size = 0;
+ WRITE_UNLOCK(&nf_ct_cache_lock);
+
+ synchronize_net();
+
+ kmem_cache_destroy(cachep);
+ kfree(name);
+
+ up(&nf_ct_cache_mutex);
}
int
@@ -595,7 +351,6 @@
return protocol->invert_tuple(inverse, orig);
}
-
/* nf_conntrack_expect helper functions */
/* Compare tuple parts depending on mask. */
@@ -610,13 +365,13 @@
destroy_expect(struct nf_conntrack_expect *exp)
{
DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
- NF_CT_ASSERT(atomic_read(&exp->use));
+ NF_CT_ASSERT(atomic_read(&exp->use) == 0);
NF_CT_ASSERT(!timer_pending(&exp->timeout));
- kfree(exp);
+ kmem_cache_free(nf_conntrack_expect_cachep, exp);
+ NF_CT_STAT_INC(expect_delete);
}
-
inline void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
{
NF_CT_ASSERT(exp);
@@ -684,8 +439,7 @@
/* if we are supposed to have a timer, but we can't delete
* it: race condition. __unexpect_related will
* be calledd by timeout function */
- if (expect->expectant->helper->timeout
- && !del_timer(&expect->timeout))
+ if (expect->expectant->helper->timeout && !del_timer(&expect->timeout))
return;
__unexpect_related(expect);
@@ -779,7 +533,7 @@
list_del(&ct->master->expected_list);
master = ct->master->expectant;
}
- kfree(ct->master);
+ kmem_cache_free(nf_conntrack_expect_cachep, ct->master);
}
WRITE_UNLOCK(&nf_conntrack_lock);
@@ -789,13 +543,18 @@
DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
free_conntrack(ct);
atomic_dec(&nf_conntrack_count);
+ NF_CT_STAT_INC(delete);
}
static void death_by_timeout(unsigned long ul_conntrack)
{
struct nf_conn *ct = (void *)ul_conntrack;
+
WRITE_LOCK(&nf_conntrack_lock);
+ /* Inside lock so preempt is disabled on module removal path.
+ * Otherwise we can get spurious warnings. */
+ NF_CT_STAT_INC(delete_list);
clean_from_lists(ct);
WRITE_UNLOCK(&nf_conntrack_lock);
nf_ct_put(ct);
@@ -817,13 +576,19 @@
{
struct nf_conntrack_tuple_hash *h;
unsigned int hash = hash_conntrack(tuple);
+ /* use per_cpu() to avoid multiple calls to smp_processor_id() */
+ unsigned int cpu = smp_processor_id();
MUST_BE_READ_LOCKED(&nf_conntrack_lock);
- h = LIST_FIND(&nf_conntrack_hash[hash],
- conntrack_tuple_cmp,
- struct nf_conntrack_tuple_hash *,
- tuple, ignored_conntrack);
- return h;
+ list_for_each_entry(h, &nf_conntrack_hash[hash], list) {
+ if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) {
+ per_cpu(nf_conntrack_stat, cpu).found++;
+ return h;
+ }
+ per_cpu(nf_conntrack_stat, cpu).searched++;
+ }
+
+ return NULL;
}
/* Find a connection corresponding to a tuple. */
@@ -842,36 +607,15 @@
return h;
}
-static inline struct nf_conn *
-__nf_ct_get(struct nf_ct_info *nfct, enum nf_conntrack_info *ctinfo)
+/* Confirm a connection given skb; places it in hash table */
+int
+__nf_conntrack_confirm(struct sk_buff *skb)
{
- struct nf_conn *ct
- = (struct nf_conn *)nfct->master;
-
- /* ctinfo is the index of the nfct inside the conntrack */
- *ctinfo = nfct - ct->infos;
- NF_CT_ASSERT(*ctinfo >= 0 && *ctinfo < NF_CT_NUMBER);
- return ct;
-}
-
-/* Return conntrack and conntrack_info given skb->nfct->master */
-struct nf_conn *
-nf_ct_get(struct sk_buff *skb, enum nf_conntrack_info *ctinfo)
-{
- if (skb->nfct)
- return __nf_ct_get(skb->nfct, ctinfo);
- return NULL;
-}
-
-/* Confirm a connection given skb->nfct; places it in hash table */
-static int
-__nf_conntrack_confirm(struct nf_ct_info *nfct)
-{
unsigned int hash, repl_hash;
struct nf_conn *ct;
enum nf_conntrack_info ctinfo;
- ct = __nf_ct_get(nfct, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
/* ipt_REJECT uses nf_conntrack_attach to attach related
ICMP/TCP RST packets in other direction. Actual packet
@@ -919,23 +663,16 @@
atomic_inc(&ct->ct_general.use);
set_bit(NF_S_CONFIRMED_BIT, &ct->status);
WRITE_UNLOCK(&nf_conntrack_lock);
+ NF_CT_STAT_INC(insert);
return NF_ACCEPT;
}
WRITE_UNLOCK(&nf_conntrack_lock);
+ NF_CT_STAT_INC(insert_failed);
DEBUGP("__nf_conntrack_confirm: duplicated conntrack\n");
return NF_DROP;
}
-int nf_conntrack_confirm(struct sk_buff *skb)
-{
-
- if (skb->nfct
- && !is_confirmed((struct nf_conn *)skb->nfct->master))
- return __nf_conntrack_confirm(skb->nfct);
- return NF_ACCEPT;
-}
-
/* Returns true if a connection correspondings to the tuple (required
for NAT). */
int
@@ -976,6 +713,7 @@
if (del_timer(&h->ctrack->timeout)) {
death_by_timeout((unsigned long)h->ctrack);
dropped = 1;
+ NF_CT_STAT_INC(early_drop);
}
nf_ct_put(h->ctrack);
return dropped;
@@ -987,7 +725,8 @@
return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
}
-struct nf_conntrack_helper *nf_ct_find_helper(const struct nf_conntrack_tuple *tuple)
+struct nf_conntrack_helper *
+nf_ct_find_helper(const struct nf_conntrack_tuple *tuple)
{
return LIST_FIND(&helpers, helper_cmp,
struct nf_conntrack_helper *,
@@ -1007,10 +746,8 @@
struct nf_conntrack_tuple repl_tuple;
size_t hash;
struct nf_conntrack_expect *expected;
- int i;
- static unsigned int drop_next;
u_int32_t features = 0;
- struct nf_conntrack_helper *helper;
+ int helper_used = 0;
if (!nf_conntrack_hash_rnd_initted) {
get_random_bytes(&nf_conntrack_hash_rnd, 4);
@@ -1019,15 +756,10 @@
hash = hash_conntrack(tuple);
- if (nf_conntrack_max &&
- atomic_read(&nf_conntrack_count) >= nf_conntrack_max) {
- /* Try dropping from random chain, or else from the
- chain about to put into (in case they're trying to
- bomb one hash chain). */
- unsigned int next = (drop_next++)%nf_conntrack_htable_size;
-
- if (!early_drop(&nf_conntrack_hash[next])
- && !early_drop(&nf_conntrack_hash[hash])) {
+ if (nf_conntrack_max
+ && atomic_read(&nf_conntrack_count) >= nf_conntrack_max) {
+ /* Try dropping from this hash chain. */
+ if (!early_drop(&nf_conntrack_hash[hash])) {
if (net_ratelimit())
printk(KERN_WARNING
"nf_conntrack: table full, dropping"
@@ -1043,9 +775,12 @@
/* find features needed by this conntrack. */
features = l3proto->get_features(tuple);
- helper = nf_ct_find_helper(&repl_tuple);
- if (helper != NULL)
+ READ_LOCK(&nf_conntrack_lock);
+ if (nf_ct_find_helper(&repl_tuple) != NULL) {
features |= NF_CT_F_HELP;
+ helper_used = 1;
+ }
+ READ_UNLOCK(&nf_conntrack_lock);
conntrack = alloc_conntrack(features);
if (!conntrack) {
@@ -1059,8 +794,6 @@
conntrack->tuplehash[NF_CT_DIR_ORIGINAL].ctrack = conntrack;
conntrack->tuplehash[NF_CT_DIR_REPLY].tuple = repl_tuple;
conntrack->tuplehash[NF_CT_DIR_REPLY].ctrack = conntrack;
- for (i=0; i < NF_CT_NUMBER; i++)
- conntrack->infos[i].master = &conntrack->ct_general;
if (!protocol->new(conntrack, skb, dataoff)) {
free_conntrack(conntrack);
@@ -1081,42 +814,62 @@
struct nf_conntrack_expect *, tuple);
READ_UNLOCK(&nf_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;
+ 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)) {
+ /* This avoids timing problem. helper may be unloaded
+ after allocating conntrack */
+ if (helper_used)
+ conntrack->helper =
+ nf_ct_find_helper(&repl_tuple);
+ goto end;
+ }
- /* Look up the conntrack helper for master connections only */
- if (!expected)
- conntrack->helper = helper;
+ /* Expectation is dying... */
+ if (expected->expectant->helper->timeout
+ && !del_timer(&expected->timeout))
+ goto end;
- /* If the expectation is dying, then this is a loser. */
- if (expected
- && expected->expectant->helper->timeout
- && ! del_timer(&expected->timeout))
- expected = NULL;
-
- if (expected) {
DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
conntrack, expected);
/* Welcome, Mr. Bond. We've been expecting you... */
- NF_CT_ASSERT(master_ct(conntrack));
+ NF_CT_ASSERT(expected->expectant);
__set_bit(NF_S_EXPECTED_BIT, &conntrack->status);
conntrack->master = expected;
expected->sibling = conntrack;
+#if CONFIG_NF_CONNTRACK_MARK
+ conntrack->mark = expected->expectant->mark;
+#endif
LIST_DELETE(&nf_conntrack_expect_list, expected);
expected->expectant->expecting--;
- nf_conntrack_get(&master_ct(conntrack)->infos[0]);
- }
+ nf_conntrack_get(&master_ct(conntrack)->ct_general);
+
+ /* this is a braindead... --pablo */
+ atomic_inc(&nf_conntrack_count);
+ WRITE_UNLOCK(&nf_conntrack_lock);
+
+ if (expected->expectfn)
+ expected->expectfn(conntrack);
+
+ NF_CT_STAT_INC(expect_new);
+
+ goto ret;
+ } else {
+ /* This avoids timing problem. helper may be unloaded
+ after allocating conntrack */
+ if (helper_used)
+ conntrack->helper = nf_ct_find_helper(&repl_tuple);
+ }
+
+end: NF_CT_STAT_INC(new);
atomic_inc(&nf_conntrack_count);
WRITE_UNLOCK(&nf_conntrack_lock);
- if (expected && expected->expectfn)
- expected->expectfn(conntrack);
- return &conntrack->tuplehash[NF_CT_DIR_ORIGINAL];
+ret: return &conntrack->tuplehash[NF_CT_DIR_ORIGINAL];
}
/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
@@ -1134,7 +887,8 @@
struct nf_conntrack_tuple_hash *h;
if (!nf_ct_get_tuple(skb, (unsigned int)(skb->nh.raw - skb->data),
- dataoff, l3num, protonum, &tuple, l3proto, proto)) {
+ dataoff, l3num, protonum, &tuple, l3proto,
+ proto)) {
DEBUGP("resolve_normal_ct: Can't get tuple\n");
return NULL;
}
@@ -1175,7 +929,8 @@
}
*set_reply = 0;
}
- skb->nfct = &h->ctrack->infos[*ctinfo];
+ skb->nfct = &h->ctrack->ct_general;
+ skb->nfctinfo = *ctinfo;
return h->ctrack;
}
@@ -1191,12 +946,15 @@
int set_reply;
int ret;
- l3proto = nf_ct_find_l3proto((u_int16_t)pf);
- if (l3proto == NULL) {
- DEBUGP("Can't find l3 module. pf=%d\n", pf);
+ /* Previously seen (loopback or untracked)? Ignore. */
+ if ((*pskb)->nfct) {
+ DEBUGP("loopback or untracked, nfct=0x%p\n", (*pskb)->nfct);
+ NF_CT_STAT_INC(ignore);
return NF_ACCEPT;
}
+ l3proto = nf_ct_find_l3proto((u_int16_t)pf);
+ DEBUGP("l3proto = %u\n", pf);
if (l3proto->prepare(pskb, hooknum, &dataoff, &protonum, &ret) == 0) {
DEBUGP("not prepared to track yet or error occured\n");
return ret;
@@ -1205,35 +963,50 @@
proto = nf_ct_find_proto((u_int16_t)pf, protonum);
DEBUGP("protonum = %u\n", protonum);
+ /* It may be an special packet, error, unclean...
+ * inverse of the return code tells to the netfilter
+ * core what to do with the packet. */
+ if (proto->error != NULL &&
+ (ret = proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) {
+ NF_CT_STAT_INC(error);
+ NF_CT_STAT_INC(invalid);
+ return -ret;
+ }
+
ct = resolve_normal_ct(*pskb, dataoff, pf, protonum, l3proto, proto,
&set_reply, &ctinfo);
if (!ct) {
/* Not valid part of a connection */
- DEBUGP("Not valid part of a connection\n");
+ DEBUGP("nf_conntrack_in: Not valid part of a connection\n");
+ NF_CT_STAT_INC(invalid);
return NF_ACCEPT;
}
if (IS_ERR(ct)) {
/* Too stressed to deal. */
- DEBUGP("Can't resolve normal connection\n");
+ DEBUGP("nf_conntrack_in: Can't resolve normal connection\n");
+ NF_CT_STAT_INC(drop);
return NF_DROP;
}
NF_CT_ASSERT((*pskb)->nfct);
- ret = proto->packet(ct, *pskb, dataoff, ctinfo, hooknum);
- if (ret == -1) {
- /* Invalid */
- DEBUGP("can't track with proto module\n");
+ ret = proto->packet(ct, *pskb, dataoff, ctinfo, pf, hooknum);
+ if (ret < 0) {
+ /* Invalid: inverse of the return code tells
+ * the netfilter core what to do */
+ DEBUGP("nf_conntrack_in: Can't track with proto module\n");
nf_conntrack_put((*pskb)->nfct);
(*pskb)->nfct = NULL;
- return NF_ACCEPT;
+ NF_CT_STAT_INC(invalid);
+ return -ret;
}
if (ret != NF_DROP && ct->helper) {
ret = ct->helper->help(*pskb, dataoff, ct, ctinfo);
if (ret == -1) {
/* Invalid */
+ NF_CT_STAT_INC(invalid);
nf_conntrack_put((*pskb)->nfct);
(*pskb)->nfct = NULL;
return NF_ACCEPT;
@@ -1318,8 +1091,7 @@
{
struct nf_conntrack_expect *new;
- new = (struct nf_conntrack_expect *)
- kmalloc(sizeof(struct nf_conntrack_expect), GFP_ATOMIC);
+ new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC);
if (!new) {
DEBUGP("expect_related: OOM allocating expect\n");
return NULL;
@@ -1327,6 +1099,7 @@
/* tuple_cmp compares whole union, we have to initialized cleanly */
memset(new, 0, sizeof(struct nf_conntrack_expect));
+ atomic_set(&new->use, 1);
return new;
}
@@ -1338,12 +1111,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(&nf_conntrack_expect_list, &new->list);
/* add and start timer if required */
if (related_to->helper->timeout) {
@@ -1392,12 +1163,12 @@
}
WRITE_UNLOCK(&nf_conntrack_lock);
- kfree(expect);
+ /* This expectation is not inserted so no need to lock */
+ kmem_cache_free(nf_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 &
NF_CT_HELPER_F_REUSE_EXPECT)) {
@@ -1413,7 +1184,7 @@
related_to->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.l3num,
NIP6(*(struct in6_addr *)related_to->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.u3.all),
NIP6(*(struct in6_addr *)related_to->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.u3.all));
- kfree(expect);
+ kmem_cache_free(nf_conntrack_expect_cachep, expect);
return -EPERM;
}
DEBUGP("nf_conntrack: max number of expected "
@@ -1426,21 +1197,14 @@
NIP6(*(struct in6_addr *)related_to->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.u3.all));
/* choose the the oldest expectation to evict */
- list_for_each(cur_item, &related_to->sibling_list) {
- struct nf_conntrack_expect *cur;
-
- cur = list_entry(cur_item,
- struct nf_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 */
- NF_CT_ASSERT(old);
+ /* We cannot fail since related_to->expecting is the number
+ * of unconfirmed expectations */
+ NF_CT_ASSERT(old && old->sibling == NULL);
/* newnat14 does not reuse the real allocated memory
* structures but rather unexpects the old and
@@ -1455,13 +1219,14 @@
WRITE_UNLOCK(&nf_conntrack_lock);
DEBUGP("expect_related: busy!\n");
- kfree(expect);
+ kmem_cache_free(nf_conntrack_expect_cachep, expect);
return -EBUSY;
}
out: nf_conntrack_expect_insert(expect, related_to);
WRITE_UNLOCK(&nf_conntrack_lock);
+ NF_CT_STAT_INC(expect_create);
return ret;
}
@@ -1538,8 +1303,7 @@
sizeof(struct nf_conn)
+ sizeof(union nf_conntrack_help)
+ __alignof__(union nf_conntrack_help),
- init_conntrack_for_helper,
- copy_conntrack_for_helper);
+ init_conntrack_for_helper);
if (ret < 0) {
printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
return ret;
@@ -1577,49 +1341,66 @@
struct nf_conntrack_tuple_hash *, me);
WRITE_UNLOCK(&nf_conntrack_lock);
- nf_conntrack_unregister_cache(NF_CT_F_HELP);
-
/* Someone could be still looking at the helper in a bh. */
synchronize_net();
}
-/* Refresh conntrack for this many jiffies. */
-void nf_ct_refresh(struct nf_conn *ct, unsigned long extra_jiffies)
+static inline void ct_add_counters(struct nf_conn *ct,
+ enum nf_conntrack_info ctinfo,
+ const struct sk_buff *skb)
{
+#ifdef CONFIG_NF_CT_ACCT
+ if (skb) {
+ ct->counters[NFCTINFO2DIR(ctinfo)].packets++;
+ /* XXX totlen should be used ? - kozakai */
+ ct->counters[NFCTINFO2DIR(ctinfo)].bytes +=
+ ntohs(skb->len - (unsigned int)(skb->nh.raw
+ - skb->data));
+ }
+#endif
+}
+
+/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */
+void nf_ct_refresh_acct(struct nf_conn *ct,
+ enum nf_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ unsigned long extra_jiffies)
+{
NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
/* If not in hash table, timer will not be active yet */
- if (!is_confirmed(ct))
+ if (!is_confirmed(ct)) {
ct->timeout.expires = extra_jiffies;
- else {
+ ct_add_counters(ct, ctinfo, skb);
+ } else {
WRITE_LOCK(&nf_conntrack_lock);
/* Need del_timer for race avoidance (may already be dying). */
if (del_timer(&ct->timeout)) {
ct->timeout.expires = jiffies + extra_jiffies;
add_timer(&ct->timeout);
}
+ ct_add_counters(ct, ctinfo, skb);
WRITE_UNLOCK(&nf_conntrack_lock);
}
}
-/* Used by ipt_REJECT. */
-static void __nf_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
+/* Used by ipt_REJECT and ip6t_REJECT. */
+static void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
{
struct nf_conn *ct;
enum nf_conntrack_info ctinfo;
- ct = __nf_ct_get(nfct, &ctinfo);
-
- /* This ICMP is in reverse direction to the packet which
- caused it */
+ /* This ICMP is in reverse direction to the packet which caused it */
+ ct = nf_ct_get(skb, &ctinfo);
if (NFCTINFO2DIR(ctinfo) == NF_CT_DIR_ORIGINAL)
ctinfo = NF_CT_RELATED + NF_CT_IS_REPLY;
else
ctinfo = NF_CT_RELATED;
- /* Attach new skbuff, and increment count */
- nskb->nfct = &ct->infos[ctinfo];
- atomic_inc(&ct->ct_general.use);
+ /* Attach to new skbuff, and increment count */
+ nskb->nfct = &ct->ct_general;
+ nskb->nfctinfo = ctinfo;
+ nf_conntrack_get(nskb->nfct);
}
static inline int
@@ -1675,6 +1456,8 @@
supposed to kill the mall. */
void nf_conntrack_cleanup(void)
{
+ int i;
+
nf_ct_attach = NULL;
/* This makes sure all current packets have passed through
netfilter framework. Roll on, two-stage module
@@ -1688,12 +1471,20 @@
goto i_see_dead_people;
}
- nf_conntrack_destroy_cache(NF_CT_F_BASIC);
+ for (i = 0; i < NF_CT_F_NUM; i++) {
+ if (nf_ct_cache[i].use == 0)
+ continue;
+
+ NF_CT_ASSERT(nf_ct_cache[i].use == 1);
+ nf_ct_cache[i].use = 1;
+ nf_conntrack_unregister_cache(i);
+ }
+ kmem_cache_destroy(nf_conntrack_expect_cachep);
vfree(nf_conntrack_hash);
}
static int hashsize;
-MODULE_PARM(hashsize, "i");
+module_param(hashsize, int, 0400);
int __init nf_conntrack_init(void)
{
@@ -1727,13 +1518,26 @@
}
ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
- sizeof(struct nf_conn),
- NULL, NULL);
+ sizeof(struct nf_conn), NULL);
if (ret < 0) {
printk(KERN_ERR "Unable to create nf_conn slab cache\n");
goto err_free_hash;
}
+ nf_conntrack_expect_cachep = kmem_cache_create("nf_conntrack_expect",
+ sizeof(struct nf_conntrack_expect),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!nf_conntrack_expect_cachep) {
+ printk(KERN_ERR "Unable to create nf_expect slab cache\n");
+ goto err_free_conntrack_slab;
+ }
+
+ /* Don't NEED lock here, but good form anyway. */
+ WRITE_LOCK(&nf_conntrack_lock);
+ for (i = 0; i < PF_MAX; i++)
+ nf_ct_l3protos[i] = &nf_conntrack_generic_l3proto;
+ WRITE_UNLOCK(&nf_conntrack_lock);
+
for (i = 0; i < nf_conntrack_htable_size; i++)
INIT_LIST_HEAD(&nf_conntrack_hash[i]);
@@ -1745,14 +1549,11 @@
atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
/* - and look it like as a confirmed connection */
set_bit(NF_S_CONFIRMED_BIT, &nf_conntrack_untracked.status);
- /* - and prepare the ctinfo field for REJECT & NAT. */
- nf_conntrack_untracked.infos[NF_CT_NEW].master =
- nf_conntrack_untracked.infos[NF_CT_RELATED].master =
- nf_conntrack_untracked.infos[NF_CT_RELATED + NF_CT_IS_REPLY].master =
- &nf_conntrack_untracked.ct_general;
return ret;
+err_free_conntrack_slab:
+ nf_conntrack_unregister_cache(NF_CT_F_BASIC);
err_free_hash:
vfree(nf_conntrack_hash);
err_unreg_sockopt:
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_ftp.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_ftp.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_ftp.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -17,13 +17,13 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/ctype.h>
#include <net/checksum.h>
#include <net/tcp.h>
-#include <linux/kernel.h>
#include <linux/netfilter/nf_conntrack.h>
#include <linux/netfilter_ipv4/lockhelp.h>
@@ -37,18 +37,16 @@
/* This is slow, but it's simple. --RR */
static char ftp_buffer[65536];
-DECLARE_LOCK(nf_ftp_lock);
+static DECLARE_LOCK(nf_ftp_lock);
struct module *nf_conntrack_ftp = 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
+module_param_array(ports, int, &ports_c, 0400);
static int loose;
-MODULE_PARM(loose, "i");
+module_param(loose, int, 0600);
#if 0
#define DEBUGP printk
@@ -247,16 +245,16 @@
u_int16_t tmp_port = 0;
int i;
- for(i = start; i < dlen; i++) {
+ for (i = start; i < dlen; i++) {
/* Finished? */
- if(data[i] == delim){
+ if (data[i] == delim) {
if (tmp_port == 0)
break;
*port = htons(tmp_port);
DEBUGP("get_port: return %d\n", tmp_port);
return i + 1;
}
- else if(data[i] >= '0' && data[i] <= '9')
+ else if (data[i] >= '0' && data[i] <= '9')
tmp_port = tmp_port*10 + data[i] - '0';
else { /* Some other crap */
DEBUGP("get_port: invalid char.\n");
@@ -266,7 +264,7 @@
return 0;
}
-/* Returns 0, or length of numbers: |1|3ffe::1|6275| or |2|132.235.1.2|6275| */
+/* Returns 0, or length of numbers: |1|132.235.1.2|6275| or |2|3ffe::1|6275| */
static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
char term)
{
@@ -393,7 +391,8 @@
enum nf_conntrack_info ctinfo)
{
unsigned int dataoff, datalen;
- struct tcphdr tcph;
+ struct tcphdr _tcph, *th;
+ char *fb_ptr;
u_int32_t old_seq_aft_nl;
int old_seq_aft_nl_set, ret;
int dir = NFCTINFO2DIR(ctinfo);
@@ -414,10 +413,11 @@
return NF_ACCEPT;
}
- if (skb_copy_bits(skb, protoff, &tcph, sizeof(tcph)) != 0)
+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+ if (th == NULL)
return NF_ACCEPT;
- dataoff = protoff + tcph.doff * 4;
+ dataoff = protoff + th->doff * 4;
/* No data? */
if (dataoff >= skb->len) {
DEBUGP("ftp: dataoff(%u) >= skblen(%u)\n", dataoff, skb->len);
@@ -426,26 +426,27 @@
datalen = skb->len - dataoff;
LOCK_BH(&nf_ftp_lock);
- skb_copy_bits(skb, dataoff, ftp_buffer, datalen);
+ fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
+ BUG_ON(fb_ptr == NULL);
old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
DEBUGP("conntrack_ftp: datalen %u\n", datalen);
- if (ftp_buffer[datalen - 1] == '\n') {
+ if (fb_ptr[datalen - 1] == '\n') {
DEBUGP("conntrack_ftp: datalen %u ends in \\n\n", datalen);
if (!old_seq_aft_nl_set
- || after(ntohl(tcph.seq) + datalen, old_seq_aft_nl)) {
+ || after(ntohl(th->seq) + datalen, old_seq_aft_nl)) {
DEBUGP("conntrack_ftp: updating nl to %u\n",
- ntohl(tcph.seq) + datalen);
+ ntohl(th->seq) + datalen);
ct_ftp_info->seq_aft_nl[dir] =
- ntohl(tcph.seq) + datalen;
+ ntohl(th->seq) + datalen;
ct_ftp_info->seq_aft_nl_set[dir] = 1;
}
}
if(!old_seq_aft_nl_set ||
- (ntohl(tcph.seq) != old_seq_aft_nl)) {
+ (ntohl(th->seq) != old_seq_aft_nl)) {
DEBUGP("nf_conntrack_ftp_help: wrong seq pos %s(%u)\n",
old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
ret = NF_ACCEPT;
@@ -461,7 +462,7 @@
for (i = 0; i < ARRAY_SIZE(search); i++) {
if (search[i].dir != dir) continue;
- found = find_pattern(ftp_buffer, datalen,
+ found = find_pattern(fb_ptr, datalen,
search[i].pattern,
search[i].plen,
search[i].skip,
@@ -474,12 +475,12 @@
if (found == -1) {
/* We don't usually drop packets. After all, this is
connection tracking, not packet filtering.
- However, it is neccessary for accurate tracking in
+ However, it is necessary for accurate tracking in
this case. */
if (net_ratelimit())
printk("conntrack_ftp: partial %s %u+%u\n",
search[i].pattern,
- ntohl(tcph.seq), datalen);
+ ntohl(th->seq), datalen);
ret = NF_DROP;
goto out;
} else if (found == 0) { /* No match */
@@ -488,8 +489,8 @@
}
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
- (int)matchlen, ftp_buffer + matchoff,
- matchlen, ntohl(tcph.seq) + matchoff);
+ (int)matchlen, fb_ptr + matchoff,
+ matchlen, ntohl(th->seq) + matchoff);
exp = nf_conntrack_expect_alloc();
if (exp == NULL) {
@@ -503,7 +504,7 @@
if ((cmd.l3num == ct->tuplehash[dir].tuple.src.l3num) &&
(!memcmp(&cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all,
sizeof(cmd.u3.all)))) {
- exp->seq = ntohl(tcph.seq) + matchoff;
+ exp->seq = ntohl(th->seq) + matchoff;
exp_ftp_info->len = matchlen;
exp_ftp_info->ftptype = search[i].ftptype;
exp_ftp_info->port = ntohs(cmd.u.tcp.port);
@@ -565,66 +566,79 @@
return ret;
}
-static struct nf_conntrack_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][10];
+static struct nf_conntrack_helper ftp[MAX_PORTS][2];
+static char ftp_names[MAX_PORTS][2][10];
-/* Not __exit: called from init() */
-static void fini(void)
+static void __exit fini(void)
{
- int i;
+ int i, j;
for (i = 0; i < ports_c; i++) {
- DEBUGP("nf_ct_ftp: unregistering helper for port %d\n",
- ports[i]);
- nf_conntrack_helper_unregister(&ftp[i]);
+ for (j = 0; j < 2; j++) {
+ DEBUGP("nf_ct_ftp: unregistering helper for pf: %d "
+ "port: %d\n",
+ ftp[i][j].tuple.src.l3num, ports[i]);
+ nf_conntrack_helper_unregister(&ftp[i][j]);
+ }
}
}
static int __init init(void)
{
- int i, ret;
+ int i, j = -1, ret = 0;
char *tmpname;
- if (ports[0] == 0)
- ports[0] = FTP_PORT;
+ if (ports_c == 0)
+ ports[ports_c++] = FTP_PORT;
/* FIXME should be configurable whether IPv4 and IPv6 FTP connections
are tracked or not - YK */
- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+ for (i = 0; i < ports_c; i++) {
memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper));
- ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
- ftp[i].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i].mask.src.u.tcp.port = 0xFFFF;
- ftp[i].mask.dst.protonum = 0xFFFF;
- ftp[i].max_expected = 1;
- ftp[i].timeout = 0;
- ftp[i].flags = NF_CT_HELPER_F_REUSE_EXPECT;
- ftp[i].me = nf_conntrack_ftp;
- ftp[i].help = help;
- tmpname = &ftp_names[i][0];
- if (ports[i] == FTP_PORT)
- sprintf(tmpname, "ftp");
- else
- sprintf(tmpname, "ftp-%d", ports[i]);
- ftp[i].name = tmpname;
+ ftp[i][0].tuple.src.l3num = PF_INET;
+ ftp[i][1].tuple.src.l3num = PF_INET6;
+ for (j = 0; j < 2; j++) {
+ ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
+ ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
+ ftp[i][j].mask.src.u.tcp.port = 0xFFFF;
+ ftp[i][j].mask.dst.protonum = 0xFFFF;
+ ftp[i][j].max_expected = 1;
+ ftp[i][j].timeout = 0;
+ ftp[i][j].flags = NF_CT_HELPER_F_REUSE_EXPECT;
+ ftp[i][j].me = nf_conntrack_ftp;
+ ftp[i][j].help = help;
+ tmpname = &ftp_names[i][j][0];
+ if (ports[i] == FTP_PORT)
+ sprintf(tmpname, "ftp");
+ else
+ sprintf(tmpname, "ftp-%d", ports[i]);
+ ftp[i][j].name = tmpname;
- DEBUGP("nf_ct_ftp: registering helper for port %d\n",
- ports[i]);
- ret = nf_conntrack_helper_register(&ftp[i]);
+ DEBUGP("nf_ct_ftp: registering helper for pf: %d "
+ "port: %d\n",
+ ftp[i][j].tuple.src.l3num, ports[i]);
+ ret = nf_conntrack_helper_register(&ftp[i][j]);
+ if (ret) {
+ printk("nf_ct_ftp: failed to register helper "
+ " for pf: %d port: %d\n",
+ ftp[i][j].tuple.src.l3num, ports[i]);
+ goto done;
+ }
+ }
+ }
- if (ret) {
- fini();
- return ret;
+done:
+ if (i < ports_c) {
+ for (;i >= 0; i--) {
+ for (; j >= 0; j--)
+ nf_conntrack_helper_unregister(&ftp[i][j]);
+ j = 1;
}
-
- ports_c++;
}
- return 0;
+ return ret;
}
-
PROVIDES_CONNTRACK(ftp);
-EXPORT_SYMBOL(nf_ftp_lock);
module_init(init);
module_exit(fini);
Added: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_l3proto_generic.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_l3proto_generic.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_l3proto_generic.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -0,0 +1,96 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam at netfilter.org>
+ * (C) 2003-2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 16 Dec 2003: Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
+ * - enable working with L3 protocol independent connection tracking.
+ *
+ * Derived from net/ipv4/netfilter/ip_conntrack_proto_generic.c
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmp.h>
+#include <linux/sysctl.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_conntrack_protocol.h>
+#include <linux/netfilter/nf_conntrack_l3proto.h>
+#include <linux/netfilter/nf_conntrack_core.h>
+#include <linux/netfilter_ipv4/nf_conntrack_ipv4.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
+static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
+ struct nf_conntrack_tuple *tuple)
+{
+ memset(tuple->src.u3.all, 0, NF_CT_TUPLE_L3SIZE);
+ memset(tuple->dst.u3.all, 0, NF_CT_TUPLE_L3SIZE);
+
+ return 1;
+}
+
+static int generic_invert_tuple(struct nf_conntrack_tuple *tuple,
+ const struct nf_conntrack_tuple *orig)
+{
+ memset(tuple->src.u3.all, 0, NF_CT_TUPLE_L3SIZE);
+ memset(tuple->dst.u3.all, 0, NF_CT_TUPLE_L3SIZE);
+
+ return 1;
+}
+
+static int generic_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
+{
+ return 0;
+}
+
+static int generic_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
+{
+ return 0;
+}
+
+static int
+generic_prepare(struct sk_buff **pskb, unsigned int hooknum,
+ unsigned int *dataoff, u_int8_t *protonum, int *ret)
+{
+ /* Never track !!! */
+ *ret = NF_ACCEPT;
+ return 0;
+}
+
+
+static u_int32_t generic_get_features(const struct nf_conntrack_tuple *tuple)
+
+{
+ return NF_CT_F_BASIC;
+}
+
+struct nf_conntrack_l3proto nf_conntrack_generic_l3proto = {
+ .l3proto = PF_UNSPEC,
+ .name = "unknown",
+ .pkt_to_tuple = generic_pkt_to_tuple,
+ .invert_tuple = generic_invert_tuple,
+ .print_tuple = generic_print_tuple,
+ .print_conntrack = generic_print_conntrack,
+ .prepare = generic_prepare,
+ .get_features = generic_get_features,
+ .me = THIS_MODULE,
+};
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_generic.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_generic.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_generic.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -40,15 +40,15 @@
}
/* Print out the per-protocol part of the tuple. */
-static unsigned int generic_print_tuple(char *buffer,
- const struct nf_conntrack_tuple *tuple)
+static int generic_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
return 0;
}
/* Print out the private part of the conntrack. */
-static unsigned int generic_print_conntrack(char *buffer,
- const struct nf_conn *state)
+static int generic_print_conntrack(struct seq_file *s,
+ const struct nf_conn *state)
{
return 0;
}
@@ -57,10 +57,11 @@
static int packet(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff,
- enum nf_conntrack_info conntrackinfo,
+ enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum)
{
- nf_ct_refresh(conntrack, nf_ct_generic_timeout);
+ nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout);
return NF_ACCEPT;
}
@@ -71,7 +72,15 @@
return 1;
}
-struct nf_conntrack_protocol nf_conntrack_generic_protocol
-= { { NULL, NULL }, PF_UNSPEC, 0, "unknown",
- generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
- generic_print_conntrack, packet, new, NULL, NULL, NULL };
+struct nf_conntrack_protocol nf_conntrack_generic_protocol =
+{
+ .l3proto = PF_UNSPEC,
+ .proto = 0,
+ .name = "unknown",
+ .pkt_to_tuple = generic_pkt_to_tuple,
+ .invert_tuple = generic_invert_tuple,
+ .print_tuple = generic_print_tuple,
+ .print_conntrack = generic_print_conntrack,
+ .packet = packet,
+ .new = new,
+};
Added: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_sctp.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_sctp.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_sctp.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -0,0 +1,675 @@
+/*
+ * 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.
+ *
+ * Derived from net/ipv4/ip_conntrack_sctp.c
+ */
+
+/*
+ * Added support for proc manipulation of timeouts.
+ */
+
+#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/seq_file.h>
+
+#include <linux/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_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 nf_ct_sctp_timeout_closed = 10 SECS;
+unsigned long nf_ct_sctp_timeout_cookie_wait = 3 SECS;
+unsigned long nf_ct_sctp_timeout_cookie_echoed = 3 SECS;
+unsigned long nf_ct_sctp_timeout_established = 5 DAYS;
+unsigned long nf_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000;
+unsigned long nf_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;
+unsigned long nf_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;
+
+static unsigned long * sctp_timeouts[]
+= { NULL, /* SCTP_CONNTRACK_NONE */
+ &nf_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */
+ &nf_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */
+ &nf_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */
+ &nf_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */
+ &nf_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */
+ &nf_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */
+ &nf_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 nf_conntrack_tuple *tuple)
+{
+ sctp_sctphdr_t _hdr, *hp;
+
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ /* Actually only need first 8 bytes. */
+ hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+ if (hp == NULL)
+ return 0;
+
+ tuple->src.u.sctp.port = hp->source;
+ tuple->dst.u.sctp.port = hp->dest;
+ return 1;
+}
+
+static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple,
+ const struct nf_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 int sctp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
+{
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ return seq_printf(s, "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 int sctp_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
+{
+ enum sctp_conntrack state;
+
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ READ_LOCK(&sctp_lock);
+ state = conntrack->proto.sctp.state;
+ READ_UNLOCK(&sctp_lock);
+
+ return seq_printf(s, "%s ", sctp_conntrack_names[state]);
+}
+
+#define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \
+for (offset = dataoff + sizeof(sctp_sctphdr_t), count = 0; \
+ offset < skb->len && \
+ (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \
+ offset += (htons(sch->length) + 3) & ~3, count++)
+
+/* Some validity checks to make sure the chunks are fine */
+static int do_basic_checks(struct nf_conn *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ char *map)
+{
+ u_int32_t offset, count;
+ sctp_chunkhdr_t _sch, *sch;
+ int flag;
+
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ flag = 0;
+
+ for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, 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 nf_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 nf_conn *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ enum sctp_conntrack newconntrack, oldsctpstate;
+ sctp_sctphdr_t _sctph, *sh;
+ sctp_chunkhdr_t _sch, *sch;
+ u_int32_t offset, count;
+ char map[256 / sizeof (char)] = {0};
+
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
+ if (sh == NULL)
+ return -1;
+
+ if (do_basic_checks(conntrack, skb, dataoff, 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)
+ && (sh->vtag != conntrack->proto.sctp.vtag[NFCTINFO2DIR(ctinfo)])) {
+ DEBUGP("Verification tag check failed\n");
+ return -1;
+ }
+
+ oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
+ for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, 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 (sh->vtag != 0) {
+ WRITE_UNLOCK(&sctp_lock);
+ return -1;
+ }
+ } else if (sch->type == SCTP_CID_ABORT) {
+ /* Sec 8.5.1 (B) */
+ if (!(sh->vtag == conntrack->proto.sctp.vtag[NFCTINFO2DIR(ctinfo)])
+ && !(sh->vtag == conntrack->proto.sctp.vtag
+ [1 - NFCTINFO2DIR(ctinfo)])) {
+ WRITE_UNLOCK(&sctp_lock);
+ return -1;
+ }
+ } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
+ /* Sec 8.5.1 (C) */
+ if (!(sh->vtag == conntrack->proto.sctp.vtag[NFCTINFO2DIR(ctinfo)])
+ && !(sh->vtag == conntrack->proto.sctp.vtag
+ [1 - NFCTINFO2DIR(ctinfo)]
+ && (sch->flags & 1))) {
+ WRITE_UNLOCK(&sctp_lock);
+ return -1;
+ }
+ } else if (sch->type == SCTP_CID_COOKIE_ECHO) {
+ /* Sec 8.5.1 (D) */
+ if (!(sh->vtag == conntrack->proto.sctp.vtag[NFCTINFO2DIR(ctinfo)])) {
+ WRITE_UNLOCK(&sctp_lock);
+ return -1;
+ }
+ }
+
+ oldsctpstate = conntrack->proto.sctp.state;
+ newconntrack = new_state(NFCTINFO2DIR(ctinfo), oldsctpstate, sch->type);
+
+ /* Invalid */
+ if (newconntrack == SCTP_CONNTRACK_MAX) {
+ DEBUGP("nf_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
+ NFCTINFO2DIR(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, *ih;
+
+ ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+ sizeof(_inithdr), &_inithdr);
+ if (ih == NULL) {
+ WRITE_UNLOCK(&sctp_lock);
+ return -1;
+ }
+ DEBUGP("Setting vtag %x for dir %d\n",
+ ih->init_tag, NFCTINFO2DIR(ctinfo));
+ conntrack->proto.sctp.vtag[NF_CT_DIR_ORIGINAL] = ih->init_tag;
+ }
+
+ conntrack->proto.sctp.state = newconntrack;
+ WRITE_UNLOCK(&sctp_lock);
+ }
+
+ nf_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]);
+
+ if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
+ && NFCTINFO2DIR(ctinfo) == NF_CT_DIR_REPLY
+ && newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
+ DEBUGP("Setting assured bit\n");
+ set_bit(NF_S_ASSURED_BIT, &conntrack->status);
+ }
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ enum sctp_conntrack newconntrack;
+ sctp_sctphdr_t _sctph, *sh;
+ sctp_chunkhdr_t _sch, *sch;
+ u_int32_t offset, count;
+ char map[256 / sizeof (char)] = {0};
+
+ DEBUGP(__FUNCTION__);
+ DEBUGP("\n");
+
+ sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
+ if (sh == NULL)
+ return 0;
+
+ if (do_basic_checks(conntrack, skb, dataoff, map) != 0)
+ return 0;
+
+ /* 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 0;
+ }
+
+ newconntrack = SCTP_CONNTRACK_MAX;
+ for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
+ /* Don't need lock here: this conntrack not in circulation yet */
+ newconntrack = new_state(NF_CT_DIR_ORIGINAL,
+ SCTP_CONNTRACK_NONE, sch->type);
+
+ /* Invalid: delete conntrack */
+ if (newconntrack == SCTP_CONNTRACK_MAX) {
+ DEBUGP("nf_conntrack_sctp: invalid new deleting.\n");
+ return 0;
+ }
+
+ /* Copy the vtag into the state info */
+ if (sch->type == SCTP_CID_INIT) {
+ if (sh->vtag == 0) {
+ sctp_inithdr_t _inithdr, *ih;
+
+ ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
+ sizeof(_inithdr), &_inithdr);
+ if (ih == NULL)
+ return 0;
+
+ DEBUGP("Setting vtag %x for new conn\n",
+ ih->init_tag);
+
+ conntrack->proto.sctp.vtag[NF_CT_DIR_REPLY] =
+ ih->init_tag;
+ } else {
+ /* Sec 8.5.1 (A) */
+ return 0;
+ }
+ }
+ /* 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",
+ sh->vtag);
+ conntrack->proto.sctp.vtag[NF_CT_DIR_REPLY] = sh->vtag;
+ }
+
+ conntrack->proto.sctp.state = newconntrack;
+ }
+
+ return 1;
+}
+
+static int sctp_exp_matches_pkt(struct nf_conntrack_expect *exp,
+ const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ /* To be implemented */
+ return 0;
+}
+
+struct nf_conntrack_protocol nf_conntrack_protocol_sctp4 = {
+ .l3proto = PF_INET,
+ .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
+};
+
+struct nf_conntrack_protocol nf_conntrack_protocol_sctp6 = {
+ .l3proto = PF_INET6,
+ .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
+};
+
+#ifdef CONFIG_SYSCTL
+static ctl_table nf_ct_sysctl_table[] = {
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,
+ .procname = "nf_conntrack_sctp_timeout_closed",
+ .data = &nf_ct_sctp_timeout_closed,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,
+ .procname = "nf_conntrack_sctp_timeout_cookie_wait",
+ .data = &nf_ct_sctp_timeout_cookie_wait,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,
+ .procname = "nf_conntrack_sctp_timeout_cookie_echoed",
+ .data = &nf_ct_sctp_timeout_cookie_echoed,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,
+ .procname = "nf_conntrack_sctp_timeout_established",
+ .data = &nf_ct_sctp_timeout_established,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,
+ .procname = "nf_conntrack_sctp_timeout_shutdown_sent",
+ .data = &nf_ct_sctp_timeout_shutdown_sent,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,
+ .procname = "nf_conntrack_sctp_timeout_shutdown_recd",
+ .data = &nf_ct_sctp_timeout_shutdown_recd,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,
+ .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent",
+ .data = &nf_ct_sctp_timeout_shutdown_ack_sent,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_netfilter_table[] = {
+ {
+ .ctl_name = NET_NETFILTER,
+ .procname = "netfilter",
+ .mode = 0555,
+ .child = nf_ct_sysctl_table,
+ },
+ { .ctl_name = 0 }
+};
+
+static ctl_table nf_ct_net_table[] = {
+ {
+ .ctl_name = CTL_NET,
+ .procname = "net",
+ .mode = 0555,
+ .child = nf_ct_netfilter_table,
+ },
+ { .ctl_name = 0 }
+};
+
+static struct ctl_table_header *nf_ct_sysctl_header;
+#endif
+
+int __init init(void)
+{
+ int ret;
+
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp4);
+ if (ret) {
+ printk("nf_conntrack_proto_sctp4: protocol register failed\n");
+ goto out;
+ }
+ ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_sctp6);
+ if (ret) {
+ printk("nf_conntrack_proto_sctp6: protocol register failed\n");
+ goto cleanup_sctp4;
+ }
+
+#ifdef CONFIG_SYSCTL
+ nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+ if (nf_ct_sysctl_header == NULL) {
+ printk("nf_conntrack_proto_sctp: can't register to sysctl.\n");
+ goto cleanup;
+ }
+#endif
+
+ return ret;
+
+#ifdef CONFIG_SYSCTL
+ cleanup:
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6);
+#endif
+ cleanup_sctp4:
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4);
+ out:
+ DEBUGP("SCTP conntrack module loading %s\n",
+ ret ? "failed": "succeeded");
+ return ret;
+}
+
+void __exit fini(void)
+{
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp6);
+ nf_conntrack_protocol_unregister(&nf_conntrack_protocol_sctp4);
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(nf_ct_sysctl_header);
+#endif
+ 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");
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_tcp.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_tcp.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_tcp.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,33 +1,51 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam at netfilter.org>
- * (C) 2003-2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * 16 Dec 2003: Yasuyuki Kozakai <yasuyuki.kozakai at toshiba.co.jp>
- * - generalize L3 protocol dependent part.
+ * Jozsef Kadlecsik <kadlec at blackhole.kfki.hu>:
+ * - Real stateful connection tracking
+ * - Modified state transitions table
+ * - Window scaling support added
+ * - SACK support added
*
- * Derived from net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+ * Willy Tarreau:
+ * - State table bugfixes
+ * - More robust state changes
+ * - Tuning timer parameters
+ *
+ * Yasuyuki KOZAKAI:
+ * - genelized Layer 3 protocol part.
+ *
+ * version 2.2
*/
+#include <linux/config.h>
#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/tcp.h>
-#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <net/ip6_checksum.h>
#include <net/tcp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/nf_conntrack.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
#include <linux/netfilter_ipv4/lockhelp.h>
#if 0
#define DEBUGP printk
+#define DEBUGP_VARS
#else
#define DEBUGP(format, args...)
#endif
@@ -35,28 +53,40 @@
/* Protects conntrack->proto.tcp */
static DECLARE_RWLOCK(tcp_lock);
-/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
- closely. They're more complex. --RR */
+/* "Be conservative in what you do,
+ be liberal in what you accept from others."
+ If it's non-zero, we mark only out of window RST segments as INVALID. */
+int nf_ct_tcp_be_liberal = 0;
-/* Actually, I believe that neither ipmasq (where this code is stolen
- from) nor ipfilter do it exactly right. A new conntrack machine taking
- into account packet loss (which creates uncertainty as to exactly
- the conntrack of the connection) is required. RSN. --RR */
+/* When connection is picked up from the middle, how many packets are required
+ to pass in each direction when we assume we are in sync - if any side uses
+ window scaling, we lost the game.
+ If it is set to zero, we disable picking up already established
+ connections. */
+int nf_ct_tcp_loose = 3;
+/* Max number of the retransmitted packets without receiving an (acceptable)
+ ACK from the destination. If this number is reached, a shorter timer
+ will be started. */
+int nf_ct_tcp_max_retrans = 3;
+
+ /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
+ closely. They're more complex. --RR */
+
static const char *tcp_conntrack_names[] = {
"NONE",
- "ESTABLISHED",
"SYN_SENT",
"SYN_RECV",
+ "ESTABLISHED",
"FIN_WAIT",
+ "CLOSE_WAIT",
+ "LAST_ACK",
"TIME_WAIT",
"CLOSE",
- "CLOSE_WAIT",
- "LAST_ACK",
"LISTEN"
};
-
-#define SECS *HZ
+
+#define SECS * HZ
#define MINS * 60 SECS
#define HOURS * 60 MINS
#define DAYS * 24 HOURS
@@ -70,64 +100,214 @@
unsigned long nf_ct_tcp_timeout_time_wait = 2 MINS;
unsigned long nf_ct_tcp_timeout_close = 10 SECS;
+/* RFC1122 says the R2 limit should be at least 100 seconds.
+ Linux uses 15 packets as limit, which corresponds
+ to ~13-30min depending on RTO. */
+unsigned long nf_ct_tcp_timeout_max_retrans = 5 MINS;
+
static unsigned long * tcp_timeouts[]
-= { 0, /* TCP_CONNTRACK_NONE */
- &nf_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */
- &nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */
- &nf_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */
- &nf_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */
- &nf_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */
- &nf_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */
- &nf_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */
- &nf_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */
- 0, /* TCP_CONNTRACK_LISTEN */
+= { NULL, /* TCP_CONNTRACK_NONE */
+ &nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */
+ &nf_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */
+ &nf_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */
+ &nf_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */
+ &nf_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */
+ &nf_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */
+ &nf_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */
+ &nf_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */
+ NULL, /* TCP_CONNTRACK_LISTEN */
};
#define sNO TCP_CONNTRACK_NONE
-#define sES TCP_CONNTRACK_ESTABLISHED
#define sSS TCP_CONNTRACK_SYN_SENT
#define sSR TCP_CONNTRACK_SYN_RECV
+#define sES TCP_CONNTRACK_ESTABLISHED
#define sFW TCP_CONNTRACK_FIN_WAIT
+#define sCW TCP_CONNTRACK_CLOSE_WAIT
+#define sLA TCP_CONNTRACK_LAST_ACK
#define sTW TCP_CONNTRACK_TIME_WAIT
#define sCL TCP_CONNTRACK_CLOSE
-#define sCW TCP_CONNTRACK_CLOSE_WAIT
-#define sLA TCP_CONNTRACK_LAST_ACK
#define sLI TCP_CONNTRACK_LISTEN
#define sIV TCP_CONNTRACK_MAX
+#define sIG TCP_CONNTRACK_IGNORE
-static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] = {
+/* What TCP flags are set from RST/SYN/FIN/ACK. */
+enum tcp_bit_set {
+ TCP_SYN_SET,
+ TCP_SYNACK_SET,
+ TCP_FIN_SET,
+ TCP_ACK_SET,
+ TCP_RST_SET,
+ TCP_NONE_SET,
+};
+
+/*
+ * The TCP state transition table needs a few words...
+ *
+ * We are the man in the middle. All the packets go through us
+ * but might get lost in transit to the destination.
+ * It is assumed that the destinations can't receive segments
+ * we haven't seen.
+ *
+ * The checked segment is in window, but our windows are *not*
+ * equivalent with the ones of the sender/receiver. We always
+ * try to guess the state of the current sender.
+ *
+ * The meaning of the states are:
+ *
+ * NONE: initial state
+ * SYN_SENT: SYN-only packet seen
+ * SYN_RECV: SYN-ACK packet seen
+ * ESTABLISHED: ACK packet seen
+ * FIN_WAIT: FIN packet seen
+ * CLOSE_WAIT: ACK seen (after FIN)
+ * LAST_ACK: FIN seen (after FIN)
+ * TIME_WAIT: last ACK seen
+ * CLOSE: closed connection
+ *
+ * LISTEN state is not used.
+ *
+ * Packets marked as IGNORED (sIG):
+ * if they may be either invalid or valid
+ * and the receiver may send back a connection
+ * closing RST or a SYN/ACK.
+ *
+ * Packets marked as INVALID (sIV):
+ * if they are invalid
+ * or we do not support the request (simultaneous open)
+ */
+static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
{
-/* ORIGINAL */
-/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
-/*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI },
-/*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI },
-/*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES },
-/*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
-/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+/* ORIGINAL */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV },
+/*
+ * sNO -> sSS Initialize a new connection
+ * sSS -> sSS Retransmitted SYN
+ * sSR -> sIG Late retransmitted SYN?
+ * sES -> sIG Error: SYNs in window outside the SYN_SENT state
+ * are errors. Receiver will reply with RST
+ * and close the connection.
+ * Or we are not in sync and hold a dead connection.
+ * sFW -> sIG
+ * sCW -> sIG
+ * sLA -> sIG
+ * sTW -> sSS Reopened connection (RFC 1122).
+ * sCL -> sSS
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
+/*
+ * A SYN/ACK from the client is always invalid:
+ * - either it tries to set up a simultaneous open, which is
+ * not supported;
+ * - or the firewall has just been inserted between the two hosts
+ * during the session set-up. The SYN will be retransmitted
+ * by the true client (or it'll time out).
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
+/*
+ * sNO -> sIV Too late and no reason to do anything...
+ * sSS -> sIV Client migth not send FIN in this state:
+ * we enforce waiting for a SYN/ACK reply first.
+ * sSR -> sFW Close started.
+ * sES -> sFW
+ * sFW -> sLA FIN seen in both directions, waiting for
+ * the last ACK.
+ * Migth be a retransmitted FIN as well...
+ * sCW -> sLA
+ * sLA -> sLA Retransmitted FIN. Remain in the same state.
+ * sTW -> sTW
+ * sCL -> sCL
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV },
+/*
+ * sNO -> sES Assumed.
+ * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet.
+ * sSR -> sES Established state is reached.
+ * sES -> sES :-)
+ * sFW -> sCW Normal close request answered by ACK.
+ * sCW -> sCW
+ * sLA -> sTW Last ACK detected.
+ * sTW -> sTW Retransmitted last ACK. Remain in the same state.
+ * sCL -> sCL
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
+/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
},
{
-/* REPLY */
-/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
-/*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR },
-/*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI },
-/*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI },
-/*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
-/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
- }
+/* REPLY */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
+/*
+ * sNO -> sIV Never reached.
+ * sSS -> sIV Simultaneous open, not supported
+ * sSR -> sIV Simultaneous open, not supported.
+ * sES -> sIV Server may not initiate a connection.
+ * sFW -> sIV
+ * sCW -> sIV
+ * sLA -> sIV
+ * sTW -> sIV Reopened connection, but server may not do it.
+ * sCL -> sIV
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV },
+/*
+ * sSS -> sSR Standard open.
+ * sSR -> sSR Retransmitted SYN/ACK.
+ * sES -> sIG Late retransmitted SYN/ACK?
+ * sFW -> sIG
+ * sCW -> sIG
+ * sLA -> sIG
+ * sTW -> sIG
+ * sCL -> sIG
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
+/*
+ * sSS -> sIV Server might not send FIN in this state.
+ * sSR -> sFW Close started.
+ * sES -> sFW
+ * sFW -> sLA FIN seen in both directions.
+ * sCW -> sLA
+ * sLA -> sLA Retransmitted FIN.
+ * sTW -> sTW
+ * sCL -> sCL
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*ack*/ { sIV, sIV, sIV, sES, sCW, sCW, sTW, sTW, sCL, sIV },
+/*
+ * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet.
+ * sSR -> sIV Simultaneous open.
+ * sES -> sES :-)
+ * sFW -> sCW Normal close request answered by ACK.
+ * sCW -> sCW
+ * sLA -> sTW Last ACK detected.
+ * sTW -> sTW Retransmitted last ACK.
+ * sCL -> sCL
+ */
+/* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */
+/*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
+/*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
+ }
};
static int tcp_pkt_to_tuple(const struct sk_buff *skb,
- unsigned int dataoff,
- struct nf_conntrack_tuple *tuple)
+ unsigned int dataoff,
+ struct nf_conntrack_tuple *tuple)
{
- struct tcphdr hdr;
+ struct tcphdr _hdr, *hp;
/* Actually only need first 8 bytes. */
- if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+ hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
+ if (hp == NULL)
return 0;
- tuple->src.u.tcp.port = hdr.source;
- tuple->dst.u.tcp.port = hdr.dest;
+ tuple->src.u.tcp.port = hp->source;
+ tuple->dst.u.tcp.port = hp->dest;
return 1;
}
@@ -141,17 +321,17 @@
}
/* Print out the per-protocol part of the tuple. */
-static unsigned int tcp_print_tuple(char *buffer,
- const struct nf_conntrack_tuple *tuple)
+static int tcp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return sprintf(buffer, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.tcp.port),
- ntohs(tuple->dst.u.tcp.port));
+ return seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.tcp.port),
+ ntohs(tuple->dst.u.tcp.port));
}
/* Print out the private part of the conntrack. */
-static unsigned int tcp_print_conntrack(char *buffer,
- const struct nf_conn *conntrack)
+static int tcp_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
enum tcp_conntrack state;
@@ -159,124 +339,815 @@
state = conntrack->proto.tcp.state;
READ_UNLOCK(&tcp_lock);
- return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
+ return seq_printf(s, "%s ", tcp_conntrack_names[state]);
}
static unsigned int get_conntrack_index(const struct tcphdr *tcph)
{
- if (tcph->rst) return 3;
- else if (tcph->syn) return 0;
- else if (tcph->fin) return 1;
- else if (tcph->ack) return 2;
- else return 4;
+ if (tcph->rst) return TCP_RST_SET;
+ else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET);
+ else if (tcph->fin) return TCP_FIN_SET;
+ else if (tcph->ack) return TCP_ACK_SET;
+ else return TCP_NONE_SET;
}
+/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
+ in IP Filter' by Guido van Rooij.
+
+ http://www.nluug.nl/events/sane2000/papers.html
+ http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
+
+ The boundaries and the conditions are slightly changed:
+
+ td_maxend = max(sack + max(win,1)) seen in reply packets
+ td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
+ td_end = max(seq + len) seen in sent packets
+
+ I. Upper bound for valid data: seq + len <= sender.td_maxend
+ II. Lower bound for valid data: seq >= sender.td_end - receiver.td_maxwin
+ III. Upper bound for valid ack: sack <= receiver.td_end
+ IV. Lower bound for valid ack: ack >= receiver.td_end - MAXACKWINDOW
+
+ where sack is the highest right edge of sack block found in the packet.
+
+ The upper bound limit for a valid ack is not ignored -
+ we doesn't have to deal with fragments.
+*/
+
+static inline __u32 segment_seq_plus_len(__u32 seq,
+ size_t len,
+ unsigned int dataoff,
+ struct tcphdr *tcph)
+{
+ /* XXX Should I use payload length field in IP/IPv6 header ?
+ * - kozakai */
+ return (seq + len - dataoff - tcph->doff*4
+ + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
+}
+
+/* Fixme: what about big packets? */
+#define MAXACKWINCONST 66000
+#define MAXACKWINDOW(sender) \
+ ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \
+ : MAXACKWINCONST)
+
+/*
+ * Simplified tcp_parse_options routine from tcp_input.c
+ */
+static void tcp_options(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct tcphdr *tcph,
+ struct nf_ct_tcp_state *state)
+{
+ unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
+ unsigned char *ptr;
+ int length = (tcph->doff*4) - sizeof(struct tcphdr);
+
+ if (!length)
+ return;
+
+ ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
+ length, buff);
+ BUG_ON(ptr == NULL);
+
+ state->td_scale =
+ state->flags = 0;
+
+ while (length > 0) {
+ int opcode=*ptr++;
+ int opsize;
+
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+ length--;
+ continue;
+ default:
+ opsize=*ptr++;
+ if (opsize < 2) /* "silly options" */
+ return;
+ if (opsize > length)
+ break; /* don't parse partial options */
+
+ if (opcode == TCPOPT_SACK_PERM
+ && opsize == TCPOLEN_SACK_PERM)
+ state->flags |= NF_CT_TCP_FLAG_SACK_PERM;
+ else if (opcode == TCPOPT_WINDOW
+ && opsize == TCPOLEN_WINDOW) {
+ state->td_scale = *(u_int8_t *)ptr;
+
+ if (state->td_scale > 14) {
+ /* See RFC1323 */
+ state->td_scale = 14;
+ }
+ state->flags |=
+ NF_CT_TCP_STATE_FLAG_WINDOW_SCALE;
+ }
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ }
+}
+
+static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
+ struct tcphdr *tcph, __u32 *sack)
+{
+ __u32 tmp;
+ unsigned char *ptr;
+ unsigned char buff[(15 * 4) - sizeof(struct tcphdr)] __attribute__((__aligned__(sizeof(__u32))));
+ int length = (tcph->doff*4) - sizeof(struct tcphdr);
+
+ ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
+ length, buff);
+ BUG_ON(ptr == NULL);
+
+ /* Fast path for timestamp-only option */
+ if (length == TCPOLEN_TSTAMP_ALIGNED*4
+ && *(__u32 *)ptr ==
+ __constant_ntohl((TCPOPT_NOP << 24)
+ | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8)
+ | TCPOLEN_TIMESTAMP))
+ return;
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize, i;
+
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize < 2) /* "silly options" */
+ return;
+ if (opsize > length)
+ break; /* don't parse partial options */
+
+ if (opcode == TCPOPT_SACK
+ && opsize >= (TCPOLEN_SACK_BASE
+ + TCPOLEN_SACK_PERBLOCK)
+ && !((opsize - TCPOLEN_SACK_BASE)
+ % TCPOLEN_SACK_PERBLOCK)) {
+ for (i = 0;
+ i < (opsize - TCPOLEN_SACK_BASE);
+ i += TCPOLEN_SACK_PERBLOCK) {
+ tmp = ntohl(*((u_int32_t *)(ptr+i)+1));
+
+ if (after(tmp, *sack))
+ *sack = tmp;
+ }
+ return;
+ }
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ }
+}
+
+static int tcp_in_window(struct nf_ct_tcp *state,
+ enum nf_conntrack_dir dir,
+ unsigned int *index,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct tcphdr *tcph,
+ int pf)
+{
+ struct nf_ct_tcp_state *sender = &state->seen[dir];
+ struct nf_ct_tcp_state *receiver = &state->seen[!dir];
+ __u32 seq, ack, sack, end, win, swin;
+ int res;
+
+ /*
+ * Get the required data from the packet.
+ */
+ seq = ntohl(tcph->seq);
+ ack = sack = ntohl(tcph->ack_seq);
+ win = ntohs(tcph->window);
+ end = segment_seq_plus_len(seq, skb->len, dataoff, tcph);
+
+ if (receiver->flags & NF_CT_TCP_FLAG_SACK_PERM)
+ tcp_sack(skb, dataoff, tcph, &sack);
+
+ DEBUGP("tcp_in_window: START\n");
+ DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+ "seq=%u ack=%u sack=%u win=%u end=%u\n",
+ NIPQUAD(iph->saddr), ntohs(tcph->source),
+ NIPQUAD(iph->daddr), ntohs(tcph->dest),
+ seq, ack, sack, win, end);
+ DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
+
+ if (sender->td_end == 0) {
+ /*
+ * Initialize sender data.
+ */
+ if (tcph->syn && tcph->ack) {
+ /*
+ * Outgoing SYN-ACK in reply to a SYN.
+ */
+ sender->td_end =
+ sender->td_maxend = end;
+ sender->td_maxwin = (win == 0 ? 1 : win);
+
+ tcp_options(skb, dataoff, tcph, sender);
+ /*
+ * RFC 1323:
+ * Both sides must send the Window Scale option
+ * to enable window scaling in either direction.
+ */
+ if (!(sender->flags & NF_CT_TCP_STATE_FLAG_WINDOW_SCALE
+ && receiver->flags & NF_CT_TCP_STATE_FLAG_WINDOW_SCALE))
+ sender->td_scale =
+ receiver->td_scale = 0;
+ } else {
+ /*
+ * We are in the middle of a connection,
+ * its history is lost for us.
+ * Let's try to use the data from the packet.
+ */
+ sender->td_end = end;
+ sender->td_maxwin = (win == 0 ? 1 : win);
+ sender->td_maxend = end + sender->td_maxwin;
+ }
+ } else if (state->state == TCP_CONNTRACK_SYN_SENT
+ && dir == NF_CT_DIR_ORIGINAL
+ && after(end, sender->td_end)) {
+ /*
+ * RFC 793: "if a TCP is reinitialized ... then it need
+ * not wait at all; it must only be sure to use sequence
+ * numbers larger than those recently used."
+ */
+ sender->td_end =
+ sender->td_maxend = end;
+ sender->td_maxwin = (win == 0 ? 1 : win);
+
+ tcp_options(skb, dataoff, tcph, sender);
+ }
+
+ if (!(tcph->ack)) {
+ /*
+ * If there is no ACK, just pretend it was set and OK.
+ */
+ ack = sack = receiver->td_end;
+ } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
+ (TCP_FLAG_ACK|TCP_FLAG_RST))
+ && (ack == 0)) {
+ /*
+ * Broken TCP stacks, that set ACK in RST packets as well
+ * with zero ack value.
+ */
+ ack = sack = receiver->td_end;
+ }
+
+ if (seq == end)
+ /*
+ * Packets contains no data: we assume it is valid
+ * and check the ack value only.
+ */
+ seq = end = sender->td_end;
+
+ DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+ "seq=%u ack=%u sack =%u win=%u end=%u trim=%u\n",
+ NIPQUAD(iph->saddr), ntohs(tcph->source),
+ NIPQUAD(iph->daddr), ntohs(tcph->dest),
+ seq, ack, sack, win, end,
+ after(end, sender->td_maxend) && before(seq, sender->td_maxend)
+ ? sender->td_maxend : end);
+ DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
+
+ /* Ignore data over the right edge of the receiver's window. */
+ if (after(end, sender->td_maxend) &&
+ before(seq, sender->td_maxend)) {
+ end = sender->td_maxend;
+ if (*index == TCP_FIN_SET)
+ *index = TCP_ACK_SET;
+ }
+ DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
+ before(end, sender->td_maxend + 1)
+ || before(seq, sender->td_maxend + 1),
+ after(seq, sender->td_end - receiver->td_maxwin - 1)
+ || after(end, sender->td_end - receiver->td_maxwin - 1),
+ before(sack, receiver->td_end + 1),
+ after(ack, receiver->td_end - MAXACKWINDOW(sender)));
+
+ if (sender->loose || receiver->loose ||
+ (before(end, sender->td_maxend + 1) &&
+ after(seq, sender->td_end - receiver->td_maxwin - 1) &&
+ before(sack, receiver->td_end + 1) &&
+ after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+ /*
+ * Take into account window scaling (RFC 1323).
+ */
+ if (!tcph->syn)
+ win <<= sender->td_scale;
+
+ /*
+ * Update sender data.
+ */
+ swin = win + (sack - ack);
+ if (sender->td_maxwin < swin)
+ sender->td_maxwin = swin;
+ if (after(end, sender->td_end))
+ sender->td_end = end;
+ if (after(sack + win, receiver->td_maxend - 1)) {
+ receiver->td_maxend = sack + win;
+ if (win == 0)
+ receiver->td_maxend++;
+ }
+
+ /*
+ * Check retransmissions.
+ */
+ if (*index == TCP_ACK_SET) {
+ if (state->last_dir == dir
+ && state->last_seq == seq
+ && state->last_end == end)
+ state->retrans++;
+ else {
+ state->last_dir = dir;
+ state->last_seq = seq;
+ state->last_end = end;
+ state->retrans = 0;
+ }
+ }
+ /*
+ * Close the window of disabled window tracking :-)
+ */
+ if (sender->loose)
+ sender->loose--;
+
+ res = 1;
+ } else {
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: %s ",
+ before(end, sender->td_maxend + 1) ?
+ after(seq, sender->td_end - receiver->td_maxwin - 1) ?
+ before(ack, receiver->td_end + 1) ?
+ after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
+ : "ACK is under the lower bound (possibly overly delayed ACK)"
+ : "ACK is over the upper bound (ACKed data has never seen yet)"
+ : "SEQ is under the lower bound (retransmitted already ACKed data)"
+ : "SEQ is over the upper bound (over the window of the receiver)");
+
+ res = nf_ct_tcp_be_liberal && !tcph->rst;
+ }
+
+ DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
+ "receiver end=%u maxend=%u maxwin=%u\n",
+ res, sender->td_end, sender->td_maxend, sender->td_maxwin,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
+
+ return res;
+}
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+/* Update sender->td_end after NAT successfully mangled the packet */
+/* Caller must linearize skb at tcp header. */
+int nf_conntrack_tcp_update(struct sk_buff *skb,
+ unsigned int dataoff,
+ struct nf_conn *conntrack,
+ int dir)
+{
+ struct tcphdr *tcph = (void *)skb->data + dataoff;
+ __u32 end;
+#ifdef DEBUGP_VARS
+ struct nf_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
+ struct nf_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
+#endif
+
+ end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
+
+ WRITE_LOCK(&tcp_lock);
+ /*
+ * We have to worry for the ack in the reply packet only...
+ */
+ if (after(end, conntrack->proto.tcp.seen[dir].td_end))
+ conntrack->proto.tcp.seen[dir].td_end = end;
+ conntrack->proto.tcp.last_end = end;
+ WRITE_UNLOCK(&tcp_lock);
+ DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
+
+ return 1;
+}
+
+#endif
+
+#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,
+};
+
+/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */
+static int tcp_error(struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum,
+ int(*csum)(const struct sk_buff *,unsigned int))
+{
+ struct tcphdr _tcph, *th;
+ unsigned int tcplen = skb->len - dataoff;
+ u_int8_t tcpflags;
+
+ /* Smaller that minimal TCP header? */
+ th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+ if (th == NULL) {
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ /* Not whole TCP header or malformed packet */
+ if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: truncated/malformed packet ");
+ return -NF_ACCEPT;
+ }
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+ * because the semantic of CHECKSUM_HW is different there
+ * and moreover root might send raw packets.
+ */
+ /* FIXME: Source route IP option packets --RR */
+ if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+ csum(skb, dataoff)) {
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: bad TCP checksum ");
+ return -NF_ACCEPT;
+ }
+
+ /* Check TCP flags. */
+ tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
+ if (!tcp_valid_flags[tcpflags]) {
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: invalid TCP flag combination ");
+ return -NF_ACCEPT;
+ }
+
+ return NF_ACCEPT;
+}
+
+static int csum4(const struct sk_buff *skb, unsigned int dataoff)
+{
+ return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->len - dataoff, IPPROTO_TCP,
+ skb->ip_summed == CHECKSUM_HW ? skb->csum
+ : skb_checksum(skb, dataoff,
+ skb->len - dataoff, 0));
+}
+
+static int csum6(const struct sk_buff *skb, unsigned int dataoff)
+{
+ return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+ skb->len - dataoff, IPPROTO_TCP,
+ skb->ip_summed == CHECKSUM_HW ? skb->csum
+ : skb_checksum(skb, dataoff, skb->len - dataoff,
+ 0));
+}
+
+static int tcp_error4(struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
+}
+
+static int tcp_error6(struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
+}
+
/* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff,
enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum)
{
- enum tcp_conntrack newconntrack, oldtcpstate;
- struct tcphdr tcph;
+ enum tcp_conntrack new_state, old_state;
+ enum nf_conntrack_dir dir;
+ struct tcphdr *th, _tcph;
+ unsigned long timeout;
+ unsigned int index;
- if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
- return -1;
- if (skb->len < dataoff + tcph.doff * 4)
- return -1;
+ th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+ BUG_ON(th == NULL);
- /* If only reply is a RST, we can consider ourselves not to
- have an established connection: this is a fairly common
- problem case, so we can delete the conntrack
- immediately. --RR */
- if (!test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status) && tcph.rst) {
- if (del_timer(&conntrack->timeout))
- conntrack->timeout.function((unsigned long)conntrack);
+ WRITE_LOCK(&tcp_lock);
+ old_state = conntrack->proto.tcp.state;
+ dir = NFCTINFO2DIR(ctinfo);
+ index = get_conntrack_index(th);
+ new_state = tcp_conntracks[dir][index][old_state];
+
+ switch (new_state) {
+ case TCP_CONNTRACK_IGNORE:
+ /* Either SYN in ORIGINAL, or SYN/ACK in REPLY direction. */
+ if (index == TCP_SYNACK_SET
+ && conntrack->proto.tcp.last_index == TCP_SYN_SET
+ && conntrack->proto.tcp.last_dir != dir
+ && after(ntohl(th->ack_seq),
+ conntrack->proto.tcp.last_seq)) {
+ /* This SYN/ACK acknowledges a SYN that we earlier
+ * ignored as invalid. This means that the client and
+ * the server are both in sync, while the firewall is
+ * not. We kill this session and block the SYN/ACK so
+ * that the client cannot but retransmit its SYN and
+ * thus initiate a clean new session.
+ */
+ WRITE_UNLOCK(&tcp_lock);
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: killing out of sync session ");
+ if (del_timer(&conntrack->timeout))
+ conntrack->timeout.function((unsigned long)
+ conntrack);
+ return -NF_DROP;
+ }
+ conntrack->proto.tcp.last_index = index;
+ conntrack->proto.tcp.last_dir = dir;
+ conntrack->proto.tcp.last_seq = ntohl(th->seq);
+
+ WRITE_UNLOCK(&tcp_lock);
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: invalid SYN (ignored) ");
return NF_ACCEPT;
+ case TCP_CONNTRACK_MAX:
+ /* Invalid packet */
+ DEBUGP("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
+ dir, get_conntrack_index(th),
+ old_state);
+ WRITE_UNLOCK(&tcp_lock);
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: invalid state ");
+ return -NF_ACCEPT;
+ case TCP_CONNTRACK_SYN_SENT:
+ if (old_state >= TCP_CONNTRACK_TIME_WAIT) {
+ /* Attempt to reopen a closed connection.
+ * Delete this connection and look up again. */
+ WRITE_UNLOCK(&tcp_lock);
+ if (del_timer(&conntrack->timeout))
+ conntrack->timeout.function((unsigned long)
+ conntrack);
+ return -NF_REPEAT;
+ }
+ break;
+ case TCP_CONNTRACK_CLOSE:
+ if (index == TCP_RST_SET
+ && test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status)
+ && conntrack->proto.tcp.last_index <= TCP_SYNACK_SET
+ && after(ntohl(th->ack_seq),
+ conntrack->proto.tcp.last_seq)) {
+ /* Ignore RST closing down invalid SYN
+ we had let trough. */
+ WRITE_UNLOCK(&tcp_lock);
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_tcp: invalid RST (ignored) ");
+ return NF_ACCEPT;
+ }
+ /* Just fall trough */
+ default:
+ /* Keep compilers happy. */
+ break;
}
- WRITE_LOCK(&tcp_lock);
- oldtcpstate = conntrack->proto.tcp.state;
- newconntrack
- = tcp_conntracks
- [NFCTINFO2DIR(ctinfo)]
- [get_conntrack_index(&tcph)][oldtcpstate];
-
- /* Invalid */
- if (newconntrack == TCP_CONNTRACK_MAX) {
- DEBUGP("nf_conntrack_tcp: Invalid dir=%i index=%u conntrack=%u\n",
- NFCTINFO2DIR(ctinfo), get_conntrack_index(&tcph),
- conntrack->proto.tcp.state);
+ if (!tcp_in_window(&conntrack->proto.tcp, dir, &index,
+ skb, dataoff, th, pf)) {
WRITE_UNLOCK(&tcp_lock);
- return -1;
+ return -NF_ACCEPT;
}
+ /* From now on we have got in-window packets */
- conntrack->proto.tcp.state = newconntrack;
+ /* If FIN was trimmed off, we don't change state. */
+ conntrack->proto.tcp.last_index = index;
+ new_state = tcp_conntracks[dir][index][old_state];
- /* Poor man's window tracking: record SYN/ACK for handshake check */
- if (oldtcpstate == TCP_CONNTRACK_SYN_SENT
- && NFCTINFO2DIR(ctinfo) == NF_CT_DIR_REPLY
- && tcph.syn && tcph.ack) {
- conntrack->proto.tcp.handshake_ack
- = htonl(ntohl(tcph.seq) + 1);
- goto out;
- }
+ DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
+ "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
+ NIPQUAD(iph->saddr), ntohs(th->source),
+ NIPQUAD(iph->daddr), ntohs(th->dest),
+ (th->syn ? 1 : 0), (th->ack ? 1 : 0),
+ (th->fin ? 1 : 0), (th->rst ? 1 : 0),
+ old_state, new_state);
- /* Set ASSURED if we see valid ack in ESTABLISHED after SYN_RECV */
- if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
- && NFCTINFO2DIR(ctinfo) == NF_CT_DIR_ORIGINAL
- && tcph.ack && !tcph.syn
- && tcph.ack_seq == conntrack->proto.tcp.handshake_ack)
- set_bit(NF_S_ASSURED_BIT, &conntrack->status);
+ conntrack->proto.tcp.state = new_state;
+ timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans
+ && *tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
+ ? nf_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
+ WRITE_UNLOCK(&tcp_lock);
-out: WRITE_UNLOCK(&tcp_lock);
- nf_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
+ if (!test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status)) {
+ /* If only reply is a RST, we can consider ourselves not to
+ have an established connection: this is a fairly common
+ problem case, so we can delete the conntrack
+ immediately. --RR */
+ if (th->rst) {
+ if (del_timer(&conntrack->timeout))
+ conntrack->timeout.function((unsigned long)
+ conntrack);
+ return NF_ACCEPT;
+ }
+ } else if (!test_bit(NF_S_ASSURED_BIT, &conntrack->status)
+ && (old_state == TCP_CONNTRACK_SYN_RECV
+ || old_state == TCP_CONNTRACK_ESTABLISHED)
+ && new_state == TCP_CONNTRACK_ESTABLISHED) {
+ /* Set ASSURED if we see see valid ack in ESTABLISHED
+ after SYN_RECV or a valid answer for a picked up
+ connection. */
+ set_bit(NF_S_ASSURED_BIT, &conntrack->status);
+ }
+ nf_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
return NF_ACCEPT;
}
-
-/* Called when a new connection for this protocol found. */
-static int tcp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+
+ /* Called when a new connection for this protocol found. */
+static int tcp_new(struct nf_conn *conntrack,
+ const struct sk_buff *skb,
unsigned int dataoff)
{
- enum tcp_conntrack newconntrack;
- struct tcphdr tcph;
+ enum tcp_conntrack new_state;
+ struct tcphdr *th, _tcph;
+#ifdef DEBUGP_VARS
+ struct nf_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
+ struct nf_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
+#endif
- if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
- return -1;
+ th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+ BUG_ON(th == NULL);
/* Don't need lock here: this conntrack not in circulation yet */
- newconntrack
- = tcp_conntracks[0][get_conntrack_index(&tcph)]
+ new_state
+ = tcp_conntracks[0][get_conntrack_index(th)]
[TCP_CONNTRACK_NONE];
/* Invalid: delete conntrack */
- if (newconntrack == TCP_CONNTRACK_MAX) {
- DEBUGP("nf_conntrack_tcp: invalid new deleting.\n");
+ if (new_state >= TCP_CONNTRACK_MAX) {
+ DEBUGP("nf_ct_tcp: invalid new deleting.\n");
return 0;
}
- conntrack->proto.tcp.state = newconntrack;
+ if (new_state == TCP_CONNTRACK_SYN_SENT) {
+ /* SYN packet */
+ conntrack->proto.tcp.seen[0].td_end =
+ segment_seq_plus_len(ntohl(th->seq), skb->len,
+ dataoff, th);
+ conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+ if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+ conntrack->proto.tcp.seen[0].td_maxwin = 1;
+ conntrack->proto.tcp.seen[0].td_maxend =
+ conntrack->proto.tcp.seen[0].td_end;
+
+ tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
+ conntrack->proto.tcp.seen[1].flags = 0;
+ conntrack->proto.tcp.seen[0].loose =
+ conntrack->proto.tcp.seen[1].loose = 0;
+ } else if (nf_ct_tcp_loose == 0) {
+ /* Don't try to pick up connections. */
+ return 0;
+ } else {
+ /*
+ * We are in the middle of a connection,
+ * its history is lost for us.
+ * Let's try to use the data from the packet.
+ */
+ conntrack->proto.tcp.seen[0].td_end =
+ segment_seq_plus_len(ntohl(th->seq), skb->len,
+ dataoff, th);
+ conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+ if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
+ conntrack->proto.tcp.seen[0].td_maxwin = 1;
+ conntrack->proto.tcp.seen[0].td_maxend =
+ conntrack->proto.tcp.seen[0].td_end +
+ conntrack->proto.tcp.seen[0].td_maxwin;
+ conntrack->proto.tcp.seen[0].td_scale = 0;
+
+ /* We assume SACK. Should we assume window scaling too? */
+ conntrack->proto.tcp.seen[0].flags =
+ conntrack->proto.tcp.seen[1].flags = NF_CT_TCP_FLAG_SACK_PERM;
+ conntrack->proto.tcp.seen[0].loose =
+ conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose;
+ }
+
+ conntrack->proto.tcp.seen[1].td_end = 0;
+ conntrack->proto.tcp.seen[1].td_maxend = 0;
+ conntrack->proto.tcp.seen[1].td_maxwin = 1;
+ conntrack->proto.tcp.seen[1].td_scale = 0;
+
+ /* tcp_packet will set them */
+ conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
+ conntrack->proto.tcp.last_index = TCP_NONE_SET;
+
+ DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
return 1;
}
-
+
static int tcp_exp_matches_pkt(struct nf_conntrack_expect *exp,
- const struct sk_buff *skb, unsigned int dataoff)
+ const struct sk_buff *skb,
+ unsigned dataoff)
{
- struct tcphdr tcph;
+ struct tcphdr *th, _tcph;
unsigned int datalen;
- if (skb_copy_bits(skb, dataoff, &tcph, sizeof(tcph)) != 0)
+ th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
+ if (th == NULL)
return 0;
- datalen = skb->len - dataoff - tcph.doff*4;
+ datalen = skb->len - dataoff - th->doff*4;
- return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
+ return between(exp->seq, ntohl(th->seq), ntohl(th->seq) + datalen);
}
-struct nf_conntrack_protocol nf_conntrack_protocol_tcp
-= { { NULL, NULL }, PF_UNSPEC, IPPROTO_TCP, "tcp",
- tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
- tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
+struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
+{
+ .l3proto = PF_INET,
+ .proto = IPPROTO_TCP,
+ .name = "tcp",
+ .pkt_to_tuple = tcp_pkt_to_tuple,
+ .invert_tuple = tcp_invert_tuple,
+ .print_tuple = tcp_print_tuple,
+ .print_conntrack = tcp_print_conntrack,
+ .packet = tcp_packet,
+ .new = tcp_new,
+ .exp_matches_pkt = tcp_exp_matches_pkt,
+ .error = tcp_error4,
+};
-EXPORT_SYMBOL(nf_conntrack_protocol_tcp);
+struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
+{
+ .l3proto = PF_INET6,
+ .proto = IPPROTO_TCP,
+ .name = "tcp",
+ .pkt_to_tuple = tcp_pkt_to_tuple,
+ .invert_tuple = tcp_invert_tuple,
+ .print_tuple = tcp_print_tuple,
+ .print_conntrack = tcp_print_conntrack,
+ .packet = tcp_packet,
+ .new = tcp_new,
+ .exp_matches_pkt = tcp_exp_matches_pkt,
+ .error = tcp_error6,
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_tcp4);
+EXPORT_SYMBOL(nf_conntrack_protocol_tcp6);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_udp.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_udp.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_proto_udp.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -18,6 +18,12 @@
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/udp.h>
+#include <linux/seq_file.h>
+#include <net/ip6_checksum.h>
+#include <net/checksum.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
unsigned long nf_ct_udp_timeout = 30*HZ;
@@ -27,14 +33,15 @@
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
- struct udphdr hdr;
+ struct udphdr _hdr, *hp;
/* Actually only need first 8 bytes. */
- if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
+ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
return 0;
- tuple->src.u.udp.port = hdr.source;
- tuple->dst.u.udp.port = hdr.dest;
+ tuple->src.u.udp.port = hp->source;
+ tuple->dst.u.udp.port = hp->dest;
return 1;
}
@@ -48,17 +55,17 @@
}
/* Print out the per-protocol part of the tuple. */
-static unsigned int udp_print_tuple(char *buffer,
- const struct nf_conntrack_tuple *tuple)
+static int udp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return sprintf(buffer, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.udp.port),
- ntohs(tuple->dst.u.udp.port));
+ return seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
}
/* Print out the private part of the conntrack. */
-static unsigned int udp_print_conntrack(char *buffer,
- const struct nf_conn *conntrack)
+static int udp_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
{
return 0;
}
@@ -67,21 +74,106 @@
static int udp_packet(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff,
- enum nf_conntrack_info conntrackinfo,
+ enum nf_conntrack_info ctinfo,
+ int pf,
unsigned int hooknum)
{
/* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */
if (test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status)) {
- nf_ct_refresh(conntrack, nf_ct_udp_timeout_stream);
+ nf_ct_refresh_acct(conntrack, ctinfo, skb,
+ nf_ct_udp_timeout_stream);
/* Also, more likely to be important, and not a probe */
set_bit(NF_S_ASSURED_BIT, &conntrack->status);
} else
- nf_ct_refresh(conntrack, nf_ct_udp_timeout);
+ nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout);
return NF_ACCEPT;
}
+static int udp_error(struct sk_buff *skb, unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum,
+ int (*csum)(const struct sk_buff *, unsigned int))
+{
+ unsigned int udplen = skb->len - dataoff;
+ struct udphdr _hdr, *hdr;
+
+ /* Header is too small? */
+ hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hdr == NULL) {
+ if (LOG_INVALID(IPPROTO_UDP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_udp: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ /* Truncated/malformed packets */
+ if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
+ if (LOG_INVALID(IPPROTO_UDP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_udp: truncated/malformed packet ");
+ return -NF_ACCEPT;
+ }
+
+ /* Packet with no checksum */
+ if (!hdr->check)
+ return NF_ACCEPT;
+
+ /* Checksum invalid? Ignore.
+ * We skip checking packets on the outgoing path
+ * because the semantic of CHECKSUM_HW is different there
+ * and moreover root might send raw packets.
+ * FIXME: Source route IP option packets --RR */
+ if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))
+ && csum(skb, dataoff)) {
+ if (LOG_INVALID(IPPROTO_UDP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ "nf_ct_udp: bad UDP checksum ");
+ return -NF_ACCEPT;
+ }
+
+ return NF_ACCEPT;
+}
+
+static int csum4(const struct sk_buff *skb, unsigned int dataoff)
+{
+ return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->len - dataoff, IPPROTO_UDP,
+ skb->ip_summed == CHECKSUM_HW ? skb->csum
+ : skb_checksum(skb, dataoff,
+ skb->len - dataoff, 0));
+}
+
+static int csum6(const struct sk_buff *skb, unsigned int dataoff)
+{
+ return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
+ skb->len - dataoff, IPPROTO_UDP,
+ skb->ip_summed == CHECKSUM_HW ? skb->csum
+ : skb_checksum(skb, dataoff, skb->len - dataoff,
+ 0));
+}
+
+static int udp_error4(struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
+}
+
+static int udp_error6(struct sk_buff *skb,
+ unsigned int dataoff,
+ enum nf_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
+}
+
/* Called when a new connection for this protocol found. */
static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
unsigned int dataoff)
@@ -89,9 +181,33 @@
return 1;
}
-struct nf_conntrack_protocol nf_conntrack_protocol_udp
-= { { NULL, NULL }, PF_UNSPEC, IPPROTO_UDP, "udp",
- udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
- udp_packet, udp_new, NULL, NULL, NULL };
+struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
+{
+ .l3proto = PF_INET,
+ .proto = IPPROTO_UDP,
+ .name = "udp",
+ .pkt_to_tuple = udp_pkt_to_tuple,
+ .invert_tuple = udp_invert_tuple,
+ .print_tuple = udp_print_tuple,
+ .print_conntrack = udp_print_conntrack,
+ .packet = udp_packet,
+ .new = udp_new,
+ .error = udp_error4,
+};
-EXPORT_SYMBOL(nf_conntrack_protocol_udp);
+struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
+{
+ .l3proto = PF_INET6,
+ .proto = IPPROTO_UDP,
+ .name = "udp",
+ .pkt_to_tuple = udp_pkt_to_tuple,
+ .invert_tuple = udp_invert_tuple,
+ .print_tuple = udp_print_tuple,
+ .print_conntrack = udp_print_conntrack,
+ .packet = udp_packet,
+ .new = udp_new,
+ .error = udp_error6,
+};
+
+EXPORT_SYMBOL(nf_conntrack_protocol_udp4);
+EXPORT_SYMBOL(nf_conntrack_protocol_udp6);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_standalone.c
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_standalone.c 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6/net/netfilter/nf_conntrack_standalone.c 2004-11-01 07:38:59 UTC (rev 3260)
@@ -24,6 +24,8 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/percpu.h>
#include <linux/netdevice.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -33,10 +35,10 @@
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&nf_conntrack_lock)
#include <linux/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_conntrack_l3proto.h>
#include <linux/netfilter/nf_conntrack_protocol.h>
#include <linux/netfilter/nf_conntrack_core.h>
#include <linux/netfilter/nf_conntrack_helper.h>
-#include <linux/netfilter/nf_conntrack_l3proto.h>
#include <linux/netfilter_ipv4/listhelp.h>
#if 0
@@ -47,172 +49,339 @@
MODULE_LICENSE("GPL");
+extern atomic_t nf_conntrack_count;
+DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
+
static int kill_l3proto(const struct nf_conn *i, void *data)
{
+ struct nf_conntrack_l3proto *l3proto;
+ l3proto = (struct nf_conntrack_l3proto *)data;
return (i->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.l3num ==
- *((u_int8_t *) data));
+ l3proto->l3proto);
}
static int kill_proto(const struct nf_conn *i, void *data)
{
+ struct nf_conntrack_protocol *proto;
+ proto = (struct nf_conntrack_protocol *)data;
return (i->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.protonum ==
- *((u_int8_t *) data));
+ proto->proto) &&
+ (i->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.l3num ==
+ proto->l3proto);
}
-static unsigned int
-print_tuple(char *buffer, const struct nf_conntrack_tuple *tuple,
+#ifdef CONFIG_PROC_FS
+static int
+print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_protocol *proto)
{
- unsigned int len;
-
- len = l3proto->print_tuple(buffer, tuple);
- len += proto->print_tuple(buffer + len, tuple);
-
- return len;
+ return l3proto->print_tuple(s, tuple) || proto->print_tuple(s, tuple);
}
-
-/* FIXME: Don't print source proto part. --RR */
+#ifdef CONFIG_NF_CT_ACCT
static unsigned int
-print_expect(char *buffer, const struct nf_conntrack_expect *expect)
+seq_print_counters(struct seq_file *s, struct nf_conntrack_counter *counter)
{
- unsigned int len;
+ return seq_printf(s, "packets=%llu bytes=%llu ",
+ (unsigned long long)counter->packets,
+ (unsigned long long)counter->bytes);
+}
+#else
+#define seq_print_counters(x, y) 0
+#endif
- if (expect->expectant->helper->timeout)
- len = sprintf(buffer, "EXPECTING: %lu ",
- timer_pending(&expect->timeout)
- ? (expect->timeout.expires - jiffies)/HZ : 0);
- else
- len = sprintf(buffer, "EXPECTING: - ");
- len += sprintf(buffer + len, "use=%u proto=%u ",
- atomic_read(&expect->use), expect->tuple.dst.protonum);
- len += print_tuple(buffer + len, &expect->tuple,
- __nf_ct_find_l3proto(expect->tuple.src.l3num),
- __nf_ct_find_proto(expect->tuple.src.l3num,
- expect->tuple.dst.protonum));
- len += sprintf(buffer + len, "\n");
- return len;
+static void *ct_seq_start(struct seq_file *s, loff_t *pos)
+{
+ if (*pos >= nf_conntrack_htable_size)
+ return NULL;
+ return &nf_conntrack_hash[*pos];
}
-static unsigned int
-print_conntrack(char *buffer, struct nf_conn *conntrack)
+static void ct_seq_stop(struct seq_file *s, void *v)
{
- unsigned int len;
- struct nf_conntrack_l3proto *l3proto
- = __nf_ct_find_l3proto(conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.src.l3num);
- struct nf_conntrack_protocol *proto
- = __nf_ct_find_proto(conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.src.l3num,
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.dst.protonum);
+}
- if (l3proto == NULL) {
- DEBUGP("Can't find l3proto. pf == %d\n",
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.l3num);
- return 0;
- }
-
- len = sprintf(buffer, "%-8s %u %-8s %u %lu ",
- l3proto->name,
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.src.l3num,
- proto->name,
- conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
- .tuple.dst.protonum,
- timer_pending(&conntrack->timeout)
- ? (conntrack->timeout.expires - jiffies)/HZ : 0);
-
- len += l3proto->print_conntrack(buffer + len, conntrack);
- len += proto->print_conntrack(buffer + len, conntrack);
- len += print_tuple(buffer + len,
- &conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple,
- l3proto, proto);
- if (!(test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status)))
- len += sprintf(buffer + len, "[UNREPLIED] ");
- len += print_tuple(buffer + len,
- &conntrack->tuplehash[NF_CT_DIR_REPLY].tuple,
- l3proto, proto);
- if (test_bit(NF_S_ASSURED_BIT, &conntrack->status))
- len += sprintf(buffer + len, "[ASSURED] ");
- len += sprintf(buffer + len, "use=%u ",
- atomic_read(&conntrack->ct_general.use));
- len += sprintf(buffer + len, "\n");
-
- return len;
+static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+ if (*pos >= nf_conntrack_htable_size)
+ return NULL;
+ return &nf_conntrack_hash[*pos];
}
-/* Returns true when finished. */
-static inline int
-conntrack_iterate(const struct nf_conntrack_tuple_hash *hash,
- char *buffer, off_t offset, off_t *upto,
- unsigned int *len, unsigned int maxlen)
+/* return 0 on success, 1 in case of error */
+static int ct_seq_real_show(const struct nf_conntrack_tuple_hash *hash,
+ struct seq_file *s)
{
- unsigned int newlen;
- NF_CT_ASSERT(hash->ctrack);
+ struct nf_conn *conntrack = hash->ctrack;
+ struct nf_conntrack_l3proto *l3proto;
+ struct nf_conntrack_protocol *proto;
MUST_BE_READ_LOCKED(&nf_conntrack_lock);
- /* Only count originals */
+ NF_CT_ASSERT(conntrack);
+
+ /* we only want to print DIR_ORIGINAL */
if (NF_CT_DIRECTION(hash))
return 0;
- if ((*upto)++ < offset)
- return 0;
+ l3proto = nf_ct_find_l3proto(conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
+ .tuple.src.l3num);
- newlen = print_conntrack(buffer + *len, hash->ctrack);
- if (*len + newlen > maxlen)
+ NF_CT_ASSERT(l3proto);
+ proto = nf_ct_find_proto(conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
+ .tuple.src.l3num,
+ conntrack->tuplehash[NF_CT_DIR_ORIGINAL]
+ .tuple.dst.protonum);
+ NF_CT_ASSERT(proto);
+
+ if (seq_printf(s, "%-8s %u %-8s %u %lu ",
+ l3proto->name,
+ conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.src.l3num,
+ proto->name,
+ conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple.dst.protonum,
+ timer_pending(&conntrack->timeout)
+ ? (conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
return 1;
- else *len += newlen;
+ if (l3proto->print_conntrack(s, conntrack))
+ return 1;
+
+ if (proto->print_conntrack(s, conntrack))
+ return 1;
+
+ if (print_tuple(s, &conntrack->tuplehash[NF_CT_DIR_ORIGINAL].tuple,
+ l3proto, proto))
+ return 1;
+
+ if (seq_print_counters(s, &conntrack->counters[NF_CT_DIR_ORIGINAL]))
+ return 1;
+
+ if (!(test_bit(NF_S_SEEN_REPLY_BIT, &conntrack->status)))
+ if (seq_printf(s, "[UNREPLIED] "))
+ return 1;
+
+ if (print_tuple(s, &conntrack->tuplehash[NF_CT_DIR_REPLY].tuple,
+ l3proto, proto))
+ return 1;
+
+ if (seq_print_counters(s, &conntrack->counters[NF_CT_DIR_REPLY]))
+ return 1;
+
+ if (test_bit(NF_S_ASSURED_BIT, &conntrack->status))
+ if (seq_printf(s, "[ASSURED] "))
+ return 1;
+
+ if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+ return 1;
+
return 0;
}
-static int
-list_conntracks(char *buffer, char **start, off_t offset, int length)
+static int ct_seq_show(struct seq_file *s, void *v)
{
- unsigned int i;
- unsigned int len = 0;
- off_t upto = 0;
- struct list_head *e;
+ struct list_head *list = v;
+ int ret = 0;
+ /* FIXME: Simply truncates if hash chain too long. */
READ_LOCK(&nf_conntrack_lock);
- /* Traverse hash; print originals then reply. */
- for (i = 0; i < nf_conntrack_htable_size; i++) {
- if (LIST_FIND(&nf_conntrack_hash[i], conntrack_iterate,
- struct nf_conntrack_tuple_hash *,
- buffer, offset, &upto, &len, length))
- goto finished;
- }
+ if (LIST_FIND(list, ct_seq_real_show,
+ struct nf_conntrack_tuple_hash *, s))
+ ret = -ENOSPC;
+ READ_UNLOCK(&nf_conntrack_lock);
+ return ret;
+}
- /* Now iterate through expecteds. */
+static struct seq_operations ct_seq_ops = {
+ .start = ct_seq_start,
+ .next = ct_seq_next,
+ .stop = ct_seq_stop,
+ .show = ct_seq_show
+};
+
+static int ct_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ct_seq_ops);
+}
+
+static struct file_operations ct_file_ops = {
+ .owner = THIS_MODULE,
+ .open = ct_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+/* expects */
+static void *exp_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct list_head *e = &nf_conntrack_expect_list;
+ loff_t i;
+
+ /* strange seq_file api calls stop even if we fail,
+ * thus we need to grab lock since stop unlocks */
+ READ_LOCK(&nf_conntrack_lock);
READ_LOCK(&nf_conntrack_expect_tuple_lock);
- list_for_each(e, &nf_conntrack_expect_list) {
- unsigned int last_len;
- struct nf_conntrack_expect *expect
- = (struct nf_conntrack_expect *)e;
- if (upto++ < offset) continue;
- last_len = len;
- len += print_expect(buffer + len, expect);
- if (len > length) {
- len = last_len;
- goto finished_expects;
- }
+ if (list_empty(e))
+ return NULL;
+
+ for (i = 0; i <= *pos; i++) {
+ e = e->next;
+ if (e == &nf_conntrack_expect_list)
+ return NULL;
}
+ return e;
+}
- finished_expects:
+static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct list_head *e = v;
+
+ e = e->next;
+
+ if (e == &nf_conntrack_expect_list)
+ return NULL;
+
+ return e;
+}
+
+static void exp_seq_stop(struct seq_file *s, void *v)
+{
READ_UNLOCK(&nf_conntrack_expect_tuple_lock);
- finished:
READ_UNLOCK(&nf_conntrack_lock);
+}
- /* `start' hack - see fs/proc/generic.c line ~165 */
- *start = (char *)((unsigned int)upto - offset);
- return len;
+static int exp_seq_show(struct seq_file *s, void *v)
+{
+ struct nf_conntrack_expect *expect = v;
+
+ if (expect->expectant->helper->timeout)
+ seq_printf(s, "%lu ", timer_pending(&expect->timeout)
+ ? (expect->timeout.expires - jiffies)/HZ : 0);
+ else
+ seq_printf(s, "- ");
+ seq_printf(s, "use=%u l3proto = %u proto=%u ",
+ atomic_read(&expect->use),
+ expect->tuple.src.l3num,
+ expect->tuple.dst.protonum);
+ print_tuple(s, &expect->tuple,
+ nf_ct_find_l3proto(expect->tuple.src.l3num),
+ nf_ct_find_proto(expect->tuple.src.l3num,
+ expect->tuple.dst.protonum));
+ return seq_putc(s, '\n');
}
+static struct seq_operations exp_seq_ops = {
+ .start = exp_seq_start,
+ .next = exp_seq_next,
+ .stop = exp_seq_stop,
+ .show = exp_seq_show
+};
+
+static int exp_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &exp_seq_ops);
+}
+
+static struct file_operations exp_file_ops = {
+ .owner = THIS_MODULE,
+ .open = exp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ int cpu;
+
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
+
+ for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+ if (!cpu_possible(cpu))
+ continue;
+ *pos = cpu + 1;
+ return &per_cpu(nf_conntrack_stat, cpu);
+ }
+
+ return NULL;
+}
+
+static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ int cpu;
+
+ for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+ if (!cpu_possible(cpu))
+ continue;
+ *pos = cpu + 1;
+ return &per_cpu(nf_conntrack_stat, cpu);
+ }
+
+ return NULL;
+}
+
+static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int ct_cpu_seq_show(struct seq_file *seq, void *v)
+{
+ unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
+ struct nf_conntrack_stat *st = v;
+
+ if (v == SEQ_START_TOKEN) {
+ seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n");
+ return 0;
+ }
+
+ seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x "
+ "%08x %08x %08x %08x %08x %08x %08x %08x \n",
+ nr_conntracks,
+ st->searched,
+ st->found,
+ st->new,
+ st->invalid,
+ st->ignore,
+ st->delete,
+ st->delete_list,
+ st->insert,
+ st->insert_failed,
+ st->drop,
+ st->early_drop,
+ st->error,
+
+ st->expect_new,
+ st->expect_create,
+ st->expect_delete
+ );
+ return 0;
+}
+
+static struct seq_operations ct_cpu_seq_ops = {
+ .start = ct_cpu_seq_start,
+ .next = ct_cpu_seq_next,
+ .stop = ct_cpu_seq_stop,
+ .show = ct_cpu_seq_show,
+};
+
+static int ct_cpu_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ct_cpu_seq_ops);
+}
+
+static struct file_operations ct_cpu_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = ct_cpu_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+#endif /* CONFIG_PROC_FS */
+
/* Sysctl support */
-
#ifdef CONFIG_SYSCTL
/* From nf_conntrack_core.c */
@@ -228,6 +397,10 @@
extern unsigned long nf_ct_tcp_timeout_last_ack;
extern unsigned long nf_ct_tcp_timeout_time_wait;
extern unsigned long nf_ct_tcp_timeout_close;
+extern unsigned long nf_ct_tcp_timeout_max_retrans;
+extern int nf_ct_tcp_loose;
+extern int nf_ct_tcp_be_liberal;
+extern int nf_ct_tcp_max_retrans;
/* From nf_conntrack_proto_udp.c */
extern unsigned long nf_ct_udp_timeout;
@@ -236,6 +409,10 @@
/* From nf_conntrack_proto_generic.c */
extern unsigned long nf_ct_generic_timeout;
+/* Log invalid packets of a given protocol */
+static int log_invalid_proto_min = 0;
+static int log_invalid_proto_max = 255;
+
static struct ctl_table_header *nf_ct_sysctl_header;
static ctl_table nf_ct_sysctl_table[] = {
@@ -248,6 +425,14 @@
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = NET_NF_CONNTRACK_COUNT,
+ .procname = "nf_conntrack_count",
+ .data = &nf_conntrack_count,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = NET_NF_CONNTRACK_BUCKETS,
.procname = "nf_conntrack_buckets",
.data = &nf_conntrack_htable_size,
@@ -343,6 +528,50 @@
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
},
+ {
+ .ctl_name = NET_NF_CONNTRACK_LOG_INVALID,
+ .procname = "nf_conntrack_log_invalid",
+ .data = &nf_ct_log_invalid,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &log_invalid_proto_min,
+ .extra2 = &log_invalid_proto_max,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,
+ .procname = "nf_conntrack_tcp_timeout_max_retrans",
+ .data = &nf_ct_tcp_timeout_max_retrans,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_TCP_LOOSE,
+ .procname = "nf_conntrack_tcp_loose",
+ .data = &nf_ct_tcp_loose,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_TCP_BE_LIBERAL,
+ .procname = "nf_conntrack_tcp_be_liberal",
+ .data = &nf_ct_tcp_be_liberal,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = NET_NF_CONNTRACK_TCP_MAX_RETRANS,
+ .procname = "nf_conntrack_tcp_max_retrans",
+ .data = &nf_ct_tcp_max_retrans,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+
{ .ctl_name = 0 }
};
@@ -375,10 +604,14 @@
},
{ .ctl_name = 0 }
};
-#endif
+EXPORT_SYMBOL(nf_ct_log_invalid);
+#endif /* CONFIG_SYSCTL */
+
static int init_or_cleanup(int init)
{
- struct proc_dir_entry *proc;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc, *proc_exp, *proc_stat;
+#endif
int ret = 0;
if (!init) goto cleanup;
@@ -387,16 +620,27 @@
if (ret < 0)
goto cleanup_nothing;
- proc = proc_net_create("nf_conntrack",0,list_conntracks);
+#ifdef CONFIG_PROC_FS
+ proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
if (!proc) goto cleanup_init;
- proc->owner = THIS_MODULE;
+ proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
+ &exp_file_ops);
+ if (!proc_exp) goto cleanup_proc;
+
+ proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
+ if (!proc_stat)
+ goto cleanup_proc_exp;
+
+ proc_stat->proc_fops = &ct_cpu_seq_fops;
+ proc_stat->owner = THIS_MODULE;
+#endif
#ifdef CONFIG_SYSCTL
nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
if (nf_ct_sysctl_header == NULL) {
printk("nf_conntrack: can't register to sysctl.\n");
ret = -ENOMEM;
- goto cleanup_proc;
+ goto cleanup_proc_stat;
}
#endif
@@ -405,10 +649,16 @@
cleanup:
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(nf_ct_sysctl_header);
+ cleanup_proc_stat:
+#endif
+#ifdef CONFIG_PROC_FS
+ proc_net_remove("nf_conntrack_stat");
+ cleanup_proc_exp:
+ proc_net_remove("nf_conntrack_expect");
cleanup_proc:
-#endif
proc_net_remove("nf_conntrack");
cleanup_init:
+#endif /* CNFIG_PROC_FS */
nf_conntrack_cleanup();
cleanup_nothing:
return ret;
@@ -417,41 +667,30 @@
int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
{
int ret = 0;
- struct list_head *i;
WRITE_LOCK(&nf_conntrack_lock);
- list_for_each(i, &l3proto_list) {
- if (((struct nf_conntrack_l3proto *)i)->l3proto
- == proto->l3proto) {
- ret = -EBUSY;
- WRITE_UNLOCK(&nf_conntrack_lock);
- goto out;
- }
+ if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_generic_l3proto) {
+ ret = -EBUSY;
+ goto out;
}
-
- list_prepend(&l3proto_list, proto);
+ nf_ct_l3protos[proto->l3proto] = proto;
+out:
WRITE_UNLOCK(&nf_conntrack_lock);
- ret = proto->init();
- out:
return ret;
}
void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
{
- proto->fini();
WRITE_LOCK(&nf_conntrack_lock);
-
- /* nf_ct_find_proto() returns proto_generic in case there is no protocol
- * helper. So this should be enough - HW */
- LIST_DELETE(&l3proto_list, proto);
+ nf_ct_l3protos[proto->l3proto] = &nf_conntrack_generic_l3proto;
WRITE_UNLOCK(&nf_conntrack_lock);
/* Somebody could be still looking at the proto in bh. */
synchronize_net();
/* Remove all contrack entries for this protocol */
- nf_ct_selective_cleanup(kill_l3proto, &proto->l3proto);
+ nf_ct_selective_cleanup(kill_l3proto, proto);
}
/* FIXME: Allow NULL functions and sub in pointers to generic for
@@ -459,40 +698,70 @@
int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto)
{
int ret = 0;
- struct list_head *i;
+retry:
WRITE_LOCK(&nf_conntrack_lock);
- list_for_each(i, &protocol_list) {
- if (((struct nf_conntrack_protocol *)i)->proto
- == proto->proto &&
- ((struct nf_conntrack_protocol *)i)->l3proto
- == proto->l3proto) {
+ if (nf_ct_protos[proto->l3proto]) {
+ if (nf_ct_protos[proto->l3proto][proto->proto]
+ != &nf_conntrack_generic_protocol) {
ret = -EBUSY;
+ goto out_unlock;
+ }
+ } else {
+ /* l3proto may be loaded latter. */
+ struct nf_conntrack_protocol **proto_array;
+ int i;
+
+ WRITE_UNLOCK(&nf_conntrack_lock);
+
+ proto_array = (struct nf_conntrack_protocol **)
+ kmalloc(MAX_NF_CT_PROTO *
+ sizeof(struct nf_conntrack_protocol *),
+ GFP_KERNEL);
+ if (proto_array == NULL) {
+ ret = -ENOMEM;
goto out;
}
+ for (i = 0; i < MAX_NF_CT_PROTO; i++)
+ proto_array[i] = &nf_conntrack_generic_protocol;
+
+ WRITE_LOCK(&nf_conntrack_lock);
+ if (nf_ct_protos[proto->l3proto]) {
+ /* bad timing, but no problem */
+ WRITE_UNLOCK(&nf_conntrack_lock);
+ kfree(proto_array);
+ } else {
+ nf_ct_protos[proto->l3proto] = proto_array;
+ WRITE_UNLOCK(&nf_conntrack_lock);
+ }
+
+ /*
+ * Just once because array is never freed until unloading
+ * nf_conntrack.ko
+ */
+ goto retry;
}
- list_prepend(&protocol_list, proto);
+ nf_ct_protos[proto->l3proto][proto->proto] = proto;
- out:
+out_unlock:
WRITE_UNLOCK(&nf_conntrack_lock);
+out:
return ret;
}
void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto)
{
WRITE_LOCK(&nf_conntrack_lock);
-
- /* nf_ct_find_proto() returns proto_generic in case there is no protocol
- * helper. So this should be enough - HW */
- LIST_DELETE(&protocol_list, proto);
+ nf_ct_protos[proto->l3proto][proto->proto]
+ = &nf_conntrack_generic_protocol;
WRITE_UNLOCK(&nf_conntrack_lock);
/* Somebody could be still looking at the proto in bh. */
synchronize_net();
/* Remove all contrack entries for this protocol */
- nf_ct_selective_cleanup(kill_proto, &proto->proto);
+ nf_ct_selective_cleanup(kill_proto, proto);
}
static int __init init(void)
@@ -514,19 +783,21 @@
{
}
+EXPORT_SYMBOL(nf_conntrack_l3proto_register);
+EXPORT_SYMBOL(nf_conntrack_l3proto_unregister);
EXPORT_SYMBOL(nf_conntrack_protocol_register);
EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
EXPORT_SYMBOL(nf_ct_invert_tuplepr);
EXPORT_SYMBOL(nf_conntrack_alter_reply);
EXPORT_SYMBOL(nf_conntrack_destroyed);
-EXPORT_SYMBOL(nf_ct_get);
EXPORT_SYMBOL(need_nf_conntrack);
EXPORT_SYMBOL(nf_conntrack_helper_register);
EXPORT_SYMBOL(nf_conntrack_helper_unregister);
EXPORT_SYMBOL(nf_ct_selective_cleanup);
-EXPORT_SYMBOL(nf_ct_refresh);
+EXPORT_SYMBOL(nf_ct_refresh_acct);
+EXPORT_SYMBOL(nf_ct_protos);
EXPORT_SYMBOL(nf_ct_find_proto);
-EXPORT_SYMBOL(__nf_ct_find_proto);
+EXPORT_SYMBOL(nf_ct_l3protos);
EXPORT_SYMBOL(nf_ct_find_helper);
EXPORT_SYMBOL(nf_conntrack_expect_alloc);
EXPORT_SYMBOL(nf_conntrack_expect_related);
@@ -539,12 +810,13 @@
EXPORT_SYMBOL(nf_conntrack_expect_list);
EXPORT_SYMBOL(nf_conntrack_lock);
EXPORT_SYMBOL(nf_conntrack_hash);
+EXPORT_SYMBOL(nf_conntrack_untracked);
EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
EXPORT_SYMBOL_GPL(nf_ct_put);
-EXPORT_SYMBOL(nf_conntrack_untracked);
-EXPORT_SYMBOL(nf_conntrack_l3proto_register);
-EXPORT_SYMBOL(nf_conntrack_l3proto_unregister);
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(nf_conntrack_tcp_update);
+#endif
+EXPORT_SYMBOL(__nf_conntrack_confirm);
EXPORT_SYMBOL(nf_ct_get_tuple);
EXPORT_SYMBOL(nf_ct_invert_tuple);
-EXPORT_SYMBOL(nf_conntrack_confirm);
EXPORT_SYMBOL(nf_conntrack_in);
Modified: trunk/patch-o-matic-ng/nf_conntrack/linux-2.6.patch
===================================================================
--- trunk/patch-o-matic-ng/nf_conntrack/linux-2.6.patch 2004-10-24 22:27:31 UTC (rev 3259)
+++ trunk/patch-o-matic-ng/nf_conntrack/linux-2.6.patch 2004-11-01 07:38:59 UTC (rev 3260)
@@ -1,18 +1,164 @@
-diff -Nur linux-2.6.7/include/linux/netfilter.h linux-2.6.7-nfct/include/linux/netfilter.h
---- linux-2.6.7/include/linux/netfilter.h 2004-06-16 14:19:23.000000000 +0900
-+++ linux-2.6.7-nfct/include/linux/netfilter.h 2004-06-30 17:50:38.000000000 +0900
-@@ -178,6 +178,7 @@
+--- linux-2.6.10-rc1/./net/Makefile 2004-09-14 02:13:55.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/Makefile 2004-10-27 11:28:17.429989192 +0900
+@@ -41,6 +41,7 @@ obj-$(CONFIG_DECNET) += decnet/
+ obj-$(CONFIG_ECONET) += econet/
+ obj-$(CONFIG_VLAN_8021Q) += 8021q/
+ obj-$(CONFIG_IP_SCTP) += sctp/
++obj-$(CONFIG_NETFILTER) += netfilter/
+
+ ifeq ($(CONFIG_NET),y)
+ obj-$(CONFIG_SYSCTL) += sysctl_net.o
+--- linux-2.6.10-rc1/./net/core/skbuff.c 2004-10-27 10:41:07.748166216 +0900
++++ linux-2.6.10-rc1-nfct/./net/core/skbuff.c 2004-10-27 11:28:17.430989040 +0900
+@@ -240,6 +240,7 @@ void __kfree_skb(struct sk_buff *skb)
+ }
+ #ifdef CONFIG_NETFILTER
+ nf_conntrack_put(skb->nfct);
++ nf_conntrack_put_reasm(skb->reasm);
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ nf_bridge_put(skb->nf_bridge);
+ #endif
+@@ -312,6 +313,8 @@ struct sk_buff *skb_clone(struct sk_buff
+ C(nfct);
+ nf_conntrack_get(skb->nfct);
+ C(nfctinfo);
++ C(reasm);
++ nf_conntrack_get_reasm(skb->reasm);
+ #ifdef CONFIG_NETFILTER_DEBUG
+ C(nf_debug);
+ #endif
+@@ -379,6 +382,8 @@ static void copy_skb_header(struct sk_bu
+ new->nfct = old->nfct;
+ nf_conntrack_get(old->nfct);
+ new->nfctinfo = old->nfctinfo;
++ nf_conntrack_get_reasm(old->reasm);
++ new->reasm = old->reasm;
+ #ifdef CONFIG_NETFILTER_DEBUG
+ new->nf_debug = old->nf_debug;
+ #endif
+--- linux-2.6.10-rc1/./net/core/netfilter.c 2004-09-30 21:04:21.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/core/netfilter.c 2004-10-27 11:28:17.431988888 +0900
+@@ -807,6 +807,7 @@ EXPORT_SYMBOL(nf_log_packet);
+ and hence manufactured ICMP or RST packets will not be associated
+ with it. */
+ void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
++void (*nf_ct_attach)(struct sk_buff *, struct sk_buff *);
+
+ void __init netfilter_init(void)
+ {
+@@ -819,6 +820,7 @@ void __init netfilter_init(void)
+ }
+
+ EXPORT_SYMBOL(ip_ct_attach);
++EXPORT_SYMBOL(nf_ct_attach);
+ EXPORT_SYMBOL(ip_route_me_harder);
+ EXPORT_SYMBOL(nf_getsockopt);
+ EXPORT_SYMBOL(nf_hook_slow);
+--- linux-2.6.10-rc1/./net/ipv6/ip6_output.c 2004-09-30 21:04:27.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/ipv6/ip6_output.c 2004-10-27 11:28:17.432988736 +0900
+@@ -478,6 +478,9 @@ static void ip6_copy_metadata(struct sk_
+ to->nfct = from->nfct;
+ nf_conntrack_get(to->nfct);
+ to->nfctinfo = from->nfctinfo;
++ nf_conntrack_put_reasm(from->reasm);
++ nf_conntrack_get_reasm(to->reasm);
++ to->reasm = from->reasm;
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ nf_bridge_put(to->nf_bridge);
+ to->nf_bridge = from->nf_bridge;
+--- linux-2.6.10-rc1/./net/ipv6/netfilter/Makefile 2004-09-30 21:04:28.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/ipv6/netfilter/Makefile 2004-10-27 11:28:17.432988736 +0900
+@@ -24,3 +24,9 @@ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.
+ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
++
++# objects for l3 independent conntrack
++nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
++
++# l3 independent conntrack
++obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
+--- linux-2.6.10-rc1/./net/ipv6/netfilter/Kconfig 2004-09-30 21:04:28.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/ipv6/netfilter/Kconfig 2004-10-27 11:28:17.432988736 +0900
+@@ -239,5 +239,20 @@ config IP6_NF_RAW
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+ help
+
++config NF_CONNTRACK_IPV6
++ tristate "IPv6 support on new connection tracking (EXPERIMENTAL)"
++ depends on EXPERIMENTAL && ! IP6_NF_CONNTRACK
++ select NF_CONNTRACK
++ ---help---
++ Connection tracking keeps a record of what packets have passed
++ through your machine, in order to figure out how they are related
++ into connections.
++
++ This is IPv6 support on Layer 3 independent connection tracking.
++ Layer 3 independent connection tracking is experimental scheme
++ which generalize ip_conntrack to support other layer 3 protocols.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ endmenu
+
+--- linux-2.6.10-rc1/./net/ipv4/netfilter/Makefile 2004-10-27 10:41:07.757164848 +0900
++++ linux-2.6.10-rc1-nfct/./net/ipv4/netfilter/Makefile 2004-10-27 11:28:17.432988736 +0900
+@@ -101,3 +101,9 @@ obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += i
+ obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o
+
+ obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
++
++# objects for l3 independent conntrack
++nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
++
++# l3 independent conntrack
++obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
+--- linux-2.6.10-rc1/./net/ipv4/netfilter/Kconfig 2004-10-27 10:41:07.757164848 +0900
++++ linux-2.6.10-rc1-nfct/./net/ipv4/netfilter/Kconfig 2004-10-27 11:28:17.433988584 +0900
+@@ -732,5 +732,20 @@ config IP_NF_COMPAT_IPFWADM
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config NF_CONNTRACK_IPV4
++ tristate "IPv4 support on new connection tracking (EXPERIMENTAL)"
++ depends on EXPERIMENTAL && !IP_NF_CONNTRACK
++ select NF_CONNTRACK
++ ---help---
++ Connection tracking keeps a record of what packets have passed
++ through your machine, in order to figure out how they are related
++ into connections.
++
++ This is IPv4 support on Layer 3 independent connection tracking.
++ Layer 3 independent connection tracking is experimental scheme
++ which generalize ip_conntrack to support other layer 3 protocols.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ endmenu
+
+--- linux-2.6.10-rc1/./net/Kconfig 2004-08-25 08:16:03.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./net/Kconfig 2004-10-27 11:28:17.433988584 +0900
+@@ -216,6 +216,7 @@ source "net/ipv4/netfilter/Kconfig"
+ source "net/ipv6/netfilter/Kconfig"
+ source "net/decnet/netfilter/Kconfig"
+ source "net/bridge/netfilter/Kconfig"
++source "net/netfilter/Kconfig"
+
+ endif
+
+--- linux-2.6.10-rc1/./include/linux/netfilter.h 2004-09-30 21:02:02.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./include/linux/netfilter.h 2004-10-27 11:28:17.434988432 +0900
+@@ -179,6 +179,7 @@ ip6t_find_target_lock(const char *name,
extern inline struct arpt_target *
arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex);
- extern void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
-+extern void (*nf_ct_attach)(struct sk_buff *, struct nf_ct_info *);
+ extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
++extern void (*nf_ct_attach)(struct sk_buff *, struct sk_buff *);
#ifdef CONFIG_NETFILTER_DEBUG
extern void nf_dump_skb(int pf, struct sk_buff *skb);
-diff -Nur linux-2.6.7/include/linux/sysctl.h linux-2.6.7-nfct/include/linux/sysctl.h
---- linux-2.6.7/include/linux/sysctl.h 2004-06-16 14:19:35.000000000 +0900
-+++ linux-2.6.7-nfct/include/linux/sysctl.h 2004-06-30 17:45:50.000000000 +0900
-@@ -187,6 +187,7 @@
+--- linux-2.6.10-rc1/./include/linux/sysctl.h 2004-10-27 10:41:07.646181720 +0900
++++ linux-2.6.10-rc1-nfct/./include/linux/sysctl.h 2004-10-27 11:31:51.297476392 +0900
+@@ -191,6 +191,7 @@ enum
NET_DECNET=15,
NET_ECONET=16,
NET_SCTP=17,
@@ -20,7 +166,7 @@
};
/* /proc/sys/kernel/random */
-@@ -251,6 +252,29 @@
+@@ -255,6 +256,42 @@ enum
NET_UNIX_MAX_DGRAM_QLEN=3,
};
@@ -41,53 +187,75 @@
+ NET_NF_CONNTRACK_ICMP_TIMEOUT=12,
+ NET_NF_CONNTRACK_GENERIC_TIMEOUT=13,
+ NET_NF_CONNTRACK_BUCKETS=14,
-+ NET_NF_CONNTRACK_ICMPV6_TIMEOUT=15,
-+ NET_NF_CONNTRACK_FRAG6_TIMEOUT=16,
-+ NET_NF_CONNTRACK_FRAG6_LOW_THRESH=17,
-+ NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=18,
++ NET_NF_CONNTRACK_LOG_INVALID=15,
++ NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16,
++ NET_NF_CONNTRACK_TCP_LOOSE=17,
++ NET_NF_CONNTRACK_TCP_BE_LIBERAL=18,
++ NET_NF_CONNTRACK_TCP_MAX_RETRANS=19,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25,
++ NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26,
++ NET_NF_CONNTRACK_COUNT=27,
++ NET_NF_CONNTRACK_ICMPV6_TIMEOUT=28,
++ NET_NF_CONNTRACK_FRAG6_TIMEOUT=29,
++ NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30,
++ NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31,
+};
+
/* /proc/sys/net/ipv4 */
enum
{
-diff -Nur linux-2.6.7/net/Kconfig linux-2.6.7-nfct/net/Kconfig
---- linux-2.6.7/net/Kconfig 2004-06-16 14:18:57.000000000 +0900
-+++ linux-2.6.7-nfct/net/Kconfig 2004-06-30 17:45:50.000000000 +0900
-@@ -214,6 +214,7 @@
- source "net/ipv6/netfilter/Kconfig"
- source "net/decnet/netfilter/Kconfig"
- source "net/bridge/netfilter/Kconfig"
-+source "net/netfilter/Kconfig"
+--- linux-2.6.10-rc1/./include/linux/skbuff.h 2004-10-12 09:28:58.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./include/linux/skbuff.h 2004-10-27 11:28:17.435988280 +0900
+@@ -251,6 +251,7 @@ struct sk_buff {
+ __u32 nfcache;
+ __u32 nfctinfo;
+ struct nf_conntrack *nfct;
++ struct sk_buff *reasm;
+ #ifdef CONFIG_NETFILTER_DEBUG
+ unsigned int nf_debug;
+ #endif
+@@ -1148,10 +1149,22 @@ static inline void nf_conntrack_get(stru
+ if (nfct)
+ atomic_inc(&nfct->use);
+ }
++static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
++{
++ if (skb)
++ atomic_inc(&skb->users);
++}
++static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
++{
++ if (skb)
++ kfree_skb(skb);
++}
+ static inline void nf_reset(struct sk_buff *skb)
+ {
+ nf_conntrack_put(skb->nfct);
+ skb->nfct = NULL;
++ nf_conntrack_put_reasm(skb->reasm);
++ skb->reasm = NULL;
+ #ifdef CONFIG_NETFILTER_DEBUG
+ skb->nf_debug = 0;
+ #endif
+--- linux-2.6.10-rc1/./include/linux/netfilter_ipv6.h 2004-09-14 02:11:32.000000000 +0900
++++ linux-2.6.10-rc1-nfct/./include/linux/netfilter_ipv6.h 2004-10-27 11:28:17.435988280 +0900
+@@ -56,6 +56,7 @@
- endif
+ enum nf_ip6_hook_priorities {
+ NF_IP6_PRI_FIRST = INT_MIN,
++ NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
+ NF_IP6_PRI_SELINUX_FIRST = -225,
+ NF_IP6_PRI_CONNTRACK = -200,
+ NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
+@@ -68,4 +69,6 @@ enum nf_ip6_hook_priorities {
+ NF_IP6_PRI_LAST = INT_MAX,
+ };
-diff -Nur linux-2.6.7/net/Makefile linux-2.6.7-nfct/net/Makefile
---- linux-2.6.7/net/Makefile 2004-06-16 14:19:22.000000000 +0900
-+++ linux-2.6.7-nfct/net/Makefile 2004-06-30 17:45:50.000000000 +0900
-@@ -40,6 +40,7 @@
- obj-$(CONFIG_ECONET) += econet/
- obj-$(CONFIG_VLAN_8021Q) += 8021q/
- obj-$(CONFIG_IP_SCTP) += sctp/
-+obj-$(CONFIG_NETFILTER) += netfilter/
-
- ifeq ($(CONFIG_NET),y)
- obj-$(CONFIG_SYSCTL) += sysctl_net.o
-diff -Nur linux-2.6.7/net/core/netfilter.c linux-2.6.7-nfct/net/core/netfilter.c
---- linux-2.6.7/net/core/netfilter.c 2004-06-16 14:19:22.000000000 +0900
-+++ linux-2.6.7-nfct/net/core/netfilter.c 2004-06-30 17:46:47.000000000 +0900
-@@ -807,6 +807,7 @@
- and hence manufactured ICMP or RST packets will not be associated
- with it. */
- void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
-+void (*nf_ct_attach)(struct sk_buff *, struct nf_ct_info *);
-
- void __init netfilter_init(void)
- {
-@@ -819,6 +820,7 @@
- }
-
- EXPORT_SYMBOL(ip_ct_attach);
-+EXPORT_SYMBOL(nf_ct_attach);
- EXPORT_SYMBOL(ip_route_me_harder);
- EXPORT_SYMBOL(nf_getsockopt);
- EXPORT_SYMBOL(nf_hook_slow);
++#define SO_ORIGINAL_DST 80
++
+ #endif /*__LINUX_IP6_NETFILTER_H*/
More information about the netfilter-cvslog
mailing list