aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2005-08-09 22:28:03 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:31:24 -0400
commitac3247baf8ecadf168642e3898b0212c29c79715 (patch)
treef2b1c65f34c035491d921006efcf8b2e7a707785
parentabc3bc58047efa72ee9c2e208cbeb73d261ad703 (diff)
[NETFILTER]: connection tracking event notifiers
This adds a notifier chain based event mechanism for ip_conntrack state changes. As opposed to the previous implementations in patch-o-matic, we do no longer need a field in the skb to achieve this. Thanks to the valuable input from Patrick McHardy and Rusty on the idea of a per_cpu implementation. Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h144
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_core.h17
-rw-r--r--net/ipv4/netfilter/Kconfig10
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c122
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c12
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c1
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_sctp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_udp.c3
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c10
10 files changed, 311 insertions, 14 deletions
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 4ed720f0c4cd..ae1270c97b50 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -65,6 +65,63 @@ enum ip_conntrack_status {
65 65
66 /* Both together */ 66 /* Both together */
67 IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE), 67 IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
68
69 /* Connection is dying (removed from lists), can not be unset. */
70 IPS_DYING_BIT = 9,
71 IPS_DYING = (1 << IPS_DYING_BIT),
72};
73
74/* Connection tracking event bits */
75enum ip_conntrack_events
76{
77 /* New conntrack */
78 IPCT_NEW_BIT = 0,
79 IPCT_NEW = (1 << IPCT_NEW_BIT),
80
81 /* Expected connection */
82 IPCT_RELATED_BIT = 1,
83 IPCT_RELATED = (1 << IPCT_RELATED_BIT),
84
85 /* Destroyed conntrack */
86 IPCT_DESTROY_BIT = 2,
87 IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
88
89 /* Timer has been refreshed */
90 IPCT_REFRESH_BIT = 3,
91 IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
92
93 /* Status has changed */
94 IPCT_STATUS_BIT = 4,
95 IPCT_STATUS = (1 << IPCT_STATUS_BIT),
96
97 /* Update of protocol info */
98 IPCT_PROTOINFO_BIT = 5,
99 IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
100
101 /* Volatile protocol info */
102 IPCT_PROTOINFO_VOLATILE_BIT = 6,
103 IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
104
105 /* New helper for conntrack */
106 IPCT_HELPER_BIT = 7,
107 IPCT_HELPER = (1 << IPCT_HELPER_BIT),
108
109 /* Update of helper info */
110 IPCT_HELPINFO_BIT = 8,
111 IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
112
113 /* Volatile helper info */
114 IPCT_HELPINFO_VOLATILE_BIT = 9,
115 IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
116
117 /* NAT info */
118 IPCT_NATINFO_BIT = 10,
119 IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
120};
121
122enum ip_conntrack_expect_events {
123 IPEXP_NEW_BIT = 0,
124 IPEXP_NEW = (1 << IPEXP_NEW_BIT),
68}; 125};
69 126
70#ifdef __KERNEL__ 127#ifdef __KERNEL__
@@ -280,6 +337,11 @@ static inline int is_confirmed(struct ip_conntrack *ct)
280 return test_bit(IPS_CONFIRMED_BIT, &ct->status); 337 return test_bit(IPS_CONFIRMED_BIT, &ct->status);
281} 338}
282 339
340static inline int is_dying(struct ip_conntrack *ct)
341{
342 return test_bit(IPS_DYING_BIT, &ct->status);
343}
344
283extern unsigned int ip_conntrack_htable_size; 345extern unsigned int ip_conntrack_htable_size;
284 346
285struct ip_conntrack_stat 347struct ip_conntrack_stat
@@ -303,6 +365,88 @@ struct ip_conntrack_stat
303 365
304#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++) 366#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
305 367
368#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
369#include <linux/notifier.h>
370
371struct ip_conntrack_ecache {
372 struct ip_conntrack *ct;
373 unsigned int events;
374};
375DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
376
377#define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x)
378
379extern struct notifier_block *ip_conntrack_chain;
380extern struct notifier_block *ip_conntrack_expect_chain;
381
382static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
383{
384 return notifier_chain_register(&ip_conntrack_chain, nb);
385}
386
387static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
388{
389 return notifier_chain_unregister(&ip_conntrack_chain, nb);
390}
391
392static inline int
393ip_conntrack_expect_register_notifier(struct notifier_block *nb)
394{
395 return notifier_chain_register(&ip_conntrack_expect_chain, nb);
396}
397
398static inline int
399ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
400{
401 return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
402}
403
404static inline void
405ip_conntrack_event_cache(enum ip_conntrack_events event,
406 const struct sk_buff *skb)
407{
408 struct ip_conntrack_ecache *ecache =
409 &__get_cpu_var(ip_conntrack_ecache);
410
411 if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) {
412 if (net_ratelimit()) {
413 printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n");
414 dump_stack();
415 }
416 }
417 ecache->events |= event;
418}
419
420extern void
421ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
422extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
423
424static inline void ip_conntrack_event(enum ip_conntrack_events event,
425 struct ip_conntrack *ct)
426{
427 if (is_confirmed(ct) && !is_dying(ct))
428 notifier_call_chain(&ip_conntrack_chain, event, ct);
429}
430
431static inline void
432ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
433 struct ip_conntrack_expect *exp)
434{
435 notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
436}
437#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
438static inline void ip_conntrack_event_cache(enum ip_conntrack_events event,
439 const struct sk_buff *skb) {}
440static inline void ip_conntrack_event(enum ip_conntrack_events event,
441 struct ip_conntrack *ct) {}
442static inline void ip_conntrack_deliver_cached_events_for(
443 struct ip_conntrack *ct) {}
444static inline void ip_conntrack_event_cache_init(const struct sk_buff *skb) {}
445static inline void
446ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
447 struct ip_conntrack_expect *exp) {}
448#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
449
306#ifdef CONFIG_IP_NF_NAT_NEEDED 450#ifdef CONFIG_IP_NF_NAT_NEEDED
307static inline int ip_nat_initialized(struct ip_conntrack *conntrack, 451static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
308 enum ip_nat_manip_type manip) 452 enum ip_nat_manip_type manip)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
index 694aec9b4784..46eeea1e2733 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -38,12 +38,21 @@ extern int __ip_conntrack_confirm(struct sk_buff **pskb);
38/* Confirm a connection: returns NF_DROP if packet must be dropped. */ 38/* Confirm a connection: returns NF_DROP if packet must be dropped. */
39static inline int ip_conntrack_confirm(struct sk_buff **pskb) 39static inline int ip_conntrack_confirm(struct sk_buff **pskb)
40{ 40{
41 if ((*pskb)->nfct 41 struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
42 && !is_confirmed((struct ip_conntrack *)(*pskb)->nfct)) 42 int ret = NF_ACCEPT;
43 return __ip_conntrack_confirm(pskb); 43
44 return NF_ACCEPT; 44 if (ct && !is_confirmed(ct))
45 ret = __ip_conntrack_confirm(pskb);
46 ip_conntrack_deliver_cached_events_for(ct);
47
48 return ret;
45} 49}
46 50
51#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
52struct ip_conntrack_ecache;
53extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec);
54#endif
55
47extern struct list_head *ip_conntrack_hash; 56extern struct list_head *ip_conntrack_hash;
48extern struct list_head ip_conntrack_expect_list; 57extern struct list_head ip_conntrack_expect_list;
49extern rwlock_t ip_conntrack_lock; 58extern rwlock_t ip_conntrack_lock;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 46d4cb1c06f0..ff3393eba924 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -40,6 +40,16 @@ config IP_NF_CONNTRACK_MARK
40 of packets, but this mark value is kept in the conntrack session 40 of packets, but this mark value is kept in the conntrack session
41 instead of the individual packets. 41 instead of the individual packets.
42 42
43config IP_NF_CONNTRACK_EVENTS
44 bool "Connection tracking events"
45 depends on IP_NF_CONNTRACK
46 help
47 If this option is enabled, the connection tracking code will
48 provide a notifier chain that can be used by other kernel code
49 to get notified about changes in the connection tracking state.
50
51 IF unsure, say `N'.
52
43config IP_NF_CT_PROTO_SCTP 53config IP_NF_CT_PROTO_SCTP
44 tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)' 54 tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
45 depends on IP_NF_CONNTRACK && EXPERIMENTAL 55 depends on IP_NF_CONNTRACK && EXPERIMENTAL
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 04c3414361d4..caf89deae116 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -37,6 +37,7 @@
37#include <linux/err.h> 37#include <linux/err.h>
38#include <linux/percpu.h> 38#include <linux/percpu.h>
39#include <linux/moduleparam.h> 39#include <linux/moduleparam.h>
40#include <linux/notifier.h>
40 41
41/* ip_conntrack_lock protects the main hash table, protocol/helper/expected 42/* ip_conntrack_lock protects the main hash table, protocol/helper/expected
42 registrations, conntrack timers*/ 43 registrations, conntrack timers*/
@@ -49,7 +50,7 @@
49#include <linux/netfilter_ipv4/ip_conntrack_core.h> 50#include <linux/netfilter_ipv4/ip_conntrack_core.h>
50#include <linux/netfilter_ipv4/listhelp.h> 51#include <linux/netfilter_ipv4/listhelp.h>
51 52
52#define IP_CONNTRACK_VERSION "2.1" 53#define IP_CONNTRACK_VERSION "2.2"
53 54
54#if 0 55#if 0
55#define DEBUGP printk 56#define DEBUGP printk
@@ -76,6 +77,81 @@ unsigned int ip_ct_log_invalid;
76static LIST_HEAD(unconfirmed); 77static LIST_HEAD(unconfirmed);
77static int ip_conntrack_vmalloc; 78static int ip_conntrack_vmalloc;
78 79
80#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
81struct notifier_block *ip_conntrack_chain;
82struct notifier_block *ip_conntrack_expect_chain;
83
84DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
85
86static inline void __deliver_cached_events(struct ip_conntrack_ecache *ecache)
87{
88 if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
89 notifier_call_chain(&ip_conntrack_chain, ecache->events,
90 ecache->ct);
91 ecache->events = 0;
92}
93
94void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
95{
96 __deliver_cached_events(ecache);
97}
98
99/* Deliver all cached events for a particular conntrack. This is called
100 * by code prior to async packet handling or freeing the skb */
101void
102ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct)
103{
104 struct ip_conntrack_ecache *ecache =
105 &__get_cpu_var(ip_conntrack_ecache);
106
107 if (!ct)
108 return;
109
110 if (ecache->ct == ct) {
111 DEBUGP("ecache: delivering event for %p\n", ct);
112 __deliver_cached_events(ecache);
113 } else {
114 if (net_ratelimit())
115 printk(KERN_WARNING "ecache: want to deliver for %p, "
116 "but cache has %p\n", ct, ecache->ct);
117 }
118
119 /* signalize that events have already been delivered */
120 ecache->ct = NULL;
121}
122
123/* Deliver cached events for old pending events, if current conntrack != old */
124void ip_conntrack_event_cache_init(const struct sk_buff *skb)
125{
126 struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct;
127 struct ip_conntrack_ecache *ecache =
128 &__get_cpu_var(ip_conntrack_ecache);
129
130 /* take care of delivering potentially old events */
131 if (ecache->ct != ct) {
132 enum ip_conntrack_info ctinfo;
133 /* we have to check, since at startup the cache is NULL */
134 if (likely(ecache->ct)) {
135 DEBUGP("ecache: entered for different conntrack: "
136 "ecache->ct=%p, skb->nfct=%p. delivering "
137 "events\n", ecache->ct, ct);
138 __deliver_cached_events(ecache);
139 ip_conntrack_put(ecache->ct);
140 } else {
141 DEBUGP("ecache: entered for conntrack %p, "
142 "cache was clean before\n", ct);
143 }
144
145 /* initialize for this conntrack/packet */
146 ecache->ct = ip_conntrack_get(skb, &ctinfo);
147 /* ecache->events cleared by __deliver_cached_devents() */
148 } else {
149 DEBUGP("ecache: re-entered for conntrack %p.\n", ct);
150 }
151}
152
153#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
154
79DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); 155DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
80 156
81void 157void
@@ -223,6 +299,8 @@ destroy_conntrack(struct nf_conntrack *nfct)
223 IP_NF_ASSERT(atomic_read(&nfct->use) == 0); 299 IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
224 IP_NF_ASSERT(!timer_pending(&ct->timeout)); 300 IP_NF_ASSERT(!timer_pending(&ct->timeout));
225 301
302 set_bit(IPS_DYING_BIT, &ct->status);
303
226 /* To make sure we don't get any weird locking issues here: 304 /* To make sure we don't get any weird locking issues here:
227 * destroy_conntrack() MUST NOT be called with a write lock 305 * destroy_conntrack() MUST NOT be called with a write lock
228 * to ip_conntrack_lock!!! -HW */ 306 * to ip_conntrack_lock!!! -HW */
@@ -261,6 +339,7 @@ static void death_by_timeout(unsigned long ul_conntrack)
261{ 339{
262 struct ip_conntrack *ct = (void *)ul_conntrack; 340 struct ip_conntrack *ct = (void *)ul_conntrack;
263 341
342 ip_conntrack_event(IPCT_DESTROY, ct);
264 write_lock_bh(&ip_conntrack_lock); 343 write_lock_bh(&ip_conntrack_lock);
265 /* Inside lock so preempt is disabled on module removal path. 344 /* Inside lock so preempt is disabled on module removal path.
266 * Otherwise we can get spurious warnings. */ 345 * Otherwise we can get spurious warnings. */
@@ -374,6 +453,16 @@ __ip_conntrack_confirm(struct sk_buff **pskb)
374 set_bit(IPS_CONFIRMED_BIT, &ct->status); 453 set_bit(IPS_CONFIRMED_BIT, &ct->status);
375 CONNTRACK_STAT_INC(insert); 454 CONNTRACK_STAT_INC(insert);
376 write_unlock_bh(&ip_conntrack_lock); 455 write_unlock_bh(&ip_conntrack_lock);
456 if (ct->helper)
457 ip_conntrack_event_cache(IPCT_HELPER, *pskb);
458#ifdef CONFIG_IP_NF_NAT_NEEDED
459 if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
460 test_bit(IPS_DST_NAT_DONE_BIT, &ct->status))
461 ip_conntrack_event_cache(IPCT_NATINFO, *pskb);
462#endif
463 ip_conntrack_event_cache(master_ct(ct) ?
464 IPCT_RELATED : IPCT_NEW, *pskb);
465
377 return NF_ACCEPT; 466 return NF_ACCEPT;
378 } 467 }
379 468
@@ -607,7 +696,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
607 struct ip_conntrack *ct; 696 struct ip_conntrack *ct;
608 enum ip_conntrack_info ctinfo; 697 enum ip_conntrack_info ctinfo;
609 struct ip_conntrack_protocol *proto; 698 struct ip_conntrack_protocol *proto;
610 int set_reply; 699 int set_reply = 0;
611 int ret; 700 int ret;
612 701
613 /* Previously seen (loopback or untracked)? Ignore. */ 702 /* Previously seen (loopback or untracked)? Ignore. */
@@ -666,6 +755,8 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
666 755
667 IP_NF_ASSERT((*pskb)->nfct); 756 IP_NF_ASSERT((*pskb)->nfct);
668 757
758 ip_conntrack_event_cache_init(*pskb);
759
669 ret = proto->packet(ct, *pskb, ctinfo); 760 ret = proto->packet(ct, *pskb, ctinfo);
670 if (ret < 0) { 761 if (ret < 0) {
671 /* Invalid: inverse of the return code tells 762 /* Invalid: inverse of the return code tells
@@ -676,8 +767,8 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
676 return -ret; 767 return -ret;
677 } 768 }
678 769
679 if (set_reply) 770 if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
680 set_bit(IPS_SEEN_REPLY_BIT, &ct->status); 771 ip_conntrack_event_cache(IPCT_STATUS, *pskb);
681 772
682 return ret; 773 return ret;
683} 774}
@@ -824,6 +915,7 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect)
824 evict_oldest_expect(expect->master); 915 evict_oldest_expect(expect->master);
825 916
826 ip_conntrack_expect_insert(expect); 917 ip_conntrack_expect_insert(expect);
918 ip_conntrack_expect_event(IPEXP_NEW, expect);
827 ret = 0; 919 ret = 0;
828out: 920out:
829 write_unlock_bh(&ip_conntrack_lock); 921 write_unlock_bh(&ip_conntrack_lock);
@@ -861,8 +953,10 @@ int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
861static inline int unhelp(struct ip_conntrack_tuple_hash *i, 953static inline int unhelp(struct ip_conntrack_tuple_hash *i,
862 const struct ip_conntrack_helper *me) 954 const struct ip_conntrack_helper *me)
863{ 955{
864 if (tuplehash_to_ctrack(i)->helper == me) 956 if (tuplehash_to_ctrack(i)->helper == me) {
957 ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i));
865 tuplehash_to_ctrack(i)->helper = NULL; 958 tuplehash_to_ctrack(i)->helper = NULL;
959 }
866 return 0; 960 return 0;
867} 961}
868 962
@@ -924,6 +1018,7 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct,
924 if (del_timer(&ct->timeout)) { 1018 if (del_timer(&ct->timeout)) {
925 ct->timeout.expires = jiffies + extra_jiffies; 1019 ct->timeout.expires = jiffies + extra_jiffies;
926 add_timer(&ct->timeout); 1020 add_timer(&ct->timeout);
1021 ip_conntrack_event_cache(IPCT_REFRESH, skb);
927 } 1022 }
928 ct_add_counters(ct, ctinfo, skb); 1023 ct_add_counters(ct, ctinfo, skb);
929 write_unlock_bh(&ip_conntrack_lock); 1024 write_unlock_bh(&ip_conntrack_lock);
@@ -1012,6 +1107,23 @@ ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *), void *data)
1012 1107
1013 ip_conntrack_put(ct); 1108 ip_conntrack_put(ct);
1014 } 1109 }
1110
1111#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1112 {
1113 /* we need to deliver all cached events in order to drop
1114 * the reference counts */
1115 int cpu;
1116 for_each_cpu(cpu) {
1117 struct ip_conntrack_ecache *ecache =
1118 &per_cpu(ip_conntrack_ecache, cpu);
1119 if (ecache->ct) {
1120 __ip_ct_deliver_cached_events(ecache);
1121 ip_conntrack_put(ecache->ct);
1122 ecache->ct = NULL;
1123 }
1124 }
1125 }
1126#endif
1015} 1127}
1016 1128
1017/* Fast function for those who don't want to parse /proc (and I don't 1129/* Fast function for those who don't want to parse /proc (and I don't
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 7a3b773be3f9..9658896f899a 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -262,7 +262,8 @@ static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
262} 262}
263 263
264/* We don't update if it's older than what we have. */ 264/* We don't update if it's older than what we have. */
265static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir) 265static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir,
266 struct sk_buff *skb)
266{ 267{
267 unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; 268 unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
268 269
@@ -276,10 +277,13 @@ static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir)
276 oldest = i; 277 oldest = i;
277 } 278 }
278 279
279 if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) 280 if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
280 info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; 281 info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
281 else if (oldest != NUM_SEQ_TO_REMEMBER) 282 ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
283 } else if (oldest != NUM_SEQ_TO_REMEMBER) {
282 info->seq_aft_nl[dir][oldest] = nl_seq; 284 info->seq_aft_nl[dir][oldest] = nl_seq;
285 ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
286 }
283} 287}
284 288
285static int help(struct sk_buff **pskb, 289static int help(struct sk_buff **pskb,
@@ -439,7 +443,7 @@ out_update_nl:
439 /* Now if this ends in \n, update ftp info. Seq may have been 443 /* Now if this ends in \n, update ftp info. Seq may have been
440 * adjusted by NAT code. */ 444 * adjusted by NAT code. */
441 if (ends_in_nl) 445 if (ends_in_nl)
442 update_nl_seq(seq, ct_ftp_info,dir); 446 update_nl_seq(seq, ct_ftp_info,dir, *pskb);
443 out: 447 out:
444 spin_unlock_bh(&ip_ftp_lock); 448 spin_unlock_bh(&ip_ftp_lock);
445 return ret; 449 return ret;
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 602c74db3252..dca1f63d6f51 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -102,6 +102,7 @@ static int icmp_packet(struct ip_conntrack *ct,
102 ct->timeout.function((unsigned long)ct); 102 ct->timeout.function((unsigned long)ct);
103 } else { 103 } else {
104 atomic_inc(&ct->proto.icmp.count); 104 atomic_inc(&ct->proto.icmp.count);
105 ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
105 ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout); 106 ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
106 } 107 }
107 108
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index 31d75390bf12..3d5f878a07d1 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -404,6 +404,8 @@ static int sctp_packet(struct ip_conntrack *conntrack,
404 } 404 }
405 405
406 conntrack->proto.sctp.state = newconntrack; 406 conntrack->proto.sctp.state = newconntrack;
407 if (oldsctpstate != newconntrack)
408 ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
407 write_unlock_bh(&sctp_lock); 409 write_unlock_bh(&sctp_lock);
408 } 410 }
409 411
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 809dfed766d4..a569ad1ee4d9 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -973,6 +973,10 @@ static int tcp_packet(struct ip_conntrack *conntrack,
973 ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state]; 973 ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
974 write_unlock_bh(&tcp_lock); 974 write_unlock_bh(&tcp_lock);
975 975
976 ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
977 if (new_state != old_state)
978 ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
979
976 if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { 980 if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
977 /* If only reply is a RST, we can consider ourselves not to 981 /* If only reply is a RST, we can consider ourselves not to
978 have an established connection: this is a fairly common 982 have an established connection: this is a fairly common
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 8c1eaba098d4..6066eaf4d825 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -73,7 +73,8 @@ static int udp_packet(struct ip_conntrack *conntrack,
73 ip_ct_refresh_acct(conntrack, ctinfo, skb, 73 ip_ct_refresh_acct(conntrack, ctinfo, skb,
74 ip_ct_udp_timeout_stream); 74 ip_ct_udp_timeout_stream);
75 /* Also, more likely to be important, and not a probe */ 75 /* Also, more likely to be important, and not a probe */
76 set_bit(IPS_ASSURED_BIT, &conntrack->status); 76 if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
77 ip_conntrack_event_cache(IPCT_STATUS, skb);
77 } else 78 } else
78 ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout); 79 ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
79 80
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index dccd4abab7ae..f0880004115d 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -402,6 +402,7 @@ static unsigned int ip_confirm(unsigned int hooknum,
402 const struct net_device *out, 402 const struct net_device *out,
403 int (*okfn)(struct sk_buff *)) 403 int (*okfn)(struct sk_buff *))
404{ 404{
405 ip_conntrack_event_cache_init(*pskb);
405 /* We've seen it coming out the other side: confirm it */ 406 /* We've seen it coming out the other side: confirm it */
406 return ip_conntrack_confirm(pskb); 407 return ip_conntrack_confirm(pskb);
407} 408}
@@ -419,6 +420,7 @@ static unsigned int ip_conntrack_help(unsigned int hooknum,
419 ct = ip_conntrack_get(*pskb, &ctinfo); 420 ct = ip_conntrack_get(*pskb, &ctinfo);
420 if (ct && ct->helper) { 421 if (ct && ct->helper) {
421 unsigned int ret; 422 unsigned int ret;
423 ip_conntrack_event_cache_init(*pskb);
422 ret = ct->helper->help(pskb, ct, ctinfo); 424 ret = ct->helper->help(pskb, ct, ctinfo);
423 if (ret != NF_ACCEPT) 425 if (ret != NF_ACCEPT)
424 return ret; 426 return ret;
@@ -889,6 +891,7 @@ static int init_or_cleanup(int init)
889 return ret; 891 return ret;
890 892
891 cleanup: 893 cleanup:
894 synchronize_net();
892#ifdef CONFIG_SYSCTL 895#ifdef CONFIG_SYSCTL
893 unregister_sysctl_table(ip_ct_sysctl_header); 896 unregister_sysctl_table(ip_ct_sysctl_header);
894 cleanup_localinops: 897 cleanup_localinops:
@@ -971,6 +974,13 @@ void need_ip_conntrack(void)
971{ 974{
972} 975}
973 976
977#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
978EXPORT_SYMBOL_GPL(ip_conntrack_chain);
979EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
980EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
981EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
982EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
983#endif
974EXPORT_SYMBOL(ip_conntrack_protocol_register); 984EXPORT_SYMBOL(ip_conntrack_protocol_register);
975EXPORT_SYMBOL(ip_conntrack_protocol_unregister); 985EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
976EXPORT_SYMBOL(ip_ct_get_tuple); 986EXPORT_SYMBOL(ip_ct_get_tuple);