1diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
2--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Apr 27 14:15:01 2001
3+++ linux/include/linux/netfilter_ipv4/ip_conntrack.h	Fri Jun  1 06:47:50 2001
4@@ -23,8 +23,26 @@
5 	/* >= this indicates reply direction */
6 	IP_CT_IS_REPLY,
7 
8-	/* Number of distinct IP_CT types (no NEW in reply dirn). */
9-	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
10+	/* For ctnetlink only, when connection gets deleted. */
11+        IP_CT_DELETE,
12+
13+	/* Number of distinct IP_CT types (no NEW in reply dirn, no DELETE). */
14+	IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 
15+};
16+
17+/* Bitset representing status of connection. */
18+enum ip_conntrack_status {
19+        /* It's an expected connection: bit 0 set.  This bit never changed */
20+        IPS_EXPECTED_BIT = 0,
21+        IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
22+
23+        /* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
24+        IPS_SEEN_REPLY_BIT = 1,
25+        IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
26+
27+        /* Conntrack should never be early-expired. */
28+        IPS_ASSURED_BIT = 2,
29+        IPS_ASSURED = (1 << IPS_ASSURED_BIT),
30 };
31 
32 #ifdef __KERNEL__
33@@ -47,21 +65,6 @@
34 #define IP_NF_ASSERT(x)
35 #endif
36 
37-/* Bitset representing status of connection. */
38-enum ip_conntrack_status {
39-	/* It's an expected connection: bit 0 set.  This bit never changed */
40-	IPS_EXPECTED_BIT = 0,
41-	IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
42-
43-	/* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
44-	IPS_SEEN_REPLY_BIT = 1,
45-	IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
46-
47-	/* Conntrack should never be early-expired. */
48-	IPS_ASSURED_BIT = 2,
49-	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
50-};
51-
52 struct ip_conntrack_expect
53 {
54 	/* Internal linked list */
55@@ -163,9 +166,24 @@
56 extern void ip_ct_refresh(struct ip_conntrack *ct,
57 			  unsigned long extra_jiffies);
58 
59-/* These are for NAT.  Icky. */
60-/* Call me when a conntrack is destroyed. */
61-extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
62+/* This is for the ip_conntrack_notify facilities. */
63+struct ip_conntrack_notify
64+{
65+        /* Internal use. */
66+        struct list_head list;
67+
68+	void (*destroyed)(struct ip_conntrack *conntrack);
69+        void (*created)(struct ip_conntrack *conntrack,
70+                enum ip_conntrack_info info,
71+                const struct net_device *in, 
72+		const struct net_device *out);
73+};
74+
75+extern int ip_conntrack_notify_register(struct ip_conntrack_notify *nb);
76+extern int ip_conntrack_notify_unregister(struct ip_conntrack_notify *nb);
77+
78+/* For ctnetlink. */
79+extern void ip_conntrack_put(struct ip_conntrack *ct);
80 
81 /* Returns new sk_buff, or NULL */
82 struct sk_buff *
83diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_core.h linux/include/linux/netfilter_ipv4/ip_conntrack_core.h
84--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Apr 27 14:15:01 2001
85+++ linux/include/linux/netfilter_ipv4/ip_conntrack_core.h	Fri Jun  1 06:47:50 2001
86@@ -29,7 +29,7 @@
87 		     struct ip_conntrack_protocol *protocol);
88 
89 /* Find a connection corresponding to a tuple. */
90-struct ip_conntrack_tuple_hash *
91+extern struct ip_conntrack_tuple_hash *
92 ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
93 		      const struct ip_conntrack *ignored_conntrack);
94 
95@@ -44,6 +44,7 @@
96 	return NF_ACCEPT;
97 }
98 
99+extern unsigned int ip_conntrack_htable_size;
100 extern struct list_head *ip_conntrack_hash;
101 extern struct list_head expect_list;
102 DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
103diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_ftp.h linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
104--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Wed Apr 25 15:00:28 2001
105+++ linux/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Fri Jun  1 06:47:50 2001
106@@ -2,15 +2,6 @@
107 #define _IP_CONNTRACK_FTP_H
108 /* FTP tracking. */
109 
110-#ifndef __KERNEL__
111-#error Only in kernel.
112-#endif
113-
114-#include <linux/netfilter_ipv4/lockhelp.h>
115-
116-/* Protects ftp part of conntracks */
117-DECLARE_LOCK_EXTERN(ip_ftp_lock);
118-
119 enum ip_ct_ftp_type
120 {
121 	/* PORT command from client */
122@@ -41,4 +32,10 @@
123 	int seq_aft_nl_set[IP_CT_DIR_MAX];
124 };
125 
126+#ifdef __KERNEL__
127+#include <linux/netfilter_ipv4/lockhelp.h>
128+
129+/* Protects ftp part of conntracks */
130+DECLARE_LOCK_EXTERN(ip_ftp_lock);
131+#endif /* __KERNEL__ */
132 #endif /* _IP_CONNTRACK_FTP_H */
133diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_netlink.h linux/include/linux/netfilter_ipv4/ip_conntrack_netlink.h
134--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_netlink.h	Wed Dec 31 16:00:00 1969
135+++ linux/include/linux/netfilter_ipv4/ip_conntrack_netlink.h	Fri Jun  1 05:55:25 2001
136@@ -0,0 +1,119 @@
137+#ifndef _IP_CONNTRACK_NETLINK_H
138+#define _IP_CONNTRACK_NETLINK_H
139+
140+/* ip_conntrack_netlink.h: structures and definitions for ctnetlink.
141+ */
142+
143+/* ctnetlink message types. 
144+ */
145+#define CTM_BASE		0x10
146+#define CTM_GETCONNTRACK	(CTM_BASE + 0)
147+#define CTM_DELCONNTRACK	(CTM_BASE + 1)
148+#define CTM_NEWCONNTRACK	(CTM_BASE + 2)
149+#define CTM_MAX         	(CTM_BASE + 3)
150+
151+/* ctnetlink attribute types.
152+ */
153+enum ctattr_type_t
154+{
155+        CTA_UNSPEC,	/* [none] I don't know (unspecified). */
156+	CTA_ORIG,	/* [ip_conntrack_tuple] Original tuple. */
157+	CTA_RPLY,	/* [ip_conntrack_tuple] Reply tuple. */
158+        CTA_IIF,	/* [char] Input interface name (ie eth0). */
159+        CTA_OIF,	/* [char] Output interface name (ie eth1). */
160+	CTA_STATUS,	/* [unsigned long] Status of connection. */
161+	CTA_INFO,	/* [unsigned long] Information (ctinfo). */
162+	CTA_PROTOINFO,	/* [rta_proto] Protocol specific ct information. */
163+	CTA_HELPINFO,	/* [rta_help] Helper specific information. */
164+	CTA_NATINFO,	/* [rta_nat] Any NAT transformations. */
165+	CTA_MAX = CTA_NATINFO 
166+};
167+
168+/* Generic structure for encapsulation optional conntrack information.
169+ * It is reminiscent of sockaddr, but with sa_family replaced
170+ * with attribute type. 
171+ * ! This should someday be put somewhere generic as now rtnetlink and
172+ * ! ctnetlink use the same attributes methods. - JSchulist.
173+ */
174+
175+struct ctattr
176+{
177+        unsigned short  cta_len;
178+        unsigned short  cta_type;
179+};
180+
181+#define CTA_ALIGNTO     4
182+#define CTA_ALIGN(len)	(((len) + CTA_ALIGNTO - 1) & ~(CTA_ALIGNTO - 1))
183+#define CTA_OK(cta,len)	((len) > 0 && (cta)->cta_len >= sizeof(struct ctattr) \
184+	&& (cta)->cta_len <= (len))
185+#define CTA_NEXT(cta,attrlen)	((attrlen) -= CTA_ALIGN((cta)->cta_len), \
186+	(struct ctattr *)(((char *)(cta)) + CTA_ALIGN((cta)->cta_len)))
187+#define CTA_LENGTH(len)	(CTA_ALIGN(sizeof(struct ctattr)) + (len))
188+#define CTA_SPACE(len)	CTA_ALIGN(CTA_LENGTH(len))
189+#define CTA_DATA(cta)   ((void *)(((char *)(cta)) + CTA_LENGTH(0)))
190+#define CTA_PAYLOAD(cta) ((int)((cta)->cta_len) - CTA_LENGTH(0))
191+
192+/* Generic ctnetlink message header. 
193+ */
194+struct ctmsg {
195+	unsigned char	ctm_family;
196+	unsigned char	ctm_orig_len;
197+	unsigned char	ctm_rply_len;
198+};
199+
200+#define CTM_CTA(c)      ((struct ctattr *)(((char *)(c)) \
201+        + NLMSG_ALIGN(sizeof(struct ctmsg))))
202+#define CTM_PAYLOAD(n)  NLMSG_PAYLOAD(n, sizeof(struct ctmsg))
203+
204+/* General form of address family dependent message.
205+ */
206+struct ctgenmsg {
207+	unsigned char ctgen_family;
208+};
209+
210+/* Attribute specific data structures.
211+ */
212+
213+#ifdef CONFIG_IP_NF_NAT_NEEDED
214+struct cta_nat {
215+	unsigned int num_manips;
216+        struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS];
217+};
218+#endif /* CONFIG_IP_NF_NAT_NEEDED */
219+
220+struct cta_proto {
221+	unsigned char num_proto;	/* Protocol number IPPROTO_X */
222+	union {
223+                struct ip_ct_tcp tcp;
224+                struct ip_ct_icmp icmp;
225+        } proto;
226+};
227+
228+struct cta_help {
229+	struct ip_conntrack_tuple tuple;
230+        struct ip_conntrack_tuple mask;
231+
232+	union {
233+                struct ip_ct_ftp ct_ftp_info;
234+        } help;
235+};
236+
237+/* ctnetlink multicast groups: reports any change of ctinfo,
238+ * ctstatus, or protocol state change.
239+ */
240+#define CTGRP_IPV4_CT_TCP	0x01
241+#define CTGRP_IPV4_CT_UDP	0x02
242+#define CTGRP_IPV4_CT_ICMP	0x04
243+
244+#define CTGRP_IPV6_CT_TCP       0x10
245+#define CTGRP_IPV6_CT_UDP       0x20
246+#define CTGRP_IPV6_CT_ICMP      0x40
247+
248+#ifdef __KERNEL__
249+extern void __cta_fill(struct sk_buff *skb, int attrtype,
250+        int attrlen, const void *data);
251+#define CTA_PUT(skb, attrtype, attrlen, data) \
252+({ if (skb_tailroom(skb) < (int)CTA_SPACE(attrlen)) goto ctattr_failure; \
253+   __cta_fill(skb, attrtype, attrlen, data); })
254+#endif	/* __KERNEL__ */
255+#endif	/* _IP_CONNTRACK_NETLINK_H */
256diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_protocol.h linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
257--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Apr 27 14:15:01 2001
258+++ linux/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Fri Jun  1 06:47:50 2001
259@@ -35,7 +35,7 @@
260 	/* Returns verdict for packet, or -1 for invalid. */
261 	int (*packet)(struct ip_conntrack *conntrack,
262 		      struct iphdr *iph, size_t len,
263-		      enum ip_conntrack_info ctinfo);
264+		      enum ip_conntrack_info ctinfo, int *set_notify);
265 
266 	/* Called when a new connection for this protocol found;
267 	 * returns TRUE if it's OK.  If so, packet() called next. */
268diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_tcp.h linux/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
269--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Fri Aug  4 13:07:24 2000
270+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tcp.h	Fri Jun  1 00:31:00 2001
271@@ -2,10 +2,6 @@
272 #define _IP_CONNTRACK_TCP_H
273 /* TCP tracking. */
274 
275-#ifndef __KERNEL__
276-#error Only in kernel.
277-#endif
278-
279 enum tcp_conntrack {
280 	TCP_CONNTRACK_NONE,
281 	TCP_CONNTRACK_ESTABLISHED,
282diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
283--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Thu Aug 10 12:35:15 2000
284+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Fri Jun  1 00:31:00 2001
285@@ -62,8 +62,6 @@
286 	} dst;
287 };
288 
289-#ifdef __KERNEL__
290-
291 #define DUMP_TUPLE(tp)						\
292 DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",	\
293        (tp), (tp)->dst.protonum,				\
294@@ -114,6 +112,8 @@
295 		 || ((t->dst.protonum ^ tuple->dst.protonum)
296 		     & mask->dst.protonum));
297 }
298+
299+#ifdef __KERNEL__
300 
301 /* Connections have two entries in the hash table: one for each way */
302 struct ip_conntrack_tuple_hash
303diff -ruN linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h
304--- linux-2.4.5-ac5/include/linux/netfilter_ipv4/ip_nat.h	Wed Apr 25 15:00:28 2001
305+++ linux/include/linux/netfilter_ipv4/ip_nat.h	Fri Jun  1 06:47:50 2001
306@@ -55,22 +55,6 @@
307 	struct ip_nat_range range[1];
308 };
309 
310-#ifdef __KERNEL__
311-#include <linux/list.h>
312-#include <linux/netfilter_ipv4/lockhelp.h>
313-
314-/* Protects NAT hash tables, and NAT-private part of conntracks. */
315-DECLARE_RWLOCK_EXTERN(ip_nat_lock);
316-
317-/* Hashes for by-source and IP/protocol. */
318-struct ip_nat_hash
319-{
320-	struct list_head list;
321-
322-	/* conntrack we're embedded in: NULL if not in hash. */
323-	struct ip_conntrack *conntrack;
324-};
325-
326 /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */
327 #define IP_NAT_MAX_MANIPS (2*3)
328 
329@@ -88,6 +72,19 @@
330 	/* Manipulations to occur at each conntrack in this dirn. */
331 	struct ip_conntrack_manip manip;
332 };
333+
334+#ifdef __KERNEL__
335+#include <linux/netfilter_ipv4/lockhelp.h>
336+#include <linux/list.h>
337+
338+/* Hashes for by-source and IP/protocol. */
339+struct ip_nat_hash
340+{
341+        struct list_head list;
342+
343+        /* conntrack we're embedded in: NULL if not in hash. */
344+        struct ip_conntrack *conntrack;
345+};
346 	
347 /* The structure embedded in the conntrack structure. */
348 struct ip_nat_info
349@@ -110,6 +107,9 @@
350 
351 	struct ip_nat_seq seq[IP_CT_DIR_MAX];
352 };
353+
354+/* Protects NAT hash tables, and NAT-private part of conntracks. */
355+DECLARE_RWLOCK_EXTERN(ip_nat_lock);
356 
357 /* Set up the info structure to map into this range. */
358 extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
359diff -ruN linux-2.4.5-ac5/include/linux/netlink.h linux/include/linux/netlink.h
360--- linux-2.4.5-ac5/include/linux/netlink.h	Sun Nov 12 20:37:17 2000
361+++ linux/include/linux/netlink.h	Fri Jun  1 00:31:00 2001
362@@ -5,6 +5,7 @@
363 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
364 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
365 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
366+#define NETLINK_CONNTRACK       5       /* Netfilter connection tracking */
367 #define NETLINK_ARPD		8
368 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
369 #define NETLINK_IP6_FW		13
370diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
371--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_core.c	Fri Apr 27 14:15:01 2001
372+++ linux/net/ipv4/netfilter/ip_conntrack_core.c	Fri Jun  1 00:31:00 2001
373@@ -45,10 +45,10 @@
374 
375 DECLARE_RWLOCK(ip_conntrack_lock);
376 
377-void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
378 LIST_HEAD(expect_list);
379 LIST_HEAD(protocol_list);
380 static LIST_HEAD(helpers);
381+static LIST_HEAD(notify_list);
382 unsigned int ip_conntrack_htable_size = 0;
383 static int ip_conntrack_max = 0;
384 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
385@@ -86,7 +86,7 @@
386 	return p;
387 }
388 
389-static inline void ip_conntrack_put(struct ip_conntrack *ct)
390+inline void ip_conntrack_put(struct ip_conntrack *ct)
391 {
392 	IP_NF_ASSERT(ct);
393 	IP_NF_ASSERT(ct->infos[0].master);
394@@ -150,6 +150,55 @@
395 	return protocol->invert_tuple(inverse, orig);
396 }
397 
398+static inline void
399+ip_conntrack_destroyed(struct ip_conntrack *ct)
400+{
401+        struct list_head *i;
402+
403+        for (i = notify_list.next; i != &notify_list; i = i->next)
404+                if (((struct ip_conntrack_notify *)i)->destroyed)
405+                        ((struct ip_conntrack_notify *)i)->destroyed(ct);
406+        return;
407+}
408+
409+static inline void
410+ip_conntrack_created(struct ip_conntrack *ct,
411+        enum ip_conntrack_info info, const struct net_device *in, 
412+	const struct net_device *out)
413+{
414+        struct list_head *i;
415+
416+        for (i = notify_list.next; i != &notify_list; i = i->next)
417+                if (((struct ip_conntrack_notify *)i)->created)
418+                        ((struct ip_conntrack_notify *)i)->created(ct, 
419+				info, in, out);
420+        return;
421+}
422+
423+int
424+ip_conntrack_notify_register(struct ip_conntrack_notify *nb)
425+{
426+        MOD_INC_USE_COUNT;
427+
428+        WRITE_LOCK(&ip_conntrack_lock);
429+        list_prepend(&notify_list, nb);
430+        WRITE_UNLOCK(&ip_conntrack_lock);
431+
432+        return 0;
433+}
434+
435+int
436+ip_conntrack_notify_unregister(struct ip_conntrack_notify *nb)
437+{
438+        WRITE_LOCK(&ip_conntrack_lock);
439+        LIST_DELETE(&notify_list, nb);
440+        WRITE_UNLOCK(&ip_conntrack_lock);
441+
442+        MOD_DEC_USE_COUNT;
443+
444+        return 0;
445+}
446+
447 static void
448 clean_from_lists(struct ip_conntrack *ct)
449 {
450@@ -182,8 +231,7 @@
451 	if (ct->master.master)
452 		nf_conntrack_put(&ct->master);
453 
454-	if (ip_conntrack_destroyed)
455-		ip_conntrack_destroyed(ct);
456+	ip_conntrack_destroyed(ct);
457 	kmem_cache_free(ip_conntrack_cachep, ct);
458 	atomic_dec(&ip_conntrack_count);
459 }
460@@ -570,7 +618,7 @@
461 static inline struct ip_conntrack *
462 resolve_normal_ct(struct sk_buff *skb,
463 		  struct ip_conntrack_protocol *proto,
464-		  int *set_reply,
465+		  int *set_reply, int *set_notify,
466 		  unsigned int hooknum,
467 		  enum ip_conntrack_info *ctinfo)
468 {
469@@ -611,6 +659,7 @@
470 			DEBUGP("ip_conntrack_in: new packet for %p\n",
471 			       h->ctrack);
472 			*ctinfo = IP_CT_NEW;
473+			*set_notify = 1;
474 		}
475 		*set_reply = 0;
476 	}
477@@ -628,7 +677,7 @@
478 	struct ip_conntrack *ct;
479 	enum ip_conntrack_info ctinfo;
480 	struct ip_conntrack_protocol *proto;
481-	int set_reply;
482+	int set_reply, set_notify = 0;
483 	int ret;
484 
485@@ -668,7 +717,8 @@
486 	    && icmp_error_track(*pskb, &ctinfo, hooknum))
487 		return NF_ACCEPT;
488 
489-	if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
490+	if (!(ct = resolve_normal_ct(*pskb, proto, &set_reply, &set_notify,
491+	    hooknum,&ctinfo)))
492 		/* Not valid part of a connection */
493 		return NF_ACCEPT;
494 
495@@ -678,7 +728,8 @@
496 
497 	IP_NF_ASSERT((*pskb)->nfct);
498 
499-	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
500+	ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo,
501+	    &set_notify);
502 	if (ret == -1) {
503 		/* Invalid */
504 		nf_conntrack_put((*pskb)->nfct);
505@@ -698,7 +749,8 @@
506 	}
507 	if (set_reply)
508 		set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
509-
510+	if (set_notify)
511+		ip_conntrack_created(ct, ctinfo, in, out);
512 	return ret;
513 }
514 
515@@ -1050,6 +1102,7 @@
516 #ifdef CONFIG_SYSCTL
517 	unregister_sysctl_table(ip_conntrack_sysctl_header);
518 #endif
519+
520 	ip_ct_attach = NULL;
521 	/* This makes sure all current packets have passed through
522            netfilter framework.  Roll on, two-stage module
523diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_netlink.c linux/net/ipv4/netfilter/ip_conntrack_netlink.c
524--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_netlink.c	Wed Dec 31 16:00:00 1969
525+++ linux/net/ipv4/netfilter/ip_conntrack_netlink.c	Fri Jun  1 00:31:00 2001
526@@ -0,0 +1,523 @@
527+/* Connection tracking via netlink socket. Allows for user space
528+ * protocol helpers and general trouble making from userspace.
529+ *
530+ * Jay Schulist <jschlst@samba.org>, Copyright (c) 2001.
531+ *
532+ * Initial connection tracking via netlink development funded and 
533+ * generally made possible by Network Robots, Inc. (www.networkrobots.com)
534+ *
535+ * This software may be used and distributed according to the terms
536+ * of the GNU General Public License, incorporated herein by reference.
537+ */
538+
539+#include <linux/config.h>
540+#include <linux/module.h>
541+#include <linux/types.h>
542+#include <linux/socket.h>
543+#include <linux/kernel.h>
544+#include <linux/major.h>
545+#include <linux/sched.h>
546+#include <linux/timer.h>
547+#include <linux/string.h>
548+#include <linux/sockios.h>
549+#include <linux/net.h>
550+#include <linux/fcntl.h>
551+#include <linux/skbuff.h>
552+#include <asm/uaccess.h>
553+#include <asm/system.h>
554+#include <net/sock.h>
555+#include <linux/init.h>
556+#include <linux/netlink.h>
557+#include <linux/spinlock.h>
558+#include <linux/rtnetlink.h>
559+
560+#include <linux/netfilter_ipv4/ip_conntrack.h>
561+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
562+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
563+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
564+#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
565+
566+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
567+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
568+#include <linux/netfilter_ipv4/listhelp.h>
569+
570+char ctversion[] = "1.00";
571+int ct_debug_level = 1;
572+#define ct_debug(level, format, arg...) \
573+	if(ct_debug_level > level)  \
574+		printk(__FILE__ ": " format, ## arg)
575+
576+static struct sock *ctnl = NULL;
577+
578+void __cta_fill(struct sk_buff *skb, int attrtype, int attrlen, 
579+	const void *data)
580+{
581+        struct ctattr *cta;
582+        int size = CTA_LENGTH(attrlen);
583+
584+        cta = (struct ctattr *)skb_put(skb, CTA_ALIGN(size));
585+        cta->cta_type = attrtype;
586+        cta->cta_len  = size;
587+        memcpy(CTA_DATA(cta), data, attrlen);
588+}
589+
590+static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
591+	int event, int nowait, const struct ip_conntrack *ct, 
592+	const enum ip_conntrack_info *ctinfo, unsigned char proto,
593+	const struct net_device *in, const struct net_device *out)
594+{
595+	struct nlmsghdr *nlh;
596+	struct ctmsg *msg;
597+	unsigned long s;
598+	unsigned char *b;
599+
600+	b = skb->tail;
601+	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct ctmsg));
602+        msg = NLMSG_DATA(nlh);
603+        nlh->nlmsg_flags 	= (nowait && pid) ? NLM_F_MULTI : 0;
604+        msg->ctm_family		= AF_INET;
605+	msg->ctm_orig_len	= sizeof(struct ip_conntrack_tuple);
606+	msg->ctm_rply_len	= sizeof(struct ip_conntrack_tuple);
607+	CTA_PUT(skb, CTA_ORIG, sizeof(struct ip_conntrack_tuple), 
608+		&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
609+	CTA_PUT(skb, CTA_RPLY, sizeof(struct ip_conntrack_tuple),
610+		&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
611+	s = ct->status;
612+	CTA_PUT(skb, CTA_STATUS, sizeof(unsigned long), &s);
613+	if(in)
614+		CTA_PUT(skb, CTA_IIF, IFNAMSIZ, in->name);
615+        if(out)
616+		CTA_PUT(skb, CTA_OIF, IFNAMSIZ, out->name);
617+	if(ctinfo)
618+		CTA_PUT(skb, CTA_INFO, sizeof(unsigned long), ctinfo);
619+#ifdef CONFIG_IP_NF_NAT_NEEDED
620+	if(ct->nat.info.initialized && ct->nat.info.num_manips)
621+        {
622+                const struct ip_nat_info *nat = &ct->nat.info;
623+		struct cta_nat cn;
624+
625+		cn.num_manips = nat->num_manips;
626+		memcpy(&cn.manips, &nat->manips, (nat->num_manips 
627+			* sizeof(struct ip_nat_info_manip)));
628+		CTA_PUT(skb, CTA_NATINFO, sizeof(struct cta_nat), &cn);
629+        }
630+#endif /* CONFIG_IP_NF_NAT_NEEDED */
631+	if(ct->helper)
632+	{
633+		struct cta_help ch;
634+
635+		memcpy(&ch.tuple, &ct->helper->tuple, 
636+			sizeof(struct ip_conntrack_tuple));
637+		memcpy(&ch.mask, &ct->helper->mask,
638+			sizeof(struct ip_conntrack_tuple));
639+		memcpy(&ch.help.ct_ftp_info, &ct->help.ct_ftp_info, 
640+			sizeof(struct ip_ct_ftp));
641+		CTA_PUT(skb, CTA_HELPINFO, sizeof(struct cta_help), &ch);
642+	}
643+	if(proto == IPPROTO_TCP || proto == IPPROTO_UDP
644+		 || proto == IPPROTO_ICMP)
645+	{
646+		struct cta_proto cp;
647+
648+	        cp.num_proto = proto;
649+		if(proto == IPPROTO_TCP)
650+			memcpy(&cp.proto.tcp, &ct->proto.tcp, 
651+				sizeof(struct ip_ct_tcp));
652+		if(proto == IPPROTO_ICMP)
653+			memcpy(&cp.proto.icmp, &ct->proto.icmp,
654+				sizeof(struct ip_ct_icmp));
655+	        CTA_PUT(skb, CTA_PROTOINFO, sizeof(struct cta_proto), &cp);
656+	}
657+
658+        nlh->nlmsg_len = skb->tail - b;
659+        return (skb->len);
660+
661+nlmsg_failure:
662+ctattr_failure:
663+        skb_trim(skb, b - skb->data);
664+        return (-1);
665+}
666+
667+static inline void ctnetlink_send(struct sk_buff *skb, u32 pid, unsigned group)
668+{
669+	NETLINK_CB(skb).dst_groups = group;
670+        netlink_broadcast(ctnl, skb, pid, group, GFP_ATOMIC);
671+	return;
672+}
673+
674+inline struct sk_buff *ctnetlink_event_build_msg(const struct ip_conntrack *ct, 
675+	const enum ip_conntrack_info ctinfo, const unsigned char proto,
676+	const struct net_device *in, const struct net_device *out)
677+{
678+	struct sk_buff *skb;
679+	int err;
680+
681+        skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
682+        if(!skb)
683+                return (NULL);
684+
685+	err = ctnetlink_fill_info(skb, 0, 0, CTM_NEWCONNTRACK, 1,
686+		ct, &ctinfo, proto, in, out);
687+	if(err <= 0)
688+		goto nlmsg_failure;
689+        return (skb);
690+
691+nlmsg_failure:
692+        if(skb)
693+                kfree_skb(skb);
694+        return (NULL);
695+}
696+
697+void ctnetlink_create(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
698+	const struct net_device *in, const struct net_device *out)
699+{
700+	u16 proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
701+	struct sk_buff *skb;
702+
703+        skb = ctnetlink_event_build_msg(ct, ctinfo, proto, in, out);
704+        if(!skb)
705+                return;
706+
707+       	if (proto == IPPROTO_TCP) {
708+		ctnetlink_send(skb, 0, CTGRP_IPV4_CT_TCP);
709+               	return;
710+       	}
711+       	if (proto == IPPROTO_UDP) {
712+		ctnetlink_send(skb, 0, CTGRP_IPV4_CT_UDP);
713+               	return;
714+       	}
715+       	if (proto == IPPROTO_ICMP) {
716+		ctnetlink_send(skb, 0, CTGRP_IPV4_CT_ICMP);
717+               	return;
718+       	}
719+
720+	kfree_skb(skb);
721+	return;
722+}
723+
724+void ctnetlink_destroy(struct ip_conntrack *ct)
725+{
726+        ctnetlink_create(ct, IP_CT_DELETE, NULL, NULL);
727+}
728+
729+inline int ctnetlink_kill(const struct ip_conntrack *i, void *data)
730+{
731+	struct ip_conntrack *t = (struct ip_conntrack *)data;
732+
733+	if(!memcmp(&i->tuplehash[IP_CT_DIR_ORIGINAL], 
734+		&t->tuplehash[IP_CT_DIR_ORIGINAL], 
735+		sizeof(struct ip_conntrack_tuple_hash)))
736+	{
737+		ip_conntrack_put(t);
738+		return (1);
739+	}
740+
741+	return (0);
742+}
743+
744+int ctnetlink_delete_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh, 
745+	void *arg)
746+{
747+        struct ip_conntrack_tuple_hash *h;
748+	struct ip_conntrack_tuple *tuple;
749+	struct ctattr **cda = arg;
750+
751+	if(cda[CTA_ORIG-1])
752+		tuple = CTA_DATA(cda[CTA_ORIG-1]);
753+	else
754+	{
755+		if(cda[CTA_RPLY-1])
756+			tuple = CTA_DATA(cda[CTA_RPLY-1]);
757+		else
758+			return (-EINVAL);
759+	}
760+
761+	h = ip_conntrack_find_get(tuple, NULL);
762+        if(!h)
763+		return (-ENOENT);
764+	ip_ct_selective_cleanup(ctnetlink_kill, h->ctrack);
765+
766+	return (0);
767+}
768+
769+int ctnetlink_get_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh,
770+        void *arg)
771+{
772+        struct ip_conntrack_tuple_hash *h;
773+        struct ip_conntrack_tuple *tuple;
774+	struct ctattr **cda = arg;
775+	struct ip_conntrack *ct;
776+	struct sk_buff *skb2 = NULL;
777+        int err, proto;
778+
779+        if(cda[CTA_ORIG-1])
780+                tuple = CTA_DATA(cda[CTA_ORIG-1]);
781+        else
782+        {
783+                if(cda[CTA_RPLY-1])
784+                        tuple = CTA_DATA(cda[CTA_RPLY-1]);
785+                else
786+                        return (-EINVAL);
787+        }
788+
789+	h = ip_conntrack_find_get(tuple, NULL);
790+        if(!h)
791+                return (-ENOENT);
792+
793+        ct = h->ctrack;
794+        if(!ct)
795+                goto nlmsg_failure;
796+
797+        skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
798+        if(!skb2)
799+                return (-ENOMEM);
800+	NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
801+
802+        proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
803+        err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 
804+		CTM_NEWCONNTRACK, 1, ct, NULL, proto, NULL, NULL);
805+        if(err <= 0)
806+                goto nlmsg_failure;
807+
808+	err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
809+        if(err < 0)
810+                return (err);
811+        return (0);
812+
813+nlmsg_failure:
814+        if(skb2)
815+                kfree_skb(skb2);
816+        return (-1);
817+}
818+
819+/* Finish me: should support NLM_F_CREATE and NLM_F_REPLACE. */
820+int ctnetlink_new_conntrack(struct sk_buff *skb, struct nlmsghdr *nlh,
821+        void *arg)
822+{
823+	return (-EOPNOTSUPP);
824+}
825+
826+int ctnetlink_done(struct netlink_callback *cb)
827+{
828+        return (0);
829+}
830+
831+int ctnetlink_dump_build_msg(const struct ip_conntrack_tuple_hash *hash,
832+	struct sk_buff *skb, u32 pid, u32 seq)
833+{
834+	struct ip_conntrack *ct;
835+	int err, proto;
836+
837+	/* Only count originals */
838+        if (DIRECTION(hash))
839+                return (0);
840+
841+	ct = hash->ctrack;
842+	if(!ct)
843+		goto nlmsg_failure;
844+
845+	proto = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
846+        err = ctnetlink_fill_info(skb, pid, seq, CTM_NEWCONNTRACK, 1,
847+                ct, NULL, proto, NULL, NULL);
848+        if(err <= 0)
849+                goto nlmsg_failure;
850+        return (0);
851+
852+nlmsg_failure:
853+        if(skb)
854+                kfree_skb(skb);
855+        return (-1);
856+}
857+
858+int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
859+{
860+	int i;
861+	int idx;
862+        int s_idx = cb->args[0];
863+
864+	/* Traverse hash; send originals then reply. */
865+	READ_LOCK(&ip_conntrack_lock);	
866+        for(i = 0, idx = 0; i < ip_conntrack_htable_size; i++, idx++)
867+	{
868+		if(idx < s_idx)
869+                        continue;
870+                if(LIST_FIND(&ip_conntrack_hash[i], ctnetlink_dump_build_msg,
871+                	struct ip_conntrack_tuple_hash *, skb, 
872+			NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq))
873+			continue;
874+        }
875+        READ_UNLOCK(&ip_conntrack_lock);
876+
877+	cb->args[0] = idx;
878+	return (skb->len);
879+}
880+
881+/* Process one complete ctlink message. */
882+static inline int ctnetlink_rcv_msg(struct sk_buff *skb, 
883+	struct nlmsghdr *nlh, int *errp)
884+{
885+	struct ctattr *cta[CTA_MAX];
886+	int type, min_len, err = 0;
887+
888+	/* Only requests are handled by kernel now. */
889+        if(!(nlh->nlmsg_flags & NLM_F_REQUEST))
890+                return (0);
891+
892+	/* Unknown message: reply with EINVAL */
893+	type = nlh->nlmsg_type;
894+        if(type > CTM_MAX)
895+                goto err_inval;
896+
897+	/* All the messages must have at least 1 byte length */
898+        if(nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct ctgenmsg)))
899+                return (0);
900+
901+	if(type == CTM_GETCONNTRACK && nlh->nlmsg_flags & NLM_F_DUMP)
902+	{
903+		struct ctgenmsg *msg = NLMSG_DATA(nlh);
904+		u32 rlen;
905+
906+		if(msg->ctgen_family != AF_INET)
907+			return (-EAFNOSUPPORT);
908+
909+		if((*errp = netlink_dump_start(ctnl, skb, nlh,
910+                	ctnetlink_dump_table, ctnetlink_done)) != 0)
911+			goto err_inval;
912+                rlen = NLMSG_ALIGN(nlh->nlmsg_len);
913+                if(rlen > skb->len)
914+                        rlen = skb->len;
915+                skb_pull(skb, rlen);
916+		goto done;
917+	}
918+
919+	/* check attribute lengths. */
920+	min_len = sizeof(struct ctmsg);
921+        if(nlh->nlmsg_len < min_len)
922+                goto err_inval;
923+
924+        if(nlh->nlmsg_len > min_len)
925+	{
926+		struct ctattr *attr = CTM_CTA(NLMSG_DATA(nlh));
927+		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
928+
929+                while(CTA_OK(attr, attrlen)) 
930+		{
931+                        unsigned flavor = attr->cta_type;
932+                        if(flavor)
933+			{
934+                                if(flavor > RTA_MAX)
935+                                        goto err_inval;
936+                                cta[flavor - 1] = attr;
937+                        }
938+                        attr = CTA_NEXT(attr, attrlen);
939+                }
940+        }
941+
942+	switch(type) {
943+		case (CTM_DELCONNTRACK):
944+			err = ctnetlink_delete_conntrack(skb,nlh,(void *)&cta);
945+			break;
946+
947+		case (CTM_GETCONNTRACK):
948+			err = ctnetlink_get_conntrack(skb,nlh,(void *)&cta);
949+			break;
950+
951+		case (CTM_NEWCONNTRACK):
952+			ctnetlink_new_conntrack(skb, nlh, (void *)&cta);
953+			break;
954+
955+		default:
956+                        goto err_inval;
957+	}
958+
959+done:
960+	*errp = err;
961+        return (err);
962+
963+err_inval:
964+        *errp = -EINVAL;
965+        return (-1);
966+}
967+
968+/* Process one packet of messages. */
969+static inline int ctnetlink_rcv_skb(struct sk_buff *skb)
970+{
971+	int err;
972+        struct nlmsghdr *nlh;
973+
974+        while(skb->len >= NLMSG_SPACE(0))
975+	{
976+                u32 rlen;
977+
978+                nlh = (struct nlmsghdr *)skb->data;
979+                if(nlh->nlmsg_len < sizeof(struct nlmsghdr) 
980+			|| skb->len < nlh->nlmsg_len)
981+                        return (0);
982+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
983+                if(rlen > skb->len)
984+                        rlen = skb->len;
985+		if(ctnetlink_rcv_msg(skb, nlh, &err))
986+		{
987+			if(err == 0)
988+				return (-1);
989+			netlink_ack(skb, nlh, err);
990+		}
991+		else
992+			if(nlh->nlmsg_flags & NLM_F_ACK)
993+				netlink_ack(skb, nlh, 0);
994+		skb_pull(skb, rlen);
995+	}
996+
997+	return (0);
998+}
999+
1000+static void ctnetlink_rcv(struct sock *sk, int len)
1001+{
1002+	do {
1003+        	struct sk_buff *skb;
1004+
1005+		if(rtnl_shlock_nowait())
1006+                        return;
1007+
1008+	        while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
1009+		{
1010+	        	if(ctnetlink_rcv_skb(skb))
1011+			{
1012+	                	if(skb->len)
1013+	                        	skb_queue_head(&sk->receive_queue, skb);                                else
1014+	                                kfree_skb(skb);
1015+	                        break;
1016+	                }
1017+	                kfree_skb(skb);
1018+		}
1019+
1020+		up(&rtnl_sem);
1021+        } while (ctnl && ctnl->receive_queue.qlen);
1022+}
1023+
1024+static struct ip_conntrack_notify ctnl_notify = { { NULL, NULL },
1025+						ctnetlink_destroy,
1026+						ctnetlink_create };
1027+
1028+void __exit ctnetlink_exit(void)
1029+{
1030+	printk("CTnetlink: removing netlink socket.\n");
1031+	ip_conntrack_notify_unregister(&ctnl_notify);
1032+	sock_release(ctnl->socket);
1033+	return;
1034+}
1035+
1036+int __init ctnetlink_init(void)
1037+{
1038+	printk("CTnetlink: initializing netlink socket v%s.\n", ctversion);
1039+	ctnl = netlink_kernel_create(NETLINK_CONNTRACK, ctnetlink_rcv);
1040+        if(!ctnl)
1041+                panic("ctnetlink_init: cannot initialize ctnetlink.\n");
1042+	if(ip_conntrack_notify_register(&ctnl_notify) < 0)
1043+		panic("ctnetlink_init: cannot register notifier.\n");
1044+
1045+	return (0);
1046+}
1047+
1048+module_init(ctnetlink_init);
1049+module_exit(ctnetlink_exit);
1050diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c
1051--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Apr 27 14:15:01 2001
1052+++ linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Fri Jun  1 00:31:00 2001
1053@@ -41,7 +41,7 @@
1054 /* Returns verdict for packet, or -1 for invalid. */
1055 static int established(struct ip_conntrack *conntrack,
1056 		       struct iphdr *iph, size_t len,
1057-		       enum ip_conntrack_info conntrackinfo)
1058+		       enum ip_conntrack_info conntrackinfo, int *set_notify)
1059 {
1060 	ip_ct_refresh(conntrack, GENERIC_TIMEOUT);
1061 	return NF_ACCEPT;
1062diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
1063--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Apr 27 14:15:01 2001
1064+++ linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Fri Jun  1 00:31:00 2001
1065@@ -70,7 +70,7 @@
1066 /* Returns verdict for packet, or -1 for invalid. */
1067 static int icmp_packet(struct ip_conntrack *ct,
1068 		       struct iphdr *iph, size_t len,
1069-		       enum ip_conntrack_info ctinfo)
1070+		       enum ip_conntrack_info ctinfo, int *set_notify)
1071 {
1072 	/* Try to delete connection immediately after all replies:
1073            won't actually vanish as we still have skb, and del_timer
1074diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
1075--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Apr 27 14:15:01 2001
1076+++ linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Fri Jun  1 00:31:00 2001
1077@@ -146,7 +146,7 @@
1078 /* Returns verdict for packet, or -1 for invalid. */
1079 static int tcp_packet(struct ip_conntrack *conntrack,
1080 		      struct iphdr *iph, size_t len,
1081-		      enum ip_conntrack_info ctinfo)
1082+		      enum ip_conntrack_info ctinfo, int *set_notify)
1083 {
1084 	enum tcp_conntrack newconntrack, oldtcpstate;
1085 	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
1086@@ -174,6 +174,9 @@
1087 		return -1;
1088 	}
1089 
1090+	if (oldtcpstate != newconntrack)
1091+		*set_notify = 1;
1092+
1093 	conntrack->proto.tcp.state = newconntrack;
1094 
1095 	/* Poor man's window tracking: record SYN/ACK for handshake check */
1096@@ -196,8 +199,10 @@
1097 		if (oldtcpstate == TCP_CONNTRACK_SYN_RECV
1098 		    && CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL
1099 		    && tcph->ack && !tcph->syn
1100-		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
1101+		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack) {
1102 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
1103+			*set_notify = 1;
1104+		}
1105 
1106 		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
1107 	}
1108diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c
1109--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Apr 27 14:15:01 2001
1110+++ linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Fri Jun  1 00:31:00 2001
1111@@ -47,14 +47,17 @@
1112 /* Returns verdict for packet, and may modify conntracktype */
1113 static int udp_packet(struct ip_conntrack *conntrack,
1114 		      struct iphdr *iph, size_t len,
1115-		      enum ip_conntrack_info conntrackinfo)
1116+		      enum ip_conntrack_info conntrackinfo, int *set_notify)
1117 {
1118 	/* If we've seen traffic both ways, this is some kind of UDP
1119 	   stream.  Extend timeout. */
1120 	if (conntrack->status & IPS_SEEN_REPLY) {
1121+		unsigned long oldstatus = conntrack->status;
1122 		ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
1123 		/* Also, more likely to be important, and not a probe */
1124 		set_bit(IPS_ASSURED_BIT, &conntrack->status);
1125+		if(oldstatus != conntrack->status)
1126+			*set_notify = 1;
1127 	} else
1128 		ip_ct_refresh(conntrack, UDP_TIMEOUT);
1129 
1130diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
1131--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Apr 27 14:15:01 2001
1132+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	Fri Jun  1 00:31:00 2001
1133@@ -320,14 +320,19 @@
1134 EXPORT_SYMBOL(ip_conntrack_protocol_register);
1135 EXPORT_SYMBOL(invert_tuplepr);
1136 EXPORT_SYMBOL(ip_conntrack_alter_reply);
1137-EXPORT_SYMBOL(ip_conntrack_destroyed);
1138 EXPORT_SYMBOL(ip_conntrack_get);
1139 EXPORT_SYMBOL(ip_conntrack_module);
1140 EXPORT_SYMBOL(ip_conntrack_helper_register);
1141 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
1142+EXPORT_SYMBOL(ip_conntrack_notify_register);
1143+EXPORT_SYMBOL(ip_conntrack_notify_unregister);
1144 EXPORT_SYMBOL(ip_ct_selective_cleanup);
1145 EXPORT_SYMBOL(ip_ct_refresh);
1146 EXPORT_SYMBOL(ip_conntrack_expect_related);
1147 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
1148 EXPORT_SYMBOL(ip_ct_gather_frags);
1149 EXPORT_SYMBOL(ip_conntrack_htable_size);
1150+EXPORT_SYMBOL(ip_conntrack_hash);
1151+EXPORT_SYMBOL(ip_conntrack_lock);
1152+EXPORT_SYMBOL(ip_conntrack_put);
1153+EXPORT_SYMBOL(ip_conntrack_find_get);
1154diff -ruN linux-2.4.5-ac5/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
1155--- linux-2.4.5-ac5/net/ipv4/netfilter/ip_nat_core.c	Wed May 16 10:31:27 2001
1156+++ linux/net/ipv4/netfilter/ip_nat_core.c	Fri Jun  1 00:31:00 2001
1157@@ -856,6 +856,10 @@
1158 	return NF_ACCEPT;
1159 }
1160 
1161+static struct ip_conntrack_notify nat_notify = { { NULL, NULL },
1162+						ip_nat_cleanup_conntrack,
1163+						NULL };
1164+
1165 int __init ip_nat_init(void)
1166 {
1167 	size_t i;
1168@@ -882,9 +886,8 @@
1169 		INIT_LIST_HEAD(&byipsproto[i]);
1170 	}
1171 
1172-	
1173-	IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
1174-	ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
1175+	if (ip_conntrack_notify_register(&nat_notify) < 0)
1176+		panic("ip_nat_init: cannot register notifier.\n");
1177 
1178 	return 0;
1179 }
1180@@ -900,5 +903,5 @@
1181 void ip_nat_cleanup(void)
1182 {
1183 	ip_ct_selective_cleanup(&clean_nat, NULL);
1184-	ip_conntrack_destroyed = NULL;
1185+	ip_conntrack_notify_unregister(&nat_notify);
1186 }
1187diff -ruN linux-2.4.5-ac5/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c
1188--- linux-2.4.5-ac5/net/netlink/netlink_dev.c	Fri Feb  9 11:29:44 2001
1189+++ linux/net/netlink/netlink_dev.c	Fri Jun  1 00:31:00 2001
1190@@ -200,6 +200,7 @@
1191 	make_devfs_entries ("skip", 1);
1192 	make_devfs_entries ("USERSOCK", 2);
1193 	make_devfs_entries ("fwmonitor", 3);
1194+	make_devfs_entries ("conntrack", 5);
1195 	make_devfs_entries ("ARPD", 8);
1196 	make_devfs_entries ("ROUTE6", 11);
1197 	make_devfs_entries ("IP6_FW", 13);
1198