aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_conntrack.h56
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c22
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c39
-rw-r--r--net/netfilter/nf_conntrack_core.c119
-rw-r--r--net/netfilter/nf_conntrack_ftp.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c39
-rw-r--r--net/netfilter/nf_conntrack_standalone.c1
-rw-r--r--net/netfilter/xt_helper.c8
8 files changed, 148 insertions, 138 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 6d075ca16e6e..2743c156caa0 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -67,6 +67,18 @@ do { \
67 67
68struct nf_conntrack_helper; 68struct nf_conntrack_helper;
69 69
70/* nf_conn feature for connections that have a helper */
71struct nf_conn_help {
72 /* Helper. if any */
73 struct nf_conntrack_helper *helper;
74
75 union nf_conntrack_help help;
76
77 /* Current number of expected connections */
78 unsigned int expecting;
79};
80
81
70#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 82#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
71struct nf_conn 83struct nf_conn
72{ 84{
@@ -81,6 +93,9 @@ struct nf_conn
81 /* Have we seen traffic both ways yet? (bitset) */ 93 /* Have we seen traffic both ways yet? (bitset) */
82 unsigned long status; 94 unsigned long status;
83 95
96 /* If we were expected by an expectation, this will be it */
97 struct nf_conn *master;
98
84 /* Timer function; drops refcnt when it goes off. */ 99 /* Timer function; drops refcnt when it goes off. */
85 struct timer_list timeout; 100 struct timer_list timeout;
86 101
@@ -88,38 +103,22 @@ struct nf_conn
88 /* Accounting Information (same cache line as other written members) */ 103 /* Accounting Information (same cache line as other written members) */
89 struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; 104 struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
90#endif 105#endif
91 /* If we were expected by an expectation, this will be it */
92 struct nf_conn *master;
93
94 /* Current number of expected connections */
95 unsigned int expecting;
96 106
97 /* Unique ID that identifies this conntrack*/ 107 /* Unique ID that identifies this conntrack*/
98 unsigned int id; 108 unsigned int id;
99 109
100 /* Helper. if any */
101 struct nf_conntrack_helper *helper;
102
103 /* features - nat, helper, ... used by allocating system */ 110 /* features - nat, helper, ... used by allocating system */
104 u_int32_t features; 111 u_int32_t features;
105 112
106 /* Storage reserved for other modules: */
107
108 union nf_conntrack_proto proto;
109
110#if defined(CONFIG_NF_CONNTRACK_MARK) 113#if defined(CONFIG_NF_CONNTRACK_MARK)
111 u_int32_t mark; 114 u_int32_t mark;
112#endif 115#endif
113 116
114 /* These members are dynamically allocated. */ 117 /* Storage reserved for other modules: */
115 118 union nf_conntrack_proto proto;
116 union nf_conntrack_help *help;
117 119
118 /* Layer 3 dependent members. (ex: NAT) */ 120 /* features dynamically at the end: helper, nat (both optional) */
119 union { 121 char data[0];
120 struct nf_conntrack_ipv4 *ipv4;
121 } l3proto;
122 void *data[0];
123}; 122};
124 123
125struct nf_conntrack_expect 124struct nf_conntrack_expect
@@ -373,10 +372,23 @@ nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
373#define NF_CT_F_NUM 4 372#define NF_CT_F_NUM 4
374 373
375extern int 374extern int
376nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size, 375nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size);
377 int (*init_conntrack)(struct nf_conn *, u_int32_t));
378extern void 376extern void
379nf_conntrack_unregister_cache(u_int32_t features); 377nf_conntrack_unregister_cache(u_int32_t features);
380 378
379/* valid combinations:
380 * basic: nf_conn, nf_conn .. nf_conn_help
381 * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help
382 */
383static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
384{
385 unsigned int offset = sizeof(struct nf_conn);
386
387 if (!(ct->features & NF_CT_F_HELP))
388 return NULL;
389
390 return (struct nf_conn_help *) ((void *)ct + offset);
391}
392
381#endif /* __KERNEL__ */ 393#endif /* __KERNEL__ */
382#endif /* _NF_CONNTRACK_H */ 394#endif /* _NF_CONNTRACK_H */
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 6c8624a54933..cb9c661f3f33 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -141,19 +141,21 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
141{ 141{
142 struct nf_conn *ct; 142 struct nf_conn *ct;
143 enum ip_conntrack_info ctinfo; 143 enum ip_conntrack_info ctinfo;
144 struct nf_conn_help *help;
144 145
145 /* This is where we call the helper: as the packet goes out. */ 146 /* This is where we call the helper: as the packet goes out. */
146 ct = nf_ct_get(*pskb, &ctinfo); 147 ct = nf_ct_get(*pskb, &ctinfo);
147 if (ct && ct->helper) { 148 if (!ct)
148 unsigned int ret; 149 return NF_ACCEPT;
149 ret = ct->helper->help(pskb, 150
150 (*pskb)->nh.raw - (*pskb)->data 151 help = nfct_help(ct);
151 + (*pskb)->nh.iph->ihl*4, 152 if (!help || !help->helper)
152 ct, ctinfo); 153 return NF_ACCEPT;
153 if (ret != NF_ACCEPT) 154
154 return ret; 155 return help->helper->help(pskb,
155 } 156 (*pskb)->nh.raw - (*pskb)->data
156 return NF_ACCEPT; 157 + (*pskb)->nh.iph->ihl*4,
158 ct, ctinfo);
157} 159}
158 160
159static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 161static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index ac702a29dd16..ac35f9526368 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
179 int (*okfn)(struct sk_buff *)) 179 int (*okfn)(struct sk_buff *))
180{ 180{
181 struct nf_conn *ct; 181 struct nf_conn *ct;
182 struct nf_conn_help *help;
182 enum ip_conntrack_info ctinfo; 183 enum ip_conntrack_info ctinfo;
184 unsigned int ret, protoff;
185 unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
186 - (*pskb)->data;
187 unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
188
183 189
184 /* This is where we call the helper: as the packet goes out. */ 190 /* This is where we call the helper: as the packet goes out. */
185 ct = nf_ct_get(*pskb, &ctinfo); 191 ct = nf_ct_get(*pskb, &ctinfo);
186 if (ct && ct->helper) { 192 if (!ct)
187 unsigned int ret, protoff; 193 goto out;
188 unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
189 - (*pskb)->data;
190 unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
191
192 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
193 (*pskb)->len - extoff);
194 if (protoff < 0 || protoff > (*pskb)->len ||
195 pnum == NEXTHDR_FRAGMENT) {
196 DEBUGP("proto header not found\n");
197 return NF_ACCEPT;
198 }
199 194
200 ret = ct->helper->help(pskb, protoff, ct, ctinfo); 195 help = nfct_help(ct);
201 if (ret != NF_ACCEPT) 196 if (!help || !help->helper)
202 return ret; 197 goto out;
198
199 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
200 (*pskb)->len - extoff);
201 if (protoff < 0 || protoff > (*pskb)->len ||
202 pnum == NEXTHDR_FRAGMENT) {
203 DEBUGP("proto header not found\n");
204 return NF_ACCEPT;
203 } 205 }
204 206
207 ret = help->helper->help(pskb, protoff, ct, ctinfo);
208 if (ret != NF_ACCEPT)
209 return ret;
210out:
205 /* We've seen it coming out the other side: confirm it */ 211 /* We've seen it coming out the other side: confirm it */
206
207 return nf_conntrack_confirm(pskb); 212 return nf_conntrack_confirm(pskb);
208} 213}
209 214
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index d622ddf08bb0..dc68d0022218 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -3,7 +3,7 @@
3 extension. */ 3 extension. */
4 4
5/* (C) 1999-2001 Paul `Rusty' Russell 5/* (C) 1999-2001 Paul `Rusty' Russell
6 * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> 6 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
7 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> 7 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,9 @@
20 * - generalize L3 protocol denendent part. 20 * - generalize L3 protocol denendent part.
21 * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> 21 * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
22 * - add support various size of conntrack structures. 22 * - add support various size of conntrack structures.
23 * 26 Jan 2006: Harald Welte <laforge@netfilter.org>
24 * - restructure nf_conn (introduce nf_conn_help)
25 * - redesign 'features' how they were originally intended
23 * 26 *
24 * Derived from net/ipv4/netfilter/ip_conntrack_core.c 27 * Derived from net/ipv4/netfilter/ip_conntrack_core.c
25 */ 28 */
@@ -55,7 +58,7 @@
55#include <net/netfilter/nf_conntrack_core.h> 58#include <net/netfilter/nf_conntrack_core.h>
56#include <linux/netfilter_ipv4/listhelp.h> 59#include <linux/netfilter_ipv4/listhelp.h>
57 60
58#define NF_CONNTRACK_VERSION "0.4.1" 61#define NF_CONNTRACK_VERSION "0.5.0"
59 62
60#if 0 63#if 0
61#define DEBUGP printk 64#define DEBUGP printk
@@ -259,21 +262,8 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
259 nf_conntrack_hash_rnd); 262 nf_conntrack_hash_rnd);
260} 263}
261 264
262/* Initialize "struct nf_conn" which has spaces for helper */
263static int
264init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features)
265{
266
267 conntrack->help = (union nf_conntrack_help *)
268 (((unsigned long)conntrack->data
269 + (__alignof__(union nf_conntrack_help) - 1))
270 & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1))));
271 return 0;
272}
273
274int nf_conntrack_register_cache(u_int32_t features, const char *name, 265int nf_conntrack_register_cache(u_int32_t features, const char *name,
275 size_t size, 266 size_t size)
276 int (*init)(struct nf_conn *, u_int32_t))
277{ 267{
278 int ret = 0; 268 int ret = 0;
279 char *cache_name; 269 char *cache_name;
@@ -296,8 +286,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
296 DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); 286 DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
297 if ((!strncmp(nf_ct_cache[features].name, name, 287 if ((!strncmp(nf_ct_cache[features].name, name,
298 NF_CT_FEATURES_NAMELEN)) 288 NF_CT_FEATURES_NAMELEN))
299 && nf_ct_cache[features].size == size 289 && nf_ct_cache[features].size == size) {
300 && nf_ct_cache[features].init_conntrack == init) {
301 DEBUGP("nf_conntrack_register_cache: reusing.\n"); 290 DEBUGP("nf_conntrack_register_cache: reusing.\n");
302 nf_ct_cache[features].use++; 291 nf_ct_cache[features].use++;
303 ret = 0; 292 ret = 0;
@@ -340,7 +329,6 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name,
340 write_lock_bh(&nf_ct_cache_lock); 329 write_lock_bh(&nf_ct_cache_lock);
341 nf_ct_cache[features].use = 1; 330 nf_ct_cache[features].use = 1;
342 nf_ct_cache[features].size = size; 331 nf_ct_cache[features].size = size;
343 nf_ct_cache[features].init_conntrack = init;
344 nf_ct_cache[features].cachep = cachep; 332 nf_ct_cache[features].cachep = cachep;
345 nf_ct_cache[features].name = cache_name; 333 nf_ct_cache[features].name = cache_name;
346 write_unlock_bh(&nf_ct_cache_lock); 334 write_unlock_bh(&nf_ct_cache_lock);
@@ -377,7 +365,6 @@ void nf_conntrack_unregister_cache(u_int32_t features)
377 name = nf_ct_cache[features].name; 365 name = nf_ct_cache[features].name;
378 nf_ct_cache[features].cachep = NULL; 366 nf_ct_cache[features].cachep = NULL;
379 nf_ct_cache[features].name = NULL; 367 nf_ct_cache[features].name = NULL;
380 nf_ct_cache[features].init_conntrack = NULL;
381 nf_ct_cache[features].size = 0; 368 nf_ct_cache[features].size = 0;
382 write_unlock_bh(&nf_ct_cache_lock); 369 write_unlock_bh(&nf_ct_cache_lock);
383 370
@@ -432,11 +419,15 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
432/* nf_conntrack_expect helper functions */ 419/* nf_conntrack_expect helper functions */
433void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) 420void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
434{ 421{
422 struct nf_conn_help *master_help = nfct_help(exp->master);
423
424 NF_CT_ASSERT(master_help);
435 ASSERT_WRITE_LOCK(&nf_conntrack_lock); 425 ASSERT_WRITE_LOCK(&nf_conntrack_lock);
436 NF_CT_ASSERT(!timer_pending(&exp->timeout)); 426 NF_CT_ASSERT(!timer_pending(&exp->timeout));
427
437 list_del(&exp->list); 428 list_del(&exp->list);
438 NF_CT_STAT_INC(expect_delete); 429 NF_CT_STAT_INC(expect_delete);
439 exp->master->expecting--; 430 master_help->expecting--;
440 nf_conntrack_expect_put(exp); 431 nf_conntrack_expect_put(exp);
441} 432}
442 433
@@ -508,9 +499,10 @@ find_expectation(const struct nf_conntrack_tuple *tuple)
508void nf_ct_remove_expectations(struct nf_conn *ct) 499void nf_ct_remove_expectations(struct nf_conn *ct)
509{ 500{
510 struct nf_conntrack_expect *i, *tmp; 501 struct nf_conntrack_expect *i, *tmp;
502 struct nf_conn_help *help = nfct_help(ct);
511 503
512 /* Optimization: most connection never expect any others. */ 504 /* Optimization: most connection never expect any others. */
513 if (ct->expecting == 0) 505 if (!help || help->expecting == 0)
514 return; 506 return;
515 507
516 list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { 508 list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
@@ -713,6 +705,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
713 conntrack_tuple_cmp, 705 conntrack_tuple_cmp,
714 struct nf_conntrack_tuple_hash *, 706 struct nf_conntrack_tuple_hash *,
715 &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { 707 &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
708 struct nf_conn_help *help;
716 /* Remove from unconfirmed list */ 709 /* Remove from unconfirmed list */
717 list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); 710 list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
718 711
@@ -726,7 +719,8 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
726 set_bit(IPS_CONFIRMED_BIT, &ct->status); 719 set_bit(IPS_CONFIRMED_BIT, &ct->status);
727 NF_CT_STAT_INC(insert); 720 NF_CT_STAT_INC(insert);
728 write_unlock_bh(&nf_conntrack_lock); 721 write_unlock_bh(&nf_conntrack_lock);
729 if (ct->helper) 722 help = nfct_help(ct);
723 if (help && help->helper)
730 nf_conntrack_event_cache(IPCT_HELPER, *pskb); 724 nf_conntrack_event_cache(IPCT_HELPER, *pskb);
731#ifdef CONFIG_NF_NAT_NEEDED 725#ifdef CONFIG_NF_NAT_NEEDED
732 if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || 726 if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) ||
@@ -842,8 +836,9 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
842{ 836{
843 struct nf_conn *conntrack = NULL; 837 struct nf_conn *conntrack = NULL;
844 u_int32_t features = 0; 838 u_int32_t features = 0;
839 struct nf_conntrack_helper *helper;
845 840
846 if (!nf_conntrack_hash_rnd_initted) { 841 if (unlikely(!nf_conntrack_hash_rnd_initted)) {
847 get_random_bytes(&nf_conntrack_hash_rnd, 4); 842 get_random_bytes(&nf_conntrack_hash_rnd, 4);
848 nf_conntrack_hash_rnd_initted = 1; 843 nf_conntrack_hash_rnd_initted = 1;
849 } 844 }
@@ -863,8 +858,11 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
863 858
864 /* find features needed by this conntrack. */ 859 /* find features needed by this conntrack. */
865 features = l3proto->get_features(orig); 860 features = l3proto->get_features(orig);
861
862 /* FIXME: protect helper list per RCU */
866 read_lock_bh(&nf_conntrack_lock); 863 read_lock_bh(&nf_conntrack_lock);
867 if (__nf_ct_helper_find(repl) != NULL) 864 helper = __nf_ct_helper_find(repl);
865 if (helper)
868 features |= NF_CT_F_HELP; 866 features |= NF_CT_F_HELP;
869 read_unlock_bh(&nf_conntrack_lock); 867 read_unlock_bh(&nf_conntrack_lock);
870 868
@@ -872,7 +870,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
872 870
873 read_lock_bh(&nf_ct_cache_lock); 871 read_lock_bh(&nf_ct_cache_lock);
874 872
875 if (!nf_ct_cache[features].use) { 873 if (unlikely(!nf_ct_cache[features].use)) {
876 DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", 874 DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n",
877 features); 875 features);
878 goto out; 876 goto out;
@@ -886,12 +884,10 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
886 884
887 memset(conntrack, 0, nf_ct_cache[features].size); 885 memset(conntrack, 0, nf_ct_cache[features].size);
888 conntrack->features = features; 886 conntrack->features = features;
889 if (nf_ct_cache[features].init_conntrack && 887 if (helper) {
890 nf_ct_cache[features].init_conntrack(conntrack, features) < 0) { 888 struct nf_conn_help *help = nfct_help(conntrack);
891 DEBUGP("nf_conntrack_alloc: failed to init\n"); 889 NF_CT_ASSERT(help);
892 kmem_cache_free(nf_ct_cache[features].cachep, conntrack); 890 help->helper = helper;
893 conntrack = NULL;
894 goto out;
895 } 891 }
896 892
897 atomic_set(&conntrack->ct_general.use, 1); 893 atomic_set(&conntrack->ct_general.use, 1);
@@ -972,11 +968,8 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
972#endif 968#endif
973 nf_conntrack_get(&conntrack->master->ct_general); 969 nf_conntrack_get(&conntrack->master->ct_general);
974 NF_CT_STAT_INC(expect_new); 970 NF_CT_STAT_INC(expect_new);
975 } else { 971 } else
976 conntrack->helper = __nf_ct_helper_find(&repl_tuple);
977
978 NF_CT_STAT_INC(new); 972 NF_CT_STAT_INC(new);
979 }
980 973
981 /* Overload tuple linked list to put us in unconfirmed list. */ 974 /* Overload tuple linked list to put us in unconfirmed list. */
982 list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); 975 list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
@@ -1206,14 +1199,16 @@ void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
1206 1199
1207static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) 1200static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
1208{ 1201{
1202 struct nf_conn_help *master_help = nfct_help(exp->master);
1203
1209 atomic_inc(&exp->use); 1204 atomic_inc(&exp->use);
1210 exp->master->expecting++; 1205 master_help->expecting++;
1211 list_add(&exp->list, &nf_conntrack_expect_list); 1206 list_add(&exp->list, &nf_conntrack_expect_list);
1212 1207
1213 init_timer(&exp->timeout); 1208 init_timer(&exp->timeout);
1214 exp->timeout.data = (unsigned long)exp; 1209 exp->timeout.data = (unsigned long)exp;
1215 exp->timeout.function = expectation_timed_out; 1210 exp->timeout.function = expectation_timed_out;
1216 exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; 1211 exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
1217 add_timer(&exp->timeout); 1212 add_timer(&exp->timeout);
1218 1213
1219 exp->id = ++nf_conntrack_expect_next_id; 1214 exp->id = ++nf_conntrack_expect_next_id;
@@ -1239,10 +1234,12 @@ static void evict_oldest_expect(struct nf_conn *master)
1239 1234
1240static inline int refresh_timer(struct nf_conntrack_expect *i) 1235static inline int refresh_timer(struct nf_conntrack_expect *i)
1241{ 1236{
1237 struct nf_conn_help *master_help = nfct_help(i->master);
1238
1242 if (!del_timer(&i->timeout)) 1239 if (!del_timer(&i->timeout))
1243 return 0; 1240 return 0;
1244 1241
1245 i->timeout.expires = jiffies + i->master->helper->timeout*HZ; 1242 i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
1246 add_timer(&i->timeout); 1243 add_timer(&i->timeout);
1247 return 1; 1244 return 1;
1248} 1245}
@@ -1251,8 +1248,11 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
1251{ 1248{
1252 struct nf_conntrack_expect *i; 1249 struct nf_conntrack_expect *i;
1253 struct nf_conn *master = expect->master; 1250 struct nf_conn *master = expect->master;
1251 struct nf_conn_help *master_help = nfct_help(master);
1254 int ret; 1252 int ret;
1255 1253
1254 NF_CT_ASSERT(master_help);
1255
1256 DEBUGP("nf_conntrack_expect_related %p\n", related_to); 1256 DEBUGP("nf_conntrack_expect_related %p\n", related_to);
1257 DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); 1257 DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple);
1258 DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); 1258 DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask);
@@ -1271,8 +1271,8 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
1271 } 1271 }
1272 } 1272 }
1273 /* Will be over limit? */ 1273 /* Will be over limit? */
1274 if (master->helper->max_expected && 1274 if (master_help->helper->max_expected &&
1275 master->expecting >= master->helper->max_expected) 1275 master_help->expecting >= master_help->helper->max_expected)
1276 evict_oldest_expect(master); 1276 evict_oldest_expect(master);
1277 1277
1278 nf_conntrack_expect_insert(expect); 1278 nf_conntrack_expect_insert(expect);
@@ -1283,24 +1283,6 @@ out:
1283 return ret; 1283 return ret;
1284} 1284}
1285 1285
1286/* Alter reply tuple (maybe alter helper). This is for NAT, and is
1287 implicitly racy: see __nf_conntrack_confirm */
1288void nf_conntrack_alter_reply(struct nf_conn *conntrack,
1289 const struct nf_conntrack_tuple *newreply)
1290{
1291 write_lock_bh(&nf_conntrack_lock);
1292 /* Should be unconfirmed, so not in hash table yet */
1293 NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack));
1294
1295 DEBUGP("Altering reply tuple of %p to ", conntrack);
1296 NF_CT_DUMP_TUPLE(newreply);
1297
1298 conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
1299 if (!conntrack->master && conntrack->expecting == 0)
1300 conntrack->helper = __nf_ct_helper_find(newreply);
1301 write_unlock_bh(&nf_conntrack_lock);
1302}
1303
1304int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 1286int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
1305{ 1287{
1306 int ret; 1288 int ret;
@@ -1308,9 +1290,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
1308 1290
1309 ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", 1291 ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
1310 sizeof(struct nf_conn) 1292 sizeof(struct nf_conn)
1311 + sizeof(union nf_conntrack_help) 1293 + sizeof(struct nf_conn_help)
1312 + __alignof__(union nf_conntrack_help), 1294 + __alignof__(struct nf_conn_help));
1313 init_conntrack_for_helper);
1314 if (ret < 0) { 1295 if (ret < 0) {
1315 printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); 1296 printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n");
1316 return ret; 1297 return ret;
@@ -1338,9 +1319,12 @@ __nf_conntrack_helper_find_byname(const char *name)
1338static inline int unhelp(struct nf_conntrack_tuple_hash *i, 1319static inline int unhelp(struct nf_conntrack_tuple_hash *i,
1339 const struct nf_conntrack_helper *me) 1320 const struct nf_conntrack_helper *me)
1340{ 1321{
1341 if (nf_ct_tuplehash_to_ctrack(i)->helper == me) { 1322 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
1342 nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i)); 1323 struct nf_conn_help *help = nfct_help(ct);
1343 nf_ct_tuplehash_to_ctrack(i)->helper = NULL; 1324
1325 if (help && help->helper == me) {
1326 nf_conntrack_event(IPCT_HELPER, ct);
1327 help->helper = NULL;
1344 } 1328 }
1345 return 0; 1329 return 0;
1346} 1330}
@@ -1356,7 +1340,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
1356 1340
1357 /* Get rid of expectations */ 1341 /* Get rid of expectations */
1358 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { 1342 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
1359 if (exp->master->helper == me && del_timer(&exp->timeout)) { 1343 struct nf_conn_help *help = nfct_help(exp->master);
1344 if (help->helper == me && del_timer(&exp->timeout)) {
1360 nf_ct_unlink_expect(exp); 1345 nf_ct_unlink_expect(exp);
1361 nf_conntrack_expect_put(exp); 1346 nf_conntrack_expect_put(exp);
1362 } 1347 }
@@ -1697,7 +1682,7 @@ int __init nf_conntrack_init(void)
1697 } 1682 }
1698 1683
1699 ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", 1684 ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
1700 sizeof(struct nf_conn), NULL); 1685 sizeof(struct nf_conn));
1701 if (ret < 0) { 1686 if (ret < 0) {
1702 printk(KERN_ERR "Unable to create nf_conn slab cache\n"); 1687 printk(KERN_ERR "Unable to create nf_conn slab cache\n");
1703 goto err_free_hash; 1688 goto err_free_hash;
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 6f210f399762..cd191b0d4ac7 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -440,7 +440,7 @@ static int help(struct sk_buff **pskb,
440 u32 seq; 440 u32 seq;
441 int dir = CTINFO2DIR(ctinfo); 441 int dir = CTINFO2DIR(ctinfo);
442 unsigned int matchlen, matchoff; 442 unsigned int matchlen, matchoff;
443 struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info; 443 struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
444 struct nf_conntrack_expect *exp; 444 struct nf_conntrack_expect *exp;
445 struct nf_conntrack_man cmd = {}; 445 struct nf_conntrack_man cmd = {};
446 446
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 9ff3463037e1..aef3cb41131f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2,7 +2,7 @@
2 * protocol helpers and general trouble making from userspace. 2 * protocol helpers and general trouble making from userspace.
3 * 3 *
4 * (C) 2001 by Jay Schulist <jschlst@samba.org> 4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
5 * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> 5 * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
6 * (C) 2003 by Patrick Mchardy <kaber@trash.net> 6 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
7 * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> 7 * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
8 * 8 *
@@ -44,7 +44,7 @@
44 44
45MODULE_LICENSE("GPL"); 45MODULE_LICENSE("GPL");
46 46
47static char __initdata version[] = "0.92"; 47static char __initdata version[] = "0.93";
48 48
49#if 0 49#if 0
50#define DEBUGP printk 50#define DEBUGP printk
@@ -165,15 +165,16 @@ static inline int
165ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) 165ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
166{ 166{
167 struct nfattr *nest_helper; 167 struct nfattr *nest_helper;
168 const struct nf_conn_help *help = nfct_help(ct);
168 169
169 if (!ct->helper) 170 if (!help || !help->helper)
170 return 0; 171 return 0;
171 172
172 nest_helper = NFA_NEST(skb, CTA_HELP); 173 nest_helper = NFA_NEST(skb, CTA_HELP);
173 NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); 174 NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name);
174 175
175 if (ct->helper->to_nfattr) 176 if (help->helper->to_nfattr)
176 ct->helper->to_nfattr(skb, ct); 177 help->helper->to_nfattr(skb, ct);
177 178
178 NFA_NEST_END(skb, nest_helper); 179 NFA_NEST_END(skb, nest_helper);
179 180
@@ -903,11 +904,17 @@ static inline int
903ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) 904ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
904{ 905{
905 struct nf_conntrack_helper *helper; 906 struct nf_conntrack_helper *helper;
907 struct nf_conn_help *help = nfct_help(ct);
906 char *helpname; 908 char *helpname;
907 int err; 909 int err;
908 910
909 DEBUGP("entered %s\n", __FUNCTION__); 911 DEBUGP("entered %s\n", __FUNCTION__);
910 912
913 if (!help) {
914 /* FIXME: we need to reallocate and rehash */
915 return -EBUSY;
916 }
917
911 /* don't change helper of sibling connections */ 918 /* don't change helper of sibling connections */
912 if (ct->master) 919 if (ct->master)
913 return -EINVAL; 920 return -EINVAL;
@@ -924,18 +931,18 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
924 return -EINVAL; 931 return -EINVAL;
925 } 932 }
926 933
927 if (ct->helper) { 934 if (help->helper) {
928 if (!helper) { 935 if (!helper) {
929 /* we had a helper before ... */ 936 /* we had a helper before ... */
930 nf_ct_remove_expectations(ct); 937 nf_ct_remove_expectations(ct);
931 ct->helper = NULL; 938 help->helper = NULL;
932 } else { 939 } else {
933 /* need to zero data of old helper */ 940 /* need to zero data of old helper */
934 memset(&ct->help, 0, sizeof(ct->help)); 941 memset(&help->help, 0, sizeof(help->help));
935 } 942 }
936 } 943 }
937 944
938 ct->helper = helper; 945 help->helper = helper;
939 946
940 return 0; 947 return 0;
941} 948}
@@ -1050,14 +1057,9 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
1050 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); 1057 ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
1051#endif 1058#endif
1052 1059
1053 ct->helper = nf_ct_helper_find_get(rtuple);
1054
1055 add_timer(&ct->timeout); 1060 add_timer(&ct->timeout);
1056 nf_conntrack_hash_insert(ct); 1061 nf_conntrack_hash_insert(ct);
1057 1062
1058 if (ct->helper)
1059 nf_ct_helper_put(ct->helper);
1060
1061 DEBUGP("conntrack with id %u inserted\n", ct->id); 1063 DEBUGP("conntrack with id %u inserted\n", ct->id);
1062 return 0; 1064 return 0;
1063 1065
@@ -1417,7 +1419,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
1417 } 1419 }
1418 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, 1420 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
1419 list) { 1421 list) {
1420 if (exp->master->helper == h 1422 struct nf_conn_help *m_help = nfct_help(exp->master);
1423 if (m_help->helper == h
1421 && del_timer(&exp->timeout)) { 1424 && del_timer(&exp->timeout)) {
1422 nf_ct_unlink_expect(exp); 1425 nf_ct_unlink_expect(exp);
1423 nf_conntrack_expect_put(exp); 1426 nf_conntrack_expect_put(exp);
@@ -1452,6 +1455,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
1452 struct nf_conntrack_tuple_hash *h = NULL; 1455 struct nf_conntrack_tuple_hash *h = NULL;
1453 struct nf_conntrack_expect *exp; 1456 struct nf_conntrack_expect *exp;
1454 struct nf_conn *ct; 1457 struct nf_conn *ct;
1458 struct nf_conn_help *help;
1455 int err = 0; 1459 int err = 0;
1456 1460
1457 DEBUGP("entered %s\n", __FUNCTION__); 1461 DEBUGP("entered %s\n", __FUNCTION__);
@@ -1472,8 +1476,9 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
1472 if (!h) 1476 if (!h)
1473 return -ENOENT; 1477 return -ENOENT;
1474 ct = nf_ct_tuplehash_to_ctrack(h); 1478 ct = nf_ct_tuplehash_to_ctrack(h);
1479 help = nfct_help(ct);
1475 1480
1476 if (!ct->helper) { 1481 if (!help || !help->helper) {
1477 /* such conntrack hasn't got any helper, abort */ 1482 /* such conntrack hasn't got any helper, abort */
1478 err = -EINVAL; 1483 err = -EINVAL;
1479 goto out; 1484 goto out;
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 617599aeeead..290d5a0c559b 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -839,7 +839,6 @@ EXPORT_SYMBOL(nf_conntrack_l3proto_unregister);
839EXPORT_SYMBOL(nf_conntrack_protocol_register); 839EXPORT_SYMBOL(nf_conntrack_protocol_register);
840EXPORT_SYMBOL(nf_conntrack_protocol_unregister); 840EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
841EXPORT_SYMBOL(nf_ct_invert_tuplepr); 841EXPORT_SYMBOL(nf_ct_invert_tuplepr);
842EXPORT_SYMBOL(nf_conntrack_alter_reply);
843EXPORT_SYMBOL(nf_conntrack_destroyed); 842EXPORT_SYMBOL(nf_conntrack_destroyed);
844EXPORT_SYMBOL(need_conntrack); 843EXPORT_SYMBOL(need_conntrack);
845EXPORT_SYMBOL(nf_conntrack_helper_register); 844EXPORT_SYMBOL(nf_conntrack_helper_register);
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 38b6715e1db4..0ddb32363d06 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -96,6 +96,7 @@ match(const struct sk_buff *skb,
96{ 96{
97 const struct xt_helper_info *info = matchinfo; 97 const struct xt_helper_info *info = matchinfo;
98 struct nf_conn *ct; 98 struct nf_conn *ct;
99 struct nf_conn_help *master_help;
99 enum ip_conntrack_info ctinfo; 100 enum ip_conntrack_info ctinfo;
100 int ret = info->invert; 101 int ret = info->invert;
101 102
@@ -111,7 +112,8 @@ match(const struct sk_buff *skb,
111 } 112 }
112 113
113 read_lock_bh(&nf_conntrack_lock); 114 read_lock_bh(&nf_conntrack_lock);
114 if (!ct->master->helper) { 115 master_help = nfct_help(ct->master);
116 if (!master_help || !master_help->helper) {
115 DEBUGP("xt_helper: master ct %p has no helper\n", 117 DEBUGP("xt_helper: master ct %p has no helper\n",
116 exp->expectant); 118 exp->expectant);
117 goto out_unlock; 119 goto out_unlock;
@@ -123,8 +125,8 @@ match(const struct sk_buff *skb,
123 if (info->name[0] == '\0') 125 if (info->name[0] == '\0')
124 ret ^= 1; 126 ret ^= 1;
125 else 127 else
126 ret ^= !strncmp(ct->master->helper->name, info->name, 128 ret ^= !strncmp(master_help->helper->name, info->name,
127 strlen(ct->master->helper->name)); 129 strlen(master_help->helper->name));
128out_unlock: 130out_unlock:
129 read_unlock_bh(&nf_conntrack_lock); 131 read_unlock_bh(&nf_conntrack_lock);
130 return ret; 132 return ret;