Skip to content

Commit 8dd33cc

Browse files
aborreroummakynes
authored andcommitted
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 <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent c55fbbb commit 8dd33cc

File tree

5 files changed

+184
-99
lines changed

5 files changed

+184
-99
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6+
unsigned int
7+
nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
8+
const struct nf_nat_range *range,
9+
const struct net_device *out);
10+
11+
void nf_nat_masquerade_ipv4_register_notifier(void);
12+
void nf_nat_masquerade_ipv4_unregister_notifier(void);
13+
14+
#endif /*_NF_NAT_MASQUERADE_IPV4_H_ */

net/ipv4/netfilter/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,15 @@ config NF_NAT_IPV4
184184

185185
if NF_NAT_IPV4
186186

187+
config 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+
187193
config IP_NF_TARGET_MASQUERADE
188194
tristate "MASQUERADE target support"
195+
select NF_NAT_MASQUERADE_IPV4
189196
default m if NETFILTER_ADVANCED=n
190197
help
191198
Masquerading is a special case of NAT: all outgoing connections are

net/ipv4/netfilter/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o
2727
obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
2828
obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
2929
obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
30+
obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o
3031

3132
# NAT protocols (nf_nat)
3233
obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o

net/ipv4/netfilter/ipt_MASQUERADE.c

Lines changed: 9 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/netfilter_ipv4.h>
2323
#include <linux/netfilter/x_tables.h>
2424
#include <net/netfilter/nf_nat.h>
25+
#include <net/netfilter/ipv4/nf_nat_masquerade.h>
2526

2627
MODULE_LICENSE("GPL");
2728
MODULE_AUTHOR("Netfilter Core Team <[email protected]>");
@@ -46,103 +47,17 @@ static int masquerade_tg_check(const struct xt_tgchk_param *par)
4647
static unsigned int
4748
masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
4849
{
49-
struct nf_conn *ct;
50-
struct nf_conn_nat *nat;
51-
enum ip_conntrack_info ctinfo;
52-
struct nf_nat_range newrange;
50+
struct nf_nat_range range;
5351
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;
7052

7153
mr = par->targinfo;
72-
rt = skb_rtable(skb);
73-
nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
74-
newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE);
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;
54+
range.flags = mr->range[0].flags;
55+
range.min_proto = mr->range[0].min;
56+
range.max_proto = mr->range[0].max;
9057

91-
/* Hand modified range to generic setup. */
92-
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
58+
return nf_nat_masquerade_ipv4(skb, par->hooknum, &range, par->out);
9359
}
9460

95-
static int
96-
device_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-
107-
static 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-
127-
static 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-
138-
static struct notifier_block masq_dev_notifier = {
139-
.notifier_call = masq_device_event,
140-
};
141-
142-
static struct notifier_block masq_inet_notifier = {
143-
.notifier_call = masq_inet_event,
144-
};
145-
14661
static struct xt_target masquerade_tg_reg __read_mostly = {
14762
.name = "MASQUERADE",
14863
.family = NFPROTO_IPV4,
@@ -160,21 +75,16 @@ static int __init masquerade_tg_init(void)
16075

16176
ret = xt_register_target(&masquerade_tg_reg);
16277

163-
if (ret == 0) {
164-
/* Register for device down reports */
165-
register_netdevice_notifier(&masq_dev_notifier);
166-
/* Register IP address change reports */
167-
register_inetaddr_notifier(&masq_inet_notifier);
168-
}
78+
if (ret == 0)
79+
nf_nat_masquerade_ipv4_register_notifier();
16980

17081
return ret;
17182
}
17283

17384
static void __exit masquerade_tg_exit(void)
17485
{
17586
xt_unregister_target(&masquerade_tg_reg);
176-
unregister_netdevice_notifier(&masq_dev_notifier);
177-
unregister_inetaddr_notifier(&masq_inet_notifier);
87+
nf_nat_masquerade_ipv4_unregister_notifier();
17888
}
17989

18090
module_init(masquerade_tg_init);
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/* (C) 1999-2001 Paul `Rusty' Russell
2+
* (C) 2002-2006 Netfilter Core Team <[email protected]>
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+
25+
unsigned int
26+
nf_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+
}
73+
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);
74+
75+
static 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+
86+
static 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+
107+
static 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+
118+
static struct notifier_block masq_dev_notifier = {
119+
.notifier_call = masq_device_event,
120+
};
121+
122+
static struct notifier_block masq_inet_notifier = {
123+
.notifier_call = masq_inet_event,
124+
};
125+
126+
static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
127+
128+
void 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+
}
139+
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);
140+
141+
void 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+
}
150+
EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier);
151+
152+
MODULE_LICENSE("GPL");
153+
MODULE_AUTHOR("Rusty Russell <[email protected]>");

0 commit comments

Comments
 (0)