diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 17 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_extend.h | 2 | ||||
-rw-r--r-- | include/net/netfilter/nf_nat.h | 6 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_core.c | 60 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_standalone.c | 21 |
6 files changed, 73 insertions, 36 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index f1e0fee9aa9c..b2083d386f33 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -278,22 +278,5 @@ nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size); | |||
278 | extern void | 278 | extern void |
279 | nf_conntrack_unregister_cache(u_int32_t features); | 279 | nf_conntrack_unregister_cache(u_int32_t features); |
280 | 280 | ||
281 | /* valid combinations: | ||
282 | * basic: nf_conn, nf_conn .. nf_conn_help | ||
283 | * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help | ||
284 | */ | ||
285 | #ifdef CONFIG_NF_NAT_NEEDED | ||
286 | #include <net/netfilter/nf_nat.h> | ||
287 | static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) | ||
288 | { | ||
289 | unsigned int offset = sizeof(struct nf_conn); | ||
290 | |||
291 | if (!(ct->features & NF_CT_F_NAT)) | ||
292 | return NULL; | ||
293 | |||
294 | offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); | ||
295 | return (struct nf_conn_nat *) ((void *)ct + offset); | ||
296 | } | ||
297 | #endif /* CONFIG_NF_NAT_NEEDED */ | ||
298 | #endif /* __KERNEL__ */ | 281 | #endif /* __KERNEL__ */ |
299 | #endif /* _NF_CONNTRACK_H */ | 282 | #endif /* _NF_CONNTRACK_H */ |
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h index 05357dc5d2d2..73b5711faf32 100644 --- a/include/net/netfilter/nf_conntrack_extend.h +++ b/include/net/netfilter/nf_conntrack_extend.h | |||
@@ -6,10 +6,12 @@ | |||
6 | enum nf_ct_ext_id | 6 | enum nf_ct_ext_id |
7 | { | 7 | { |
8 | NF_CT_EXT_HELPER, | 8 | NF_CT_EXT_HELPER, |
9 | NF_CT_EXT_NAT, | ||
9 | NF_CT_EXT_NUM, | 10 | NF_CT_EXT_NUM, |
10 | }; | 11 | }; |
11 | 12 | ||
12 | #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help | 13 | #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help |
14 | #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat | ||
13 | 15 | ||
14 | /* Extensions: optional stuff which isn't permanently in struct. */ | 16 | /* Extensions: optional stuff which isn't permanently in struct. */ |
15 | struct nf_ct_ext { | 17 | struct nf_ct_ext { |
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 575dc8ac48dc..0425e28c6a78 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h | |||
@@ -52,6 +52,7 @@ struct nf_nat_multi_range_compat | |||
52 | #ifdef __KERNEL__ | 52 | #ifdef __KERNEL__ |
53 | #include <linux/list.h> | 53 | #include <linux/list.h> |
54 | #include <linux/netfilter/nf_conntrack_pptp.h> | 54 | #include <linux/netfilter/nf_conntrack_pptp.h> |
55 | #include <net/netfilter/nf_conntrack_extend.h> | ||
55 | 56 | ||
56 | struct nf_conn; | 57 | struct nf_conn; |
57 | 58 | ||
@@ -89,6 +90,11 @@ extern unsigned int nf_nat_setup_info(struct nf_conn *ct, | |||
89 | extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, | 90 | extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, |
90 | const struct nf_conn *ignored_conntrack); | 91 | const struct nf_conn *ignored_conntrack); |
91 | 92 | ||
93 | static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) | ||
94 | { | ||
95 | return nf_ct_ext_find(ct, NF_CT_EXT_NAT); | ||
96 | } | ||
97 | |||
92 | extern int nf_nat_module_is_loaded; | 98 | extern int nf_nat_module_is_loaded; |
93 | 99 | ||
94 | #else /* !__KERNEL__: iptables wants this to compile. */ | 100 | #else /* !__KERNEL__: iptables wants this to compile. */ |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 6dc72a815f77..96f641d07a40 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -108,9 +108,6 @@ EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded); | |||
108 | 108 | ||
109 | static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) | 109 | static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) |
110 | { | 110 | { |
111 | if (nf_nat_module_is_loaded) | ||
112 | return NF_CT_F_NAT; | ||
113 | |||
114 | return NF_CT_F_BASIC; | 111 | return NF_CT_F_BASIC; |
115 | } | 112 | } |
116 | 113 | ||
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index ac7e8abbbdeb..4ce82d7014ff 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -297,11 +297,21 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
297 | unsigned int hooknum) | 297 | unsigned int hooknum) |
298 | { | 298 | { |
299 | struct nf_conntrack_tuple curr_tuple, new_tuple; | 299 | struct nf_conntrack_tuple curr_tuple, new_tuple; |
300 | struct nf_conn_nat *nat = nfct_nat(ct); | 300 | struct nf_conn_nat *nat; |
301 | struct nf_nat_info *info = &nat->info; | 301 | struct nf_nat_info *info; |
302 | int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); | 302 | int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); |
303 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | 303 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); |
304 | 304 | ||
305 | /* nat helper or nfctnetlink also setup binding */ | ||
306 | nat = nfct_nat(ct); | ||
307 | if (!nat) { | ||
308 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | ||
309 | if (nat == NULL) { | ||
310 | DEBUGP("failed to add NAT extension\n"); | ||
311 | return NF_ACCEPT; | ||
312 | } | ||
313 | } | ||
314 | |||
305 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || | 315 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || |
306 | hooknum == NF_IP_POST_ROUTING || | 316 | hooknum == NF_IP_POST_ROUTING || |
307 | hooknum == NF_IP_LOCAL_IN || | 317 | hooknum == NF_IP_LOCAL_IN || |
@@ -338,6 +348,8 @@ nf_nat_setup_info(struct nf_conn *ct, | |||
338 | 348 | ||
339 | srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 349 | srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
340 | write_lock_bh(&nf_nat_lock); | 350 | write_lock_bh(&nf_nat_lock); |
351 | /* nf_conntrack_alter_reply might re-allocate exntension aera */ | ||
352 | info = &nfct_nat(ct)->info; | ||
341 | info->ct = ct; | 353 | info->ct = ct; |
342 | list_add(&info->bysource, &bysource[srchash]); | 354 | list_add(&info->bysource, &bysource[srchash]); |
343 | write_unlock_bh(&nf_nat_lock); | 355 | write_unlock_bh(&nf_nat_lock); |
@@ -592,17 +604,52 @@ nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) | |||
592 | EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); | 604 | EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); |
593 | #endif | 605 | #endif |
594 | 606 | ||
607 | static void nf_nat_move_storage(struct nf_conn *conntrack, void *old) | ||
608 | { | ||
609 | struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); | ||
610 | struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; | ||
611 | struct nf_conn *ct = old_nat->info.ct; | ||
612 | unsigned int srchash; | ||
613 | |||
614 | if (!(ct->status & IPS_NAT_DONE_MASK)) | ||
615 | return; | ||
616 | |||
617 | srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
618 | |||
619 | write_lock_bh(&nf_nat_lock); | ||
620 | list_replace(&old_nat->info.bysource, &new_nat->info.bysource); | ||
621 | new_nat->info.ct = ct; | ||
622 | write_unlock_bh(&nf_nat_lock); | ||
623 | } | ||
624 | |||
625 | struct nf_ct_ext_type nat_extend = { | ||
626 | .len = sizeof(struct nf_conn_nat), | ||
627 | .align = __alignof__(struct nf_conn_nat), | ||
628 | .move = nf_nat_move_storage, | ||
629 | .id = NF_CT_EXT_NAT, | ||
630 | .flags = NF_CT_EXT_F_PREALLOC, | ||
631 | }; | ||
632 | |||
595 | static int __init nf_nat_init(void) | 633 | static int __init nf_nat_init(void) |
596 | { | 634 | { |
597 | size_t i; | 635 | size_t i; |
636 | int ret; | ||
637 | |||
638 | ret = nf_ct_extend_register(&nat_extend); | ||
639 | if (ret < 0) { | ||
640 | printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); | ||
641 | return ret; | ||
642 | } | ||
598 | 643 | ||
599 | /* Leave them the same for the moment. */ | 644 | /* Leave them the same for the moment. */ |
600 | nf_nat_htable_size = nf_conntrack_htable_size; | 645 | nf_nat_htable_size = nf_conntrack_htable_size; |
601 | 646 | ||
602 | /* One vmalloc for both hash tables */ | 647 | /* One vmalloc for both hash tables */ |
603 | bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); | 648 | bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); |
604 | if (!bysource) | 649 | if (!bysource) { |
605 | return -ENOMEM; | 650 | ret = -ENOMEM; |
651 | goto cleanup_extend; | ||
652 | } | ||
606 | 653 | ||
607 | /* Sew in builtin protocols. */ | 654 | /* Sew in builtin protocols. */ |
608 | write_lock_bh(&nf_nat_lock); | 655 | write_lock_bh(&nf_nat_lock); |
@@ -626,6 +673,10 @@ static int __init nf_nat_init(void) | |||
626 | 673 | ||
627 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); | 674 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); |
628 | return 0; | 675 | return 0; |
676 | |||
677 | cleanup_extend: | ||
678 | nf_ct_extend_unregister(&nat_extend); | ||
679 | return ret; | ||
629 | } | 680 | } |
630 | 681 | ||
631 | /* Clear NAT section of all conntracks, in case we're loaded again. */ | 682 | /* Clear NAT section of all conntracks, in case we're loaded again. */ |
@@ -647,6 +698,7 @@ static void __exit nf_nat_cleanup(void) | |||
647 | synchronize_rcu(); | 698 | synchronize_rcu(); |
648 | vfree(bysource); | 699 | vfree(bysource); |
649 | nf_ct_l3proto_put(l3proto); | 700 | nf_ct_l3proto_put(l3proto); |
701 | nf_ct_extend_unregister(&nat_extend); | ||
650 | } | 702 | } |
651 | 703 | ||
652 | MODULE_LICENSE("GPL"); | 704 | MODULE_LICENSE("GPL"); |
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 0b2f0c33f7cd..51a2708f7bf0 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <net/netfilter/nf_conntrack.h> | 20 | #include <net/netfilter/nf_conntrack.h> |
21 | #include <net/netfilter/nf_conntrack_core.h> | 21 | #include <net/netfilter/nf_conntrack_core.h> |
22 | #include <net/netfilter/nf_conntrack_extend.h> | ||
22 | #include <net/netfilter/nf_nat.h> | 23 | #include <net/netfilter/nf_nat.h> |
23 | #include <net/netfilter/nf_nat_rule.h> | 24 | #include <net/netfilter/nf_nat_rule.h> |
24 | #include <net/netfilter/nf_nat_protocol.h> | 25 | #include <net/netfilter/nf_nat_protocol.h> |
@@ -113,8 +114,13 @@ nf_nat_fn(unsigned int hooknum, | |||
113 | return NF_ACCEPT; | 114 | return NF_ACCEPT; |
114 | 115 | ||
115 | nat = nfct_nat(ct); | 116 | nat = nfct_nat(ct); |
116 | if (!nat) | 117 | if (!nat) { |
117 | return NF_ACCEPT; | 118 | nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); |
119 | if (nat == NULL) { | ||
120 | DEBUGP("failed to add NAT extension\n"); | ||
121 | return NF_ACCEPT; | ||
122 | } | ||
123 | } | ||
118 | 124 | ||
119 | switch (ctinfo) { | 125 | switch (ctinfo) { |
120 | case IP_CT_RELATED: | 126 | case IP_CT_RELATED: |
@@ -326,18 +332,10 @@ static struct nf_hook_ops nf_nat_ops[] = { | |||
326 | 332 | ||
327 | static int __init nf_nat_standalone_init(void) | 333 | static int __init nf_nat_standalone_init(void) |
328 | { | 334 | { |
329 | int size, ret = 0; | 335 | int ret = 0; |
330 | 336 | ||
331 | need_conntrack(); | 337 | need_conntrack(); |
332 | 338 | ||
333 | size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + | ||
334 | sizeof(struct nf_conn_nat); | ||
335 | ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); | ||
336 | if (ret < 0) { | ||
337 | printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); | ||
338 | return ret; | ||
339 | } | ||
340 | |||
341 | #ifdef CONFIG_XFRM | 339 | #ifdef CONFIG_XFRM |
342 | BUG_ON(ip_nat_decode_session != NULL); | 340 | BUG_ON(ip_nat_decode_session != NULL); |
343 | ip_nat_decode_session = nat_decode_session; | 341 | ip_nat_decode_session = nat_decode_session; |
@@ -362,7 +360,6 @@ static int __init nf_nat_standalone_init(void) | |||
362 | ip_nat_decode_session = NULL; | 360 | ip_nat_decode_session = NULL; |
363 | synchronize_net(); | 361 | synchronize_net(); |
364 | #endif | 362 | #endif |
365 | nf_conntrack_unregister_cache(NF_CT_F_NAT); | ||
366 | return ret; | 363 | return ret; |
367 | } | 364 | } |
368 | 365 | ||