1 /* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
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.
8 #include <linux/types.h>
9 #include <linux/icmp.h>
10 #include <linux/gfp.h>
12 #include <linux/netfilter.h>
13 #include <linux/netfilter_ipv4.h>
14 #include <linux/module.h>
15 #include <linux/skbuff.h>
16 #include <linux/proc_fs.h>
18 #include <net/checksum.h>
19 #include <linux/spinlock.h>
21 #include <net/netfilter/nf_conntrack.h>
22 #include <net/netfilter/nf_conntrack_core.h>
23 #include <net/netfilter/nf_conntrack_extend.h>
24 #include <net/netfilter/nf_nat.h>
25 #include <net/netfilter/nf_nat_rule.h>
26 #include <net/netfilter/nf_nat_protocol.h>
27 #include <net/netfilter/nf_nat_core.h>
28 #include <net/netfilter/nf_nat_helper.h>
29 #include <linux/netfilter_ipv4/ip_tables.h>
32 static void nat_decode_session(struct sk_buff
*skb
, struct flowi
*fl
)
34 struct flowi4
*fl4
= &fl
->u
.ip4
;
35 const struct nf_conn
*ct
;
36 const struct nf_conntrack_tuple
*t
;
37 enum ip_conntrack_info ctinfo
;
38 enum ip_conntrack_dir dir
;
39 unsigned long statusbit
;
41 ct
= nf_ct_get(skb
, &ctinfo
);
44 dir
= CTINFO2DIR(ctinfo
);
45 t
= &ct
->tuplehash
[dir
].tuple
;
47 if (dir
== IP_CT_DIR_ORIGINAL
)
48 statusbit
= IPS_DST_NAT
;
50 statusbit
= IPS_SRC_NAT
;
52 if (ct
->status
& statusbit
) {
53 fl4
->daddr
= t
->dst
.u3
.ip
;
54 if (t
->dst
.protonum
== IPPROTO_TCP
||
55 t
->dst
.protonum
== IPPROTO_UDP
||
56 t
->dst
.protonum
== IPPROTO_UDPLITE
||
57 t
->dst
.protonum
== IPPROTO_DCCP
||
58 t
->dst
.protonum
== IPPROTO_SCTP
)
59 fl4
->fl4_dport
= t
->dst
.u
.tcp
.port
;
62 statusbit
^= IPS_NAT_MASK
;
64 if (ct
->status
& statusbit
) {
65 fl4
->saddr
= t
->src
.u3
.ip
;
66 if (t
->dst
.protonum
== IPPROTO_TCP
||
67 t
->dst
.protonum
== IPPROTO_UDP
||
68 t
->dst
.protonum
== IPPROTO_UDPLITE
||
69 t
->dst
.protonum
== IPPROTO_DCCP
||
70 t
->dst
.protonum
== IPPROTO_SCTP
)
71 fl4
->fl4_sport
= t
->src
.u
.tcp
.port
;
77 nf_nat_fn(unsigned int hooknum
,
79 const struct net_device
*in
,
80 const struct net_device
*out
,
81 int (*okfn
)(struct sk_buff
*))
84 enum ip_conntrack_info ctinfo
;
85 struct nf_conn_nat
*nat
;
86 /* maniptype == SRC for postrouting. */
87 enum nf_nat_manip_type maniptype
= HOOK2MANIP(hooknum
);
89 /* We never see fragments: conntrack defrags on pre-routing
90 and local-out, and nf_nat_out protects post-routing. */
91 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb
)));
93 ct
= nf_ct_get(skb
, &ctinfo
);
94 /* Can't track? It's not due to stress, or conntrack would
95 have dropped it. Hence it's the user's responsibilty to
96 packet filter it out, or implement conntrack/NAT for that
101 /* Don't try to NAT if this packet is not conntracked */
102 if (nf_ct_is_untracked(ct
))
107 /* NAT module was loaded late. */
108 if (nf_ct_is_confirmed(ct
))
110 nat
= nf_ct_ext_add(ct
, NF_CT_EXT_NAT
, GFP_ATOMIC
);
112 pr_debug("failed to add NAT extension\n");
119 case IP_CT_RELATED_REPLY
:
120 if (ip_hdr(skb
)->protocol
== IPPROTO_ICMP
) {
121 if (!nf_nat_icmp_reply_translation(ct
, ctinfo
,
127 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
130 /* Seen it before? This can happen for loopback, retrans,
131 or local packets.. */
132 if (!nf_nat_initialized(ct
, maniptype
)) {
135 ret
= nf_nat_rule_find(skb
, hooknum
, in
, out
, ct
);
136 if (ret
!= NF_ACCEPT
)
139 pr_debug("Already setup manip %s for ct %p\n",
140 maniptype
== NF_NAT_MANIP_SRC
? "SRC" : "DST",
146 NF_CT_ASSERT(ctinfo
== IP_CT_ESTABLISHED
||
147 ctinfo
== IP_CT_ESTABLISHED_REPLY
);
150 return nf_nat_packet(ct
, ctinfo
, hooknum
, skb
);
154 nf_nat_in(unsigned int hooknum
,
156 const struct net_device
*in
,
157 const struct net_device
*out
,
158 int (*okfn
)(struct sk_buff
*))
161 __be32 daddr
= ip_hdr(skb
)->daddr
;
163 ret
= nf_nat_fn(hooknum
, skb
, in
, out
, okfn
);
164 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
165 daddr
!= ip_hdr(skb
)->daddr
)
172 nf_nat_out(unsigned int hooknum
,
174 const struct net_device
*in
,
175 const struct net_device
*out
,
176 int (*okfn
)(struct sk_buff
*))
179 const struct nf_conn
*ct
;
180 enum ip_conntrack_info ctinfo
;
184 /* root is playing with raw sockets. */
185 if (skb
->len
< sizeof(struct iphdr
) ||
186 ip_hdrlen(skb
) < sizeof(struct iphdr
))
189 ret
= nf_nat_fn(hooknum
, skb
, in
, out
, okfn
);
191 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
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
.src
.u
.all
!=
198 ct
->tuplehash
[!dir
].tuple
.dst
.u
.all
)
200 return ip_xfrm_me_harder(skb
) == 0 ? ret
: NF_DROP
;
207 nf_nat_local_fn(unsigned int hooknum
,
209 const struct net_device
*in
,
210 const struct net_device
*out
,
211 int (*okfn
)(struct sk_buff
*))
213 const struct nf_conn
*ct
;
214 enum ip_conntrack_info ctinfo
;
217 /* root is playing with raw sockets. */
218 if (skb
->len
< sizeof(struct iphdr
) ||
219 ip_hdrlen(skb
) < sizeof(struct iphdr
))
222 ret
= nf_nat_fn(hooknum
, skb
, in
, out
, okfn
);
223 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
224 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
225 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
227 if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
!=
228 ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
229 if (ip_route_me_harder(skb
, RTN_UNSPEC
))
233 else if (ct
->tuplehash
[dir
].tuple
.dst
.u
.all
!=
234 ct
->tuplehash
[!dir
].tuple
.src
.u
.all
)
235 if (ip_xfrm_me_harder(skb
))
242 /* We must be after connection tracking and before packet filtering. */
244 static struct nf_hook_ops nf_nat_ops
[] __read_mostly
= {
245 /* Before packet filtering, change destination */
248 .owner
= THIS_MODULE
,
250 .hooknum
= NF_INET_PRE_ROUTING
,
251 .priority
= NF_IP_PRI_NAT_DST
,
253 /* After packet filtering, change source */
256 .owner
= THIS_MODULE
,
258 .hooknum
= NF_INET_POST_ROUTING
,
259 .priority
= NF_IP_PRI_NAT_SRC
,
261 /* Before packet filtering, change destination */
263 .hook
= nf_nat_local_fn
,
264 .owner
= THIS_MODULE
,
266 .hooknum
= NF_INET_LOCAL_OUT
,
267 .priority
= NF_IP_PRI_NAT_DST
,
269 /* After packet filtering, change source */
272 .owner
= THIS_MODULE
,
274 .hooknum
= NF_INET_LOCAL_IN
,
275 .priority
= NF_IP_PRI_NAT_SRC
,
279 static int __init
nf_nat_standalone_init(void)
283 need_ipv4_conntrack();
286 BUG_ON(ip_nat_decode_session
!= NULL
);
287 RCU_INIT_POINTER(ip_nat_decode_session
, nat_decode_session
);
289 ret
= nf_nat_rule_init();
291 pr_err("nf_nat_init: can't setup rules.\n");
292 goto cleanup_decode_session
;
294 ret
= nf_register_hooks(nf_nat_ops
, ARRAY_SIZE(nf_nat_ops
));
296 pr_err("nf_nat_init: can't register hooks.\n");
297 goto cleanup_rule_init
;
302 nf_nat_rule_cleanup();
303 cleanup_decode_session
:
305 RCU_INIT_POINTER(ip_nat_decode_session
, NULL
);
311 static void __exit
nf_nat_standalone_fini(void)
313 nf_unregister_hooks(nf_nat_ops
, ARRAY_SIZE(nf_nat_ops
));
314 nf_nat_rule_cleanup();
316 RCU_INIT_POINTER(ip_nat_decode_session
, NULL
);
319 /* Conntrack caches are unregistered in nf_conntrack_cleanup */
322 module_init(nf_nat_standalone_init
);
323 module_exit(nf_nat_standalone_fini
);
325 MODULE_LICENSE("GPL");
326 MODULE_ALIAS("ip_nat");