1 /* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2011 Patrick McHardy <kaber@trash.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <linux/module.h>
11 #include <linux/netfilter.h>
12 #include <linux/netfilter_ipv4.h>
13 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <net/netfilter/nf_nat.h>
18 #include <net/netfilter/nf_nat_core.h>
19 #include <net/netfilter/nf_nat_l3proto.h>
21 static const struct xt_table nf_nat_ipv4_table
= {
23 .valid_hooks
= (1 << NF_INET_PRE_ROUTING
) |
24 (1 << NF_INET_POST_ROUTING
) |
25 (1 << NF_INET_LOCAL_OUT
) |
26 (1 << NF_INET_LOCAL_IN
),
31 static unsigned int alloc_null_binding(struct nf_conn
*ct
, unsigned int hooknum
)
33 /* Force range to this IP; let proto decide mapping for
34 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
36 struct nf_nat_range range
;
39 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct
,
40 HOOK2MANIP(hooknum
) == NF_NAT_MANIP_SRC
?
41 &ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.dst
.u3
.ip
:
42 &ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.src
.u3
.ip
);
44 return nf_nat_setup_info(ct
, &range
, HOOK2MANIP(hooknum
));
47 static unsigned int nf_nat_rule_find(struct sk_buff
*skb
, unsigned int hooknum
,
48 const struct net_device
*in
,
49 const struct net_device
*out
,
52 struct net
*net
= nf_ct_net(ct
);
55 ret
= ipt_do_table(skb
, hooknum
, in
, out
, net
->ipv4
.nat_table
);
56 if (ret
== NF_ACCEPT
) {
57 if (!nf_nat_initialized(ct
, HOOK2MANIP(hooknum
)))
58 ret
= alloc_null_binding(ct
, hooknum
);
64 nf_nat_ipv4_fn(unsigned int hooknum
,
66 const struct net_device
*in
,
67 const struct net_device
*out
,
68 int (*okfn
)(struct sk_buff
*))
71 enum ip_conntrack_info ctinfo
;
72 struct nf_conn_nat
*nat
;
73 /* maniptype == SRC for postrouting. */
74 enum nf_nat_manip_type maniptype
= HOOK2MANIP(hooknum
);
76 /* We never see fragments: conntrack defrags on pre-routing
77 * and local-out, and nf_nat_out protects post-routing.
79 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb
)));
81 ct
= nf_ct_get(skb
, &ctinfo
);
82 /* Can't track? It's not due to stress, or conntrack would
83 * have dropped it. Hence it's the user's responsibilty to
84 * packet filter it out, or implement conntrack/NAT for that
90 /* Don't try to NAT if this packet is not conntracked */
91 if (nf_ct_is_untracked(ct
))
96 /* NAT module was loaded late. */
97 if (nf_ct_is_confirmed(ct
))
99 nat
= nf_ct_ext_add(ct
, NF_CT_EXT_NAT
, GFP_ATOMIC
);
101 pr_debug("failed to add NAT extension\n");
108 case IP_CT_RELATED_REPLY
:
109 if (ip_hdr(skb
)->protocol
== IPPROTO_ICMP
) {
110 if (!nf_nat_icmp_reply_translation(skb
, ct
, ctinfo
,
116 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
118 /* Seen it before? This can happen for loopback, retrans,
121 if (!nf_nat_initialized(ct
, maniptype
)) {
124 ret
= nf_nat_rule_find(skb
, hooknum
, in
, out
, ct
);
125 if (ret
!= NF_ACCEPT
)
128 pr_debug("Already setup manip %s for ct %p\n",
129 maniptype
== NF_NAT_MANIP_SRC
? "SRC" : "DST",
131 if (nf_nat_oif_changed(hooknum
, ctinfo
, nat
, out
))
138 NF_CT_ASSERT(ctinfo
== IP_CT_ESTABLISHED
||
139 ctinfo
== IP_CT_ESTABLISHED_REPLY
);
140 if (nf_nat_oif_changed(hooknum
, ctinfo
, nat
, out
))
144 return nf_nat_packet(ct
, ctinfo
, hooknum
, skb
);
147 nf_ct_kill_acct(ct
, ctinfo
, skb
);
152 nf_nat_ipv4_in(unsigned int hooknum
,
154 const struct net_device
*in
,
155 const struct net_device
*out
,
156 int (*okfn
)(struct sk_buff
*))
159 __be32 daddr
= ip_hdr(skb
)->daddr
;
161 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
162 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
163 daddr
!= ip_hdr(skb
)->daddr
)
170 nf_nat_ipv4_out(unsigned int hooknum
,
172 const struct net_device
*in
,
173 const struct net_device
*out
,
174 int (*okfn
)(struct sk_buff
*))
177 const struct nf_conn
*ct
;
178 enum ip_conntrack_info ctinfo
;
183 /* root is playing with raw sockets. */
184 if (skb
->len
< sizeof(struct iphdr
) ||
185 ip_hdrlen(skb
) < sizeof(struct iphdr
))
188 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
190 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
191 !(IPCB(skb
)->flags
& IPSKB_XFRM_TRANSFORMED
) &&
192 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
193 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
195 if ((ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
!=
196 ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
) ||
197 (ct
->tuplehash
[dir
].tuple
.dst
.protonum
!= IPPROTO_ICMP
&&
198 ct
->tuplehash
[dir
].tuple
.src
.u
.all
!=
199 ct
->tuplehash
[!dir
].tuple
.dst
.u
.all
)) {
200 err
= nf_xfrm_me_harder(skb
, AF_INET
);
202 ret
= NF_DROP_ERR(err
);
210 nf_nat_ipv4_local_fn(unsigned int hooknum
,
212 const struct net_device
*in
,
213 const struct net_device
*out
,
214 int (*okfn
)(struct sk_buff
*))
216 const struct nf_conn
*ct
;
217 enum ip_conntrack_info ctinfo
;
221 /* root is playing with raw sockets. */
222 if (skb
->len
< sizeof(struct iphdr
) ||
223 ip_hdrlen(skb
) < sizeof(struct iphdr
))
226 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
227 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
228 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
229 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
231 if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
!=
232 ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
233 err
= ip_route_me_harder(skb
, RTN_UNSPEC
);
235 ret
= NF_DROP_ERR(err
);
238 else if (!(IPCB(skb
)->flags
& IPSKB_XFRM_TRANSFORMED
) &&
239 ct
->tuplehash
[dir
].tuple
.dst
.protonum
!= IPPROTO_ICMP
&&
240 ct
->tuplehash
[dir
].tuple
.dst
.u
.all
!=
241 ct
->tuplehash
[!dir
].tuple
.src
.u
.all
) {
242 err
= nf_xfrm_me_harder(skb
, AF_INET
);
244 ret
= NF_DROP_ERR(err
);
251 static struct nf_hook_ops nf_nat_ipv4_ops
[] __read_mostly
= {
252 /* Before packet filtering, change destination */
254 .hook
= nf_nat_ipv4_in
,
255 .owner
= THIS_MODULE
,
257 .hooknum
= NF_INET_PRE_ROUTING
,
258 .priority
= NF_IP_PRI_NAT_DST
,
260 /* After packet filtering, change source */
262 .hook
= nf_nat_ipv4_out
,
263 .owner
= THIS_MODULE
,
265 .hooknum
= NF_INET_POST_ROUTING
,
266 .priority
= NF_IP_PRI_NAT_SRC
,
268 /* Before packet filtering, change destination */
270 .hook
= nf_nat_ipv4_local_fn
,
271 .owner
= THIS_MODULE
,
273 .hooknum
= NF_INET_LOCAL_OUT
,
274 .priority
= NF_IP_PRI_NAT_DST
,
276 /* After packet filtering, change source */
278 .hook
= nf_nat_ipv4_fn
,
279 .owner
= THIS_MODULE
,
281 .hooknum
= NF_INET_LOCAL_IN
,
282 .priority
= NF_IP_PRI_NAT_SRC
,
286 static int __net_init
iptable_nat_net_init(struct net
*net
)
288 struct ipt_replace
*repl
;
290 repl
= ipt_alloc_initial_table(&nf_nat_ipv4_table
);
293 net
->ipv4
.nat_table
= ipt_register_table(net
, &nf_nat_ipv4_table
, repl
);
295 return PTR_RET(net
->ipv4
.nat_table
);
298 static void __net_exit
iptable_nat_net_exit(struct net
*net
)
300 ipt_unregister_table(net
, net
->ipv4
.nat_table
);
303 static struct pernet_operations iptable_nat_net_ops
= {
304 .init
= iptable_nat_net_init
,
305 .exit
= iptable_nat_net_exit
,
308 static int __init
iptable_nat_init(void)
312 err
= register_pernet_subsys(&iptable_nat_net_ops
);
316 err
= nf_register_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
322 unregister_pernet_subsys(&iptable_nat_net_ops
);
327 static void __exit
iptable_nat_exit(void)
329 nf_unregister_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
330 unregister_pernet_subsys(&iptable_nat_net_ops
);
333 module_init(iptable_nat_init
);
334 module_exit(iptable_nat_exit
);
336 MODULE_LICENSE("GPL");