aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArturo Borrero <arturo.borrero.glez@gmail.com>2014-09-04 08:06:49 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-09-09 10:31:29 -0400
commitbe6b635cd674add9410efa9ac6f03e0040848b12 (patch)
treeace7d6c1ecd491aa68d3a1b3ad4b8829dd40305f
parent8dd33cc93ec92b8460ed2ad98c6db39276f6a72b (diff)
netfilter: nf_nat: generalize IPv6 masquerading support for nf_tables
Let's refactor the code so we can reach the masquerade functionality from outside the xt context (ie. nftables). The patch includes the addition of an atomic counter to the masquerade notifier: the stuff to be done by the notifier is the same for xt and nftables. Therefore, only one notification handler is needed. This factorization only involves IPv6; a similar patch exists to handle IPv4. Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--include/net/netfilter/ipv6/nf_nat_masquerade.h10
-rw-r--r--net/ipv6/netfilter/Kconfig7
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6t_MASQUERADE.c76
-rw-r--r--net/ipv6/netfilter/nf_nat_masquerade_ipv6.c120
5 files changed, 143 insertions, 71 deletions
diff --git a/include/net/netfilter/ipv6/nf_nat_masquerade.h b/include/net/netfilter/ipv6/nf_nat_masquerade.h
new file mode 100644
index 000000000000..0a13396cd390
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_nat_masquerade.h
@@ -0,0 +1,10 @@
1#ifndef _NF_NAT_MASQUERADE_IPV6_H_
2#define _NF_NAT_MASQUERADE_IPV6_H_
3
4unsigned int
5nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
6 const struct net_device *out);
7void nf_nat_masquerade_ipv6_register_notifier(void);
8void nf_nat_masquerade_ipv6_unregister_notifier(void);
9
10#endif /* _NF_NAT_MASQUERADE_IPV6_H_ */
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index ac93df16f5af..6c8cfec6836a 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -246,8 +246,15 @@ config NF_NAT_IPV6
246 246
247if NF_NAT_IPV6 247if NF_NAT_IPV6
248 248
249config NF_NAT_MASQUERADE_IPV6
250 tristate "IPv6 masquerade support"
251 help
252 This is the kernel functionality to provide NAT in the masquerade
253 flavour (automatic source address selection) for IPv6.
254
249config IP6_NF_TARGET_MASQUERADE 255config IP6_NF_TARGET_MASQUERADE
250 tristate "MASQUERADE target support" 256 tristate "MASQUERADE target support"
257 select NF_NAT_MASQUERADE_IPV6
251 help 258 help
252 Masquerading is a special case of NAT: all outgoing connections are 259 Masquerading is a special case of NAT: all outgoing connections are
253 changed to seem to come from a particular interface's address, and 260 changed to seem to come from a particular interface's address, and
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c0b263104ed2..89a0bd751f82 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
18 18
19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o 19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o
20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o 20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
21obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o
21 22
22# defrag 23# defrag
23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 24nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c
index 3e4e92d5e157..7f9f45d829d2 100644
--- a/net/ipv6/netfilter/ip6t_MASQUERADE.c
+++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c
@@ -19,33 +19,12 @@
19#include <net/netfilter/nf_nat.h> 19#include <net/netfilter/nf_nat.h>
20#include <net/addrconf.h> 20#include <net/addrconf.h>
21#include <net/ipv6.h> 21#include <net/ipv6.h>
22#include <net/netfilter/ipv6/nf_nat_masquerade.h>
22 23
23static unsigned int 24static unsigned int
24masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) 25masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
25{ 26{
26 const struct nf_nat_range *range = par->targinfo; 27 return nf_nat_masquerade_ipv6(skb, par->targinfo, par->out);
27 enum ip_conntrack_info ctinfo;
28 struct in6_addr src;
29 struct nf_conn *ct;
30 struct nf_nat_range newrange;
31
32 ct = nf_ct_get(skb, &ctinfo);
33 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
34 ctinfo == IP_CT_RELATED_REPLY));
35
36 if (ipv6_dev_get_saddr(dev_net(par->out), par->out,
37 &ipv6_hdr(skb)->daddr, 0, &src) < 0)
38 return NF_DROP;
39
40 nfct_nat(ct)->masq_index = par->out->ifindex;
41
42 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
43 newrange.min_addr.in6 = src;
44 newrange.max_addr.in6 = src;
45 newrange.min_proto = range->min_proto;
46 newrange.max_proto = range->max_proto;
47
48 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
49} 28}
50 29
51static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) 30static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
@@ -57,48 +36,6 @@ static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
57 return 0; 36 return 0;
58} 37}
59 38
60static int device_cmp(struct nf_conn *ct, void *ifindex)
61{
62 const struct nf_conn_nat *nat = nfct_nat(ct);
63
64 if (!nat)
65 return 0;
66 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
67 return 0;
68 return nat->masq_index == (int)(long)ifindex;
69}
70
71static int masq_device_event(struct notifier_block *this,
72 unsigned long event, void *ptr)
73{
74 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
75 struct net *net = dev_net(dev);
76
77 if (event == NETDEV_DOWN)
78 nf_ct_iterate_cleanup(net, device_cmp,
79 (void *)(long)dev->ifindex, 0, 0);
80
81 return NOTIFY_DONE;
82}
83
84static struct notifier_block masq_dev_notifier = {
85 .notifier_call = masq_device_event,
86};
87
88static int masq_inet_event(struct notifier_block *this,
89 unsigned long event, void *ptr)
90{
91 struct inet6_ifaddr *ifa = ptr;
92 struct netdev_notifier_info info;
93
94 netdev_notifier_info_init(&info, ifa->idev->dev);
95 return masq_device_event(this, event, &info);
96}
97
98static struct notifier_block masq_inet_notifier = {
99 .notifier_call = masq_inet_event,
100};
101
102static struct xt_target masquerade_tg6_reg __read_mostly = { 39static struct xt_target masquerade_tg6_reg __read_mostly = {
103 .name = "MASQUERADE", 40 .name = "MASQUERADE",
104 .family = NFPROTO_IPV6, 41 .family = NFPROTO_IPV6,
@@ -115,17 +52,14 @@ static int __init masquerade_tg6_init(void)
115 int err; 52 int err;
116 53
117 err = xt_register_target(&masquerade_tg6_reg); 54 err = xt_register_target(&masquerade_tg6_reg);
118 if (err == 0) { 55 if (err == 0)
119 register_netdevice_notifier(&masq_dev_notifier); 56 nf_nat_masquerade_ipv6_register_notifier();
120 register_inet6addr_notifier(&masq_inet_notifier);
121 }
122 57
123 return err; 58 return err;
124} 59}
125static void __exit masquerade_tg6_exit(void) 60static void __exit masquerade_tg6_exit(void)
126{ 61{
127 unregister_inet6addr_notifier(&masq_inet_notifier); 62 nf_nat_masquerade_ipv6_unregister_notifier();
128 unregister_netdevice_notifier(&masq_dev_notifier);
129 xt_unregister_target(&masquerade_tg6_reg); 63 xt_unregister_target(&masquerade_tg6_reg);
130} 64}
131 65
diff --git a/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c
new file mode 100644
index 000000000000..7745609665cd
--- /dev/null
+++ b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c
@@ -0,0 +1,120 @@
1/*
2 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
9 * NAT funded by Astaro.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/atomic.h>
15#include <linux/netdevice.h>
16#include <linux/ipv6.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter_ipv6.h>
19#include <net/netfilter/nf_nat.h>
20#include <net/addrconf.h>
21#include <net/ipv6.h>
22#include <net/netfilter/ipv6/nf_nat_masquerade.h>
23
24unsigned int
25nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
26 const struct net_device *out)
27{
28 enum ip_conntrack_info ctinfo;
29 struct in6_addr src;
30 struct nf_conn *ct;
31 struct nf_nat_range newrange;
32
33 ct = nf_ct_get(skb, &ctinfo);
34 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
35 ctinfo == IP_CT_RELATED_REPLY));
36
37 if (ipv6_dev_get_saddr(dev_net(out), out,
38 &ipv6_hdr(skb)->daddr, 0, &src) < 0)
39 return NF_DROP;
40
41 nfct_nat(ct)->masq_index = out->ifindex;
42
43 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
44 newrange.min_addr.in6 = src;
45 newrange.max_addr.in6 = src;
46 newrange.min_proto = range->min_proto;
47 newrange.max_proto = range->max_proto;
48
49 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
50}
51EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6);
52
53static int device_cmp(struct nf_conn *ct, void *ifindex)
54{
55 const struct nf_conn_nat *nat = nfct_nat(ct);
56
57 if (!nat)
58 return 0;
59 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
60 return 0;
61 return nat->masq_index == (int)(long)ifindex;
62}
63
64static int masq_device_event(struct notifier_block *this,
65 unsigned long event, void *ptr)
66{
67 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
68 struct net *net = dev_net(dev);
69
70 if (event == NETDEV_DOWN)
71 nf_ct_iterate_cleanup(net, device_cmp,
72 (void *)(long)dev->ifindex, 0, 0);
73
74 return NOTIFY_DONE;
75}
76
77static struct notifier_block masq_dev_notifier = {
78 .notifier_call = masq_device_event,
79};
80
81static int masq_inet_event(struct notifier_block *this,
82 unsigned long event, void *ptr)
83{
84 struct inet6_ifaddr *ifa = ptr;
85 struct netdev_notifier_info info;
86
87 netdev_notifier_info_init(&info, ifa->idev->dev);
88 return masq_device_event(this, event, &info);
89}
90
91static struct notifier_block masq_inet_notifier = {
92 .notifier_call = masq_inet_event,
93};
94
95static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
96
97void nf_nat_masquerade_ipv6_register_notifier(void)
98{
99 /* check if the notifier is already set */
100 if (atomic_inc_return(&masquerade_notifier_refcount) > 1)
101 return;
102
103 register_netdevice_notifier(&masq_dev_notifier);
104 register_inet6addr_notifier(&masq_inet_notifier);
105}
106EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier);
107
108void nf_nat_masquerade_ipv6_unregister_notifier(void)
109{
110 /* check if the notifier still has clients */
111 if (atomic_dec_return(&masquerade_notifier_refcount) > 0)
112 return;
113
114 unregister_inet6addr_notifier(&masq_inet_notifier);
115 unregister_netdevice_notifier(&masq_dev_notifier);
116}
117EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier);
118
119MODULE_LICENSE("GPL");
120MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");