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",
135 NF_CT_ASSERT(ctinfo
== IP_CT_ESTABLISHED
||
136 ctinfo
== IP_CT_ESTABLISHED_REPLY
);
139 return nf_nat_packet(ct
, ctinfo
, hooknum
, skb
);
143 nf_nat_ipv4_in(unsigned int hooknum
,
145 const struct net_device
*in
,
146 const struct net_device
*out
,
147 int (*okfn
)(struct sk_buff
*))
150 __be32 daddr
= ip_hdr(skb
)->daddr
;
152 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
153 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
154 daddr
!= ip_hdr(skb
)->daddr
)
161 nf_nat_ipv4_out(unsigned int hooknum
,
163 const struct net_device
*in
,
164 const struct net_device
*out
,
165 int (*okfn
)(struct sk_buff
*))
168 const struct nf_conn
*ct
;
169 enum ip_conntrack_info ctinfo
;
173 /* root is playing with raw sockets. */
174 if (skb
->len
< sizeof(struct iphdr
) ||
175 ip_hdrlen(skb
) < sizeof(struct iphdr
))
178 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
180 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
181 !(IPCB(skb
)->flags
& IPSKB_XFRM_TRANSFORMED
) &&
182 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
183 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
185 if ((ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
!=
186 ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
) ||
187 (ct
->tuplehash
[dir
].tuple
.src
.u
.all
!=
188 ct
->tuplehash
[!dir
].tuple
.dst
.u
.all
))
189 if (nf_xfrm_me_harder(skb
, AF_INET
) < 0)
197 nf_nat_ipv4_local_fn(unsigned int hooknum
,
199 const struct net_device
*in
,
200 const struct net_device
*out
,
201 int (*okfn
)(struct sk_buff
*))
203 const struct nf_conn
*ct
;
204 enum ip_conntrack_info ctinfo
;
207 /* root is playing with raw sockets. */
208 if (skb
->len
< sizeof(struct iphdr
) ||
209 ip_hdrlen(skb
) < sizeof(struct iphdr
))
212 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
213 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
214 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
215 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
217 if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
!=
218 ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
219 if (ip_route_me_harder(skb
, RTN_UNSPEC
))
223 else if (!(IPCB(skb
)->flags
& IPSKB_XFRM_TRANSFORMED
) &&
224 ct
->tuplehash
[dir
].tuple
.dst
.u
.all
!=
225 ct
->tuplehash
[!dir
].tuple
.src
.u
.all
)
226 if (nf_xfrm_me_harder(skb
, AF_INET
) < 0)
233 static struct nf_hook_ops nf_nat_ipv4_ops
[] __read_mostly
= {
234 /* Before packet filtering, change destination */
236 .hook
= nf_nat_ipv4_in
,
237 .owner
= THIS_MODULE
,
239 .hooknum
= NF_INET_PRE_ROUTING
,
240 .priority
= NF_IP_PRI_NAT_DST
,
242 /* After packet filtering, change source */
244 .hook
= nf_nat_ipv4_out
,
245 .owner
= THIS_MODULE
,
247 .hooknum
= NF_INET_POST_ROUTING
,
248 .priority
= NF_IP_PRI_NAT_SRC
,
250 /* Before packet filtering, change destination */
252 .hook
= nf_nat_ipv4_local_fn
,
253 .owner
= THIS_MODULE
,
255 .hooknum
= NF_INET_LOCAL_OUT
,
256 .priority
= NF_IP_PRI_NAT_DST
,
258 /* After packet filtering, change source */
260 .hook
= nf_nat_ipv4_fn
,
261 .owner
= THIS_MODULE
,
263 .hooknum
= NF_INET_LOCAL_IN
,
264 .priority
= NF_IP_PRI_NAT_SRC
,
268 static int __net_init
iptable_nat_net_init(struct net
*net
)
270 struct ipt_replace
*repl
;
272 repl
= ipt_alloc_initial_table(&nf_nat_ipv4_table
);
275 net
->ipv4
.nat_table
= ipt_register_table(net
, &nf_nat_ipv4_table
, repl
);
277 if (IS_ERR(net
->ipv4
.nat_table
))
278 return PTR_ERR(net
->ipv4
.nat_table
);
282 static void __net_exit
iptable_nat_net_exit(struct net
*net
)
284 ipt_unregister_table(net
, net
->ipv4
.nat_table
);
287 static struct pernet_operations iptable_nat_net_ops
= {
288 .init
= iptable_nat_net_init
,
289 .exit
= iptable_nat_net_exit
,
292 static int __init
iptable_nat_init(void)
296 err
= register_pernet_subsys(&iptable_nat_net_ops
);
300 err
= nf_register_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
306 unregister_pernet_subsys(&iptable_nat_net_ops
);
311 static void __exit
iptable_nat_exit(void)
313 nf_unregister_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
314 unregister_pernet_subsys(&iptable_nat_net_ops
);
317 module_init(iptable_nat_init
);
318 module_exit(iptable_nat_exit
);
320 MODULE_LICENSE("GPL");