aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArturo Borrero <arturo.borrero.glez@gmail.com>2014-09-04 08:06:33 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2014-09-09 10:31:29 -0400
commit8dd33cc93ec92b8460ed2ad98c6db39276f6a72b (patch)
treefd0e78d1cd7a224aed7e35238525d1ad92af8bd2
parentc55fbbb4a730e3d6e1727b7de08b39e6cd847fad (diff)
netfilter: nf_nat: generalize IPv4 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 IPv4; a similar patch follows to handle IPv6. 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/ipv4/nf_nat_masquerade.h14
-rw-r--r--net/ipv4/netfilter/Kconfig7
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c108
-rw-r--r--net/ipv4/netfilter/nf_nat_masquerade_ipv4.c153
5 files changed, 184 insertions, 99 deletions
diff --git a/include/net/netfilter/ipv4/nf_nat_masquerade.h b/include/net/netfilter/ipv4/nf_nat_masquerade.h
new file mode 100644
index 000000000000..a9c001c646da
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_nat_masquerade.h
@@ -0,0 +1,14 @@
1#ifndef _NF_NAT_MASQUERADE_IPV4_H_
2#define _NF_NAT_MASQUERADE_IPV4_H_
3
4#include <net/netfilter/nf_nat.h>
5
6unsigned int
7nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
8 const struct nf_nat_range *range,
9 const struct net_device *out);
10
11void nf_nat_masquerade_ipv4_register_notifier(void);
12void nf_nat_masquerade_ipv4_unregister_notifier(void);
13
14#endif /*_NF_NAT_MASQUERADE_IPV4_H_ */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index fb173126f03d..4be3e541350e 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -184,8 +184,15 @@ config NF_NAT_IPV4
184 184
185if NF_NAT_IPV4 185if NF_NAT_IPV4
186 186
187config NF_NAT_MASQUERADE_IPV4
188 tristate "IPv4 masquerade support"
189 help
190 This is the kernel functionality to provide NAT in the masquerade
191 flavour (automatic source address selection).
192
187config IP_NF_TARGET_MASQUERADE 193config IP_NF_TARGET_MASQUERADE
188 tristate "MASQUERADE target support" 194 tristate "MASQUERADE target support"
195 select NF_NAT_MASQUERADE_IPV4
189 default m if NETFILTER_ADVANCED=n 196 default m if NETFILTER_ADVANCED=n
190 help 197 help
191 Masquerading is a special case of NAT: all outgoing connections are 198 Masquerading is a special case of NAT: all outgoing connections are
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 33001621465b..42056b2fd0e3 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o
27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
28obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 28obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
29obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 29obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
30obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o
30 31
31# NAT protocols (nf_nat) 32# NAT protocols (nf_nat)
32obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 33obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 00352ce0f0de..da7f02a0b868 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -22,6 +22,7 @@
22#include <linux/netfilter_ipv4.h> 22#include <linux/netfilter_ipv4.h>
23#include <linux/netfilter/x_tables.h> 23#include <linux/netfilter/x_tables.h>
24#include <net/netfilter/nf_nat.h> 24#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/ipv4/nf_nat_masquerade.h>
25 26
26MODULE_LICENSE("GPL"); 27MODULE_LICENSE("GPL");
27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 28MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -46,103 +47,17 @@ static int masquerade_tg_check(const struct xt_tgchk_param *par)
46static unsigned int 47static unsigned int
47masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par) 48masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
48{ 49{
49 struct nf_conn *ct; 50 struct nf_nat_range range;
50 struct nf_conn_nat *nat;
51 enum ip_conntrack_info ctinfo;
52 struct nf_nat_range newrange;
53 const struct nf_nat_ipv4_multi_range_compat *mr; 51 const struct nf_nat_ipv4_multi_range_compat *mr;
54 const struct rtable *rt;
55 __be32 newsrc, nh;
56
57 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
58
59 ct = nf_ct_get(skb, &ctinfo);
60 nat = nfct_nat(ct);
61
62 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
63 ctinfo == IP_CT_RELATED_REPLY));
64
65 /* Source address is 0.0.0.0 - locally generated packet that is
66 * probably not supposed to be masqueraded.
67 */
68 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
69 return NF_ACCEPT;
70 52
71 mr = par->targinfo; 53 mr = par->targinfo;
72 rt = skb_rtable(skb); 54 range.flags = mr->range[0].flags;
73 nh = rt_nexthop(rt, ip_hdr(skb)->daddr); 55 range.min_proto = mr->range[0].min;
74 newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE); 56 range.max_proto = mr->range[0].max;
75 if (!newsrc) {
76 pr_info("%s ate my IP address\n", par->out->name);
77 return NF_DROP;
78 }
79
80 nat->masq_index = par->out->ifindex;
81
82 /* Transfer from original range. */
83 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
84 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
85 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
86 newrange.min_addr.ip = newsrc;
87 newrange.max_addr.ip = newsrc;
88 newrange.min_proto = mr->range[0].min;
89 newrange.max_proto = mr->range[0].max;
90 57
91 /* Hand modified range to generic setup. */ 58 return nf_nat_masquerade_ipv4(skb, par->hooknum, &range, par->out);
92 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
93} 59}
94 60
95static int
96device_cmp(struct nf_conn *i, void *ifindex)
97{
98 const struct nf_conn_nat *nat = nfct_nat(i);
99
100 if (!nat)
101 return 0;
102 if (nf_ct_l3num(i) != NFPROTO_IPV4)
103 return 0;
104 return nat->masq_index == (int)(long)ifindex;
105}
106
107static int masq_device_event(struct notifier_block *this,
108 unsigned long event,
109 void *ptr)
110{
111 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
112 struct net *net = dev_net(dev);
113
114 if (event == NETDEV_DOWN) {
115 /* Device was downed. Search entire table for
116 conntracks which were associated with that device,
117 and forget them. */
118 NF_CT_ASSERT(dev->ifindex != 0);
119
120 nf_ct_iterate_cleanup(net, device_cmp,
121 (void *)(long)dev->ifindex, 0, 0);
122 }
123
124 return NOTIFY_DONE;
125}
126
127static int masq_inet_event(struct notifier_block *this,
128 unsigned long event,
129 void *ptr)
130{
131 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
132 struct netdev_notifier_info info;
133
134 netdev_notifier_info_init(&info, dev);
135 return masq_device_event(this, event, &info);
136}
137
138static struct notifier_block masq_dev_notifier = {
139 .notifier_call = masq_device_event,
140};
141
142static struct notifier_block masq_inet_notifier = {
143 .notifier_call = masq_inet_event,
144};
145
146static struct xt_target masquerade_tg_reg __read_mostly = { 61static struct xt_target masquerade_tg_reg __read_mostly = {
147 .name = "MASQUERADE", 62 .name = "MASQUERADE",
148 .family = NFPROTO_IPV4, 63 .family = NFPROTO_IPV4,
@@ -160,12 +75,8 @@ static int __init masquerade_tg_init(void)
160 75
161 ret = xt_register_target(&masquerade_tg_reg); 76 ret = xt_register_target(&masquerade_tg_reg);
162 77
163 if (ret == 0) { 78 if (ret == 0)
164 /* Register for device down reports */ 79 nf_nat_masquerade_ipv4_register_notifier();
165 register_netdevice_notifier(&masq_dev_notifier);
166 /* Register IP address change reports */
167 register_inetaddr_notifier(&masq_inet_notifier);
168 }
169 80
170 return ret; 81 return ret;
171} 82}
@@ -173,8 +84,7 @@ static int __init masquerade_tg_init(void)
173static void __exit masquerade_tg_exit(void) 84static void __exit masquerade_tg_exit(void)
174{ 85{
175 xt_unregister_target(&masquerade_tg_reg); 86 xt_unregister_target(&masquerade_tg_reg);
176 unregister_netdevice_notifier(&masq_dev_notifier); 87 nf_nat_masquerade_ipv4_unregister_notifier();
177 unregister_inetaddr_notifier(&masq_inet_notifier);
178} 88}
179 89
180module_init(masquerade_tg_init); 90module_init(masquerade_tg_init);
diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
new file mode 100644
index 000000000000..c6eb42100e9a
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
@@ -0,0 +1,153 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
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
9#include <linux/types.h>
10#include <linux/module.h>
11#include <linux/atomic.h>
12#include <linux/inetdevice.h>
13#include <linux/ip.h>
14#include <linux/timer.h>
15#include <linux/netfilter.h>
16#include <net/protocol.h>
17#include <net/ip.h>
18#include <net/checksum.h>
19#include <net/route.h>
20#include <linux/netfilter_ipv4.h>
21#include <linux/netfilter/x_tables.h>
22#include <net/netfilter/nf_nat.h>
23#include <net/netfilter/ipv4/nf_nat_masquerade.h>
24
25unsigned int
26nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
27 const struct nf_nat_range *range,
28 const struct net_device *out)
29{
30 struct nf_conn *ct;
31 struct nf_conn_nat *nat;
32 enum ip_conntrack_info ctinfo;
33 struct nf_nat_range newrange;
34 const struct rtable *rt;
35 __be32 newsrc, nh;
36
37 NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING);
38
39 ct = nf_ct_get(skb, &ctinfo);
40 nat = nfct_nat(ct);
41
42 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
43 ctinfo == IP_CT_RELATED_REPLY));
44
45 /* Source address is 0.0.0.0 - locally generated packet that is
46 * probably not supposed to be masqueraded.
47 */
48 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
49 return NF_ACCEPT;
50
51 rt = skb_rtable(skb);
52 nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
53 newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE);
54 if (!newsrc) {
55 pr_info("%s ate my IP address\n", out->name);
56 return NF_DROP;
57 }
58
59 nat->masq_index = out->ifindex;
60
61 /* Transfer from original range. */
62 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
63 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
64 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
65 newrange.min_addr.ip = newsrc;
66 newrange.max_addr.ip = newsrc;
67 newrange.min_proto = range->min_proto;
68 newrange.max_proto = range->max_proto;
69
70 /* Hand modified range to generic setup. */
71 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
72}
73EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);
74
75static int device_cmp(struct nf_conn *i, void *ifindex)
76{
77 const struct nf_conn_nat *nat = nfct_nat(i);
78
79 if (!nat)
80 return 0;
81 if (nf_ct_l3num(i) != NFPROTO_IPV4)
82 return 0;
83 return nat->masq_index == (int)(long)ifindex;
84}
85
86static int masq_device_event(struct notifier_block *this,
87 unsigned long event,
88 void *ptr)
89{
90 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
91 struct net *net = dev_net(dev);
92
93 if (event == NETDEV_DOWN) {
94 /* Device was downed. Search entire table for
95 * conntracks which were associated with that device,
96 * and forget them.
97 */
98 NF_CT_ASSERT(dev->ifindex != 0);
99
100 nf_ct_iterate_cleanup(net, device_cmp,
101 (void *)(long)dev->ifindex, 0, 0);
102 }
103
104 return NOTIFY_DONE;
105}
106
107static int masq_inet_event(struct notifier_block *this,
108 unsigned long event,
109 void *ptr)
110{
111 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
112 struct netdev_notifier_info info;
113
114 netdev_notifier_info_init(&info, dev);
115 return masq_device_event(this, event, &info);
116}
117
118static struct notifier_block masq_dev_notifier = {
119 .notifier_call = masq_device_event,
120};
121
122static struct notifier_block masq_inet_notifier = {
123 .notifier_call = masq_inet_event,
124};
125
126static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
127
128void nf_nat_masquerade_ipv4_register_notifier(void)
129{
130 /* check if the notifier was already set */
131 if (atomic_inc_return(&masquerade_notifier_refcount) > 1)
132 return;
133
134 /* Register for device down reports */
135 register_netdevice_notifier(&masq_dev_notifier);
136 /* Register IP address change reports */
137 register_inetaddr_notifier(&masq_inet_notifier);
138}
139EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);
140
141void nf_nat_masquerade_ipv4_unregister_notifier(void)
142{
143 /* check if the notifier still has clients */
144 if (atomic_dec_return(&masquerade_notifier_refcount) > 0)
145 return;
146
147 unregister_netdevice_notifier(&masq_dev_notifier);
148 unregister_inetaddr_notifier(&masq_inet_notifier);
149}
150EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier);
151
152MODULE_LICENSE("GPL");
153MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");