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
.dst
.protonum
!= IPPROTO_ICMP
&&
188 ct
->tuplehash
[dir
].tuple
.src
.u
.all
!=
189 ct
->tuplehash
[!dir
].tuple
.dst
.u
.all
))
190 if (nf_xfrm_me_harder(skb
, AF_INET
) < 0)
198 nf_nat_ipv4_local_fn(unsigned int hooknum
,
200 const struct net_device
*in
,
201 const struct net_device
*out
,
202 int (*okfn
)(struct sk_buff
*))
204 const struct nf_conn
*ct
;
205 enum ip_conntrack_info ctinfo
;
208 /* root is playing with raw sockets. */
209 if (skb
->len
< sizeof(struct iphdr
) ||
210 ip_hdrlen(skb
) < sizeof(struct iphdr
))
213 ret
= nf_nat_ipv4_fn(hooknum
, skb
, in
, out
, okfn
);
214 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
215 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
216 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
218 if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
!=
219 ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
220 if (ip_route_me_harder(skb
, RTN_UNSPEC
))
224 else if (!(IPCB(skb
)->flags
& IPSKB_XFRM_TRANSFORMED
) &&
225 ct
->tuplehash
[dir
].tuple
.dst
.protonum
!= IPPROTO_ICMP
&&
226 ct
->tuplehash
[dir
].tuple
.dst
.u
.all
!=
227 ct
->tuplehash
[!dir
].tuple
.src
.u
.all
)
228 if (nf_xfrm_me_harder(skb
, AF_INET
) < 0)
235 static struct nf_hook_ops nf_nat_ipv4_ops
[] __read_mostly
= {
236 /* Before packet filtering, change destination */
238 .hook
= nf_nat_ipv4_in
,
239 .owner
= THIS_MODULE
,
241 .hooknum
= NF_INET_PRE_ROUTING
,
242 .priority
= NF_IP_PRI_NAT_DST
,
244 /* After packet filtering, change source */
246 .hook
= nf_nat_ipv4_out
,
247 .owner
= THIS_MODULE
,
249 .hooknum
= NF_INET_POST_ROUTING
,
250 .priority
= NF_IP_PRI_NAT_SRC
,
252 /* Before packet filtering, change destination */
254 .hook
= nf_nat_ipv4_local_fn
,
255 .owner
= THIS_MODULE
,
257 .hooknum
= NF_INET_LOCAL_OUT
,
258 .priority
= NF_IP_PRI_NAT_DST
,
260 /* After packet filtering, change source */
262 .hook
= nf_nat_ipv4_fn
,
263 .owner
= THIS_MODULE
,
265 .hooknum
= NF_INET_LOCAL_IN
,
266 .priority
= NF_IP_PRI_NAT_SRC
,
270 static int __net_init
iptable_nat_net_init(struct net
*net
)
272 struct ipt_replace
*repl
;
274 repl
= ipt_alloc_initial_table(&nf_nat_ipv4_table
);
277 net
->ipv4
.nat_table
= ipt_register_table(net
, &nf_nat_ipv4_table
, repl
);
279 if (IS_ERR(net
->ipv4
.nat_table
))
280 return PTR_ERR(net
->ipv4
.nat_table
);
284 static void __net_exit
iptable_nat_net_exit(struct net
*net
)
286 ipt_unregister_table(net
, net
->ipv4
.nat_table
);
289 static struct pernet_operations iptable_nat_net_ops
= {
290 .init
= iptable_nat_net_init
,
291 .exit
= iptable_nat_net_exit
,
294 static int __init
iptable_nat_init(void)
298 err
= register_pernet_subsys(&iptable_nat_net_ops
);
302 err
= nf_register_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
308 unregister_pernet_subsys(&iptable_nat_net_ops
);
313 static void __exit
iptable_nat_exit(void)
315 nf_unregister_hooks(nf_nat_ipv4_ops
, ARRAY_SIZE(nf_nat_ipv4_ops
));
316 unregister_pernet_subsys(&iptable_nat_net_ops
);
319 module_init(iptable_nat_init
);
320 module_exit(iptable_nat_exit
);
322 MODULE_LICENSE("GPL");