diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 7 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_MASQUERADE.c | 108 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 153 |
4 files changed, 170 insertions, 99 deletions
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 | ||
185 | if NF_NAT_IPV4 | 185 | if NF_NAT_IPV4 |
186 | 186 | ||
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 | |||
187 | config IP_NF_TARGET_MASQUERADE | 193 | config 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 | |||
27 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o | 27 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o |
28 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o | 28 | obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o |
29 | obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o | 29 | obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o |
30 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o | ||
30 | 31 | ||
31 | # NAT protocols (nf_nat) | 32 | # NAT protocols (nf_nat) |
32 | obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o | 33 | obj-$(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 | ||
26 | MODULE_LICENSE("GPL"); | 27 | MODULE_LICENSE("GPL"); |
27 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 28 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -46,103 +47,17 @@ static int masquerade_tg_check(const struct xt_tgchk_param *par) | |||
46 | static unsigned int | 47 | static unsigned int |
47 | masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par) | 48 | masquerade_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 | ||
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 | |||
146 | static struct xt_target masquerade_tg_reg __read_mostly = { | 61 | static 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) | |||
173 | static void __exit masquerade_tg_exit(void) | 84 | static 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 | ||
180 | module_init(masquerade_tg_init); | 90 | module_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 | |||
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 <rusty@rustcorp.com.au>"); | ||