aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-04-14 05:15:52 -0400
committerPatrick McHardy <kaber@trash.net>2008-04-14 05:15:52 -0400
commitdd13b010368f85dfa59364ba87bfe8ae930b2832 (patch)
treef7f0a8fa77858674564aeb614499f40dd3c6dcd8 /net/ipv4
parent55871d04793d9c069ee277b1e98794b88d92ed80 (diff)
[NETFILTER]: nf_nat: kill helper and seq_adjust hooks
Connection tracking helpers (specifically FTP) need to be called before NAT sequence numbers adjustments are performed to be able to compare them against previously seen ones. We've introduced two new hooks around 2.6.11 to maintain this ordering when NAT modules were changed to get called from conntrack helpers directly. The cost of netfilter hooks is quite high and sequence number adjustments are only rarely needed however. Add a RCU-protected sequence number adjustment function pointer and call it from IPv4 conntrack after calling the helper. Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c56
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c1
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c35
4 files changed, 32 insertions, 65 deletions
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index a65b845c5f15..41e79613eb0a 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -23,6 +23,12 @@
23#include <net/netfilter/nf_conntrack_l3proto.h> 23#include <net/netfilter/nf_conntrack_l3proto.h>
24#include <net/netfilter/nf_conntrack_core.h> 24#include <net/netfilter/nf_conntrack_core.h>
25#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 25#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
26#include <net/netfilter/nf_nat_helper.h>
27
28int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
29 struct nf_conn *ct,
30 enum ip_conntrack_info ctinfo);
31EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
26 32
27static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, 33static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
28 struct nf_conntrack_tuple *tuple) 34 struct nf_conntrack_tuple *tuple)
@@ -101,35 +107,41 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
101 const struct net_device *out, 107 const struct net_device *out,
102 int (*okfn)(struct sk_buff *)) 108 int (*okfn)(struct sk_buff *))
103{ 109{
104 /* We've seen it coming out the other side: confirm it */
105 return nf_conntrack_confirm(skb);
106}
107
108static unsigned int ipv4_conntrack_help(unsigned int hooknum,
109 struct sk_buff *skb,
110 const struct net_device *in,
111 const struct net_device *out,
112 int (*okfn)(struct sk_buff *))
113{
114 struct nf_conn *ct; 110 struct nf_conn *ct;
115 enum ip_conntrack_info ctinfo; 111 enum ip_conntrack_info ctinfo;
116 const struct nf_conn_help *help; 112 const struct nf_conn_help *help;
117 const struct nf_conntrack_helper *helper; 113 const struct nf_conntrack_helper *helper;
114 unsigned int ret;
118 115
119 /* This is where we call the helper: as the packet goes out. */ 116 /* This is where we call the helper: as the packet goes out. */
120 ct = nf_ct_get(skb, &ctinfo); 117 ct = nf_ct_get(skb, &ctinfo);
121 if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) 118 if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
122 return NF_ACCEPT; 119 goto out;
123 120
124 help = nfct_help(ct); 121 help = nfct_help(ct);
125 if (!help) 122 if (!help)
126 return NF_ACCEPT; 123 goto out;
124
127 /* rcu_read_lock()ed by nf_hook_slow */ 125 /* rcu_read_lock()ed by nf_hook_slow */
128 helper = rcu_dereference(help->helper); 126 helper = rcu_dereference(help->helper);
129 if (!helper) 127 if (!helper)
130 return NF_ACCEPT; 128 goto out;
131 return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), 129
132 ct, ctinfo); 130 ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
131 ct, ctinfo);
132 if (ret != NF_ACCEPT)
133 return ret;
134
135 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
136 typeof(nf_nat_seq_adjust_hook) seq_adjust;
137
138 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
139 if (!seq_adjust || !seq_adjust(skb, ct, ctinfo))
140 return NF_DROP;
141 }
142out:
143 /* We've seen it coming out the other side: confirm it */
144 return nf_conntrack_confirm(skb);
133} 145}
134 146
135static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, 147static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
@@ -211,20 +223,6 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
211 .priority = NF_IP_PRI_CONNTRACK, 223 .priority = NF_IP_PRI_CONNTRACK,
212 }, 224 },
213 { 225 {
214 .hook = ipv4_conntrack_help,
215 .owner = THIS_MODULE,
216 .pf = PF_INET,
217 .hooknum = NF_INET_POST_ROUTING,
218 .priority = NF_IP_PRI_CONNTRACK_HELPER,
219 },
220 {
221 .hook = ipv4_conntrack_help,
222 .owner = THIS_MODULE,
223 .pf = PF_INET,
224 .hooknum = NF_INET_LOCAL_IN,
225 .priority = NF_IP_PRI_CONNTRACK_HELPER,
226 },
227 {
228 .hook = ipv4_confirm, 226 .hook = ipv4_confirm,
229 .owner = THIS_MODULE, 227 .owner = THIS_MODULE,
230 .pf = PF_INET, 228 .pf = PF_INET,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 9320c7ac5729..25c3efe4207e 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -618,6 +618,9 @@ static int __init nf_nat_init(void)
618 nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; 618 nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
619 619
620 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); 620 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
621
622 BUG_ON(nf_nat_seq_adjust_hook != NULL);
623 rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
621 return 0; 624 return 0;
622 625
623 cleanup_extend: 626 cleanup_extend:
@@ -644,6 +647,8 @@ static void __exit nf_nat_cleanup(void)
644 nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); 647 nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);
645 nf_ct_l3proto_put(l3proto); 648 nf_ct_l3proto_put(l3proto);
646 nf_ct_extend_unregister(&nat_extend); 649 nf_ct_extend_unregister(&nat_extend);
650 rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
651 synchronize_net();
647} 652}
648 653
649MODULE_LICENSE("GPL"); 654MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 2fca727aa8ba..11976ea29884 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -416,7 +416,6 @@ nf_nat_seq_adjust(struct sk_buff *skb,
416 416
417 return 1; 417 return 1;
418} 418}
419EXPORT_SYMBOL(nf_nat_seq_adjust);
420 419
421/* Setup NAT on this expected conntrack so it follows master. */ 420/* Setup NAT on this expected conntrack so it follows master. */
422/* If we fail to get a free NAT slot, we'll get dropped on confirm */ 421/* If we fail to get a free NAT slot, we'll get dropped on confirm */
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index a366b5865b9c..b7dd695691a0 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -245,25 +245,6 @@ nf_nat_local_fn(unsigned int hooknum,
245 return ret; 245 return ret;
246} 246}
247 247
248static unsigned int
249nf_nat_adjust(unsigned int hooknum,
250 struct sk_buff *skb,
251 const struct net_device *in,
252 const struct net_device *out,
253 int (*okfn)(struct sk_buff *))
254{
255 struct nf_conn *ct;
256 enum ip_conntrack_info ctinfo;
257
258 ct = nf_ct_get(skb, &ctinfo);
259 if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
260 pr_debug("nf_nat_standalone: adjusting sequence number\n");
261 if (!nf_nat_seq_adjust(skb, ct, ctinfo))
262 return NF_DROP;
263 }
264 return NF_ACCEPT;
265}
266
267/* We must be after connection tracking and before packet filtering. */ 248/* We must be after connection tracking and before packet filtering. */
268 249
269static struct nf_hook_ops nf_nat_ops[] __read_mostly = { 250static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
@@ -283,14 +264,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
283 .hooknum = NF_INET_POST_ROUTING, 264 .hooknum = NF_INET_POST_ROUTING,
284 .priority = NF_IP_PRI_NAT_SRC, 265 .priority = NF_IP_PRI_NAT_SRC,
285 }, 266 },
286 /* After conntrack, adjust sequence number */
287 {
288 .hook = nf_nat_adjust,
289 .owner = THIS_MODULE,
290 .pf = PF_INET,
291 .hooknum = NF_INET_POST_ROUTING,
292 .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
293 },
294 /* Before packet filtering, change destination */ 267 /* Before packet filtering, change destination */
295 { 268 {
296 .hook = nf_nat_local_fn, 269 .hook = nf_nat_local_fn,
@@ -307,14 +280,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
307 .hooknum = NF_INET_LOCAL_IN, 280 .hooknum = NF_INET_LOCAL_IN,
308 .priority = NF_IP_PRI_NAT_SRC, 281 .priority = NF_IP_PRI_NAT_SRC,
309 }, 282 },
310 /* After conntrack, adjust sequence number */
311 {
312 .hook = nf_nat_adjust,
313 .owner = THIS_MODULE,
314 .pf = PF_INET,
315 .hooknum = NF_INET_LOCAL_IN,
316 .priority = NF_IP_PRI_NAT_SEQ_ADJUST,
317 },
318}; 283};
319 284
320static int __init nf_nat_standalone_init(void) 285static int __init nf_nat_standalone_init(void)