2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
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 * Development of this code funded by Astaro AG (http://www.astaro.com/)
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/list.h>
14 #include <linux/skbuff.h>
16 #include <linux/netlink.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter_ipv4.h>
19 #include <linux/netfilter/nfnetlink.h>
20 #include <linux/netfilter/nf_tables.h>
21 #include <net/netfilter/nf_conntrack.h>
22 #include <net/netfilter/nf_nat.h>
23 #include <net/netfilter/nf_nat_core.h>
24 #include <net/netfilter/nf_tables.h>
25 #include <net/netfilter/nf_nat_l3proto.h>
29 enum nft_registers sreg_addr_min
:8;
30 enum nft_registers sreg_addr_max
:8;
31 enum nft_registers sreg_proto_min
:8;
32 enum nft_registers sreg_proto_max
:8;
33 enum nf_nat_manip_type type
;
36 static void nft_nat_eval(const struct nft_expr
*expr
,
37 struct nft_data data
[NFT_REG_MAX
+ 1],
38 const struct nft_pktinfo
*pkt
)
40 const struct nft_nat
*priv
= nft_expr_priv(expr
);
41 enum ip_conntrack_info ctinfo
;
42 struct nf_conn
*ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
43 struct nf_nat_range range
;
45 memset(&range
, 0, sizeof(range
));
46 if (priv
->sreg_addr_min
) {
47 range
.min_addr
.ip
= data
[priv
->sreg_addr_min
].data
[0];
48 range
.max_addr
.ip
= data
[priv
->sreg_addr_max
].data
[0];
49 range
.flags
|= NF_NAT_RANGE_MAP_IPS
;
52 if (priv
->sreg_proto_min
) {
53 range
.min_proto
.all
= data
[priv
->sreg_proto_min
].data
[0];
54 range
.max_proto
.all
= data
[priv
->sreg_proto_max
].data
[0];
55 range
.flags
|= NF_NAT_RANGE_PROTO_SPECIFIED
;
58 data
[NFT_REG_VERDICT
].verdict
=
59 nf_nat_setup_info(ct
, &range
, priv
->type
);
62 static const struct nla_policy nft_nat_policy
[NFTA_NAT_MAX
+ 1] = {
63 [NFTA_NAT_ADDR_MIN
] = { .type
= NLA_U32
},
64 [NFTA_NAT_ADDR_MAX
] = { .type
= NLA_U32
},
65 [NFTA_NAT_PROTO_MIN
] = { .type
= NLA_U32
},
66 [NFTA_NAT_PROTO_MAX
] = { .type
= NLA_U32
},
67 [NFTA_NAT_TYPE
] = { .type
= NLA_U32
},
70 static int nft_nat_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
71 const struct nlattr
* const tb
[])
73 struct nft_nat
*priv
= nft_expr_priv(expr
);
76 if (tb
[NFTA_NAT_TYPE
] == NULL
)
79 switch (ntohl(nla_get_be32(tb
[NFTA_NAT_TYPE
]))) {
81 priv
->type
= NF_NAT_MANIP_SRC
;
84 priv
->type
= NF_NAT_MANIP_DST
;
90 if (tb
[NFTA_NAT_ADDR_MIN
]) {
91 priv
->sreg_addr_min
= ntohl(nla_get_be32(tb
[NFTA_NAT_ADDR_MIN
]));
92 err
= nft_validate_input_register(priv
->sreg_addr_min
);
97 if (tb
[NFTA_NAT_ADDR_MAX
]) {
98 priv
->sreg_addr_max
= ntohl(nla_get_be32(tb
[NFTA_NAT_ADDR_MAX
]));
99 err
= nft_validate_input_register(priv
->sreg_addr_max
);
103 priv
->sreg_addr_max
= priv
->sreg_addr_min
;
105 if (tb
[NFTA_NAT_PROTO_MIN
]) {
106 priv
->sreg_proto_min
= ntohl(nla_get_be32(tb
[NFTA_NAT_PROTO_MIN
]));
107 err
= nft_validate_input_register(priv
->sreg_proto_min
);
112 if (tb
[NFTA_NAT_PROTO_MAX
]) {
113 priv
->sreg_proto_max
= ntohl(nla_get_be32(tb
[NFTA_NAT_PROTO_MAX
]));
114 err
= nft_validate_input_register(priv
->sreg_proto_max
);
118 priv
->sreg_proto_max
= priv
->sreg_proto_min
;
123 static int nft_nat_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
125 const struct nft_nat
*priv
= nft_expr_priv(expr
);
127 switch (priv
->type
) {
128 case NF_NAT_MANIP_SRC
:
129 if (nla_put_be32(skb
, NFTA_NAT_TYPE
, htonl(NFT_NAT_SNAT
)))
130 goto nla_put_failure
;
132 case NF_NAT_MANIP_DST
:
133 if (nla_put_be32(skb
, NFTA_NAT_TYPE
, htonl(NFT_NAT_DNAT
)))
134 goto nla_put_failure
;
138 if (nla_put_be32(skb
, NFTA_NAT_ADDR_MIN
, htonl(priv
->sreg_addr_min
)))
139 goto nla_put_failure
;
140 if (nla_put_be32(skb
, NFTA_NAT_ADDR_MAX
, htonl(priv
->sreg_addr_max
)))
141 goto nla_put_failure
;
142 if (nla_put_be32(skb
, NFTA_NAT_PROTO_MIN
, htonl(priv
->sreg_proto_min
)))
143 goto nla_put_failure
;
144 if (nla_put_be32(skb
, NFTA_NAT_PROTO_MAX
, htonl(priv
->sreg_proto_max
)))
145 goto nla_put_failure
;
152 static struct nft_expr_type nft_nat_type
;
153 static const struct nft_expr_ops nft_nat_ops
= {
154 .type
= &nft_nat_type
,
155 .size
= NFT_EXPR_SIZE(sizeof(struct nft_nat
)),
156 .eval
= nft_nat_eval
,
157 .init
= nft_nat_init
,
158 .dump
= nft_nat_dump
,
161 static struct nft_expr_type nft_nat_type __read_mostly
= {
164 .policy
= nft_nat_policy
,
165 .maxattr
= NFTA_NAT_MAX
,
166 .owner
= THIS_MODULE
,
173 static unsigned int nf_nat_fn(const struct nf_hook_ops
*ops
,
175 const struct net_device
*in
,
176 const struct net_device
*out
,
177 int (*okfn
)(struct sk_buff
*))
179 enum ip_conntrack_info ctinfo
;
180 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
181 struct nf_conn_nat
*nat
;
182 enum nf_nat_manip_type maniptype
= HOOK2MANIP(ops
->hooknum
);
185 if (ct
== NULL
|| nf_ct_is_untracked(ct
))
188 NF_CT_ASSERT(!(ip_hdr(skb
)->frag_off
& htons(IP_MF
| IP_OFFSET
)));
192 /* Conntrack module was loaded late, can't add extension. */
193 if (nf_ct_is_confirmed(ct
))
195 nat
= nf_ct_ext_add(ct
, NF_CT_EXT_NAT
, GFP_ATOMIC
);
202 case IP_CT_RELATED
+ IP_CT_IS_REPLY
:
203 if (ip_hdr(skb
)->protocol
== IPPROTO_ICMP
) {
204 if (!nf_nat_icmp_reply_translation(skb
, ct
, ctinfo
,
212 if (nf_nat_initialized(ct
, maniptype
))
215 ret
= nft_do_chain(ops
, skb
, in
, out
, okfn
);
216 if (ret
!= NF_ACCEPT
)
218 if (!nf_nat_initialized(ct
, maniptype
)) {
219 ret
= nf_nat_alloc_null_binding(ct
, ops
->hooknum
);
220 if (ret
!= NF_ACCEPT
)
227 return nf_nat_packet(ct
, ctinfo
, ops
->hooknum
, skb
);
230 static unsigned int nf_nat_prerouting(const struct nf_hook_ops
*ops
,
232 const struct net_device
*in
,
233 const struct net_device
*out
,
234 int (*okfn
)(struct sk_buff
*))
236 __be32 daddr
= ip_hdr(skb
)->daddr
;
239 ret
= nf_nat_fn(ops
, skb
, in
, out
, okfn
);
240 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
241 ip_hdr(skb
)->daddr
!= daddr
) {
247 static unsigned int nf_nat_postrouting(const struct nf_hook_ops
*ops
,
249 const struct net_device
*in
,
250 const struct net_device
*out
,
251 int (*okfn
)(struct sk_buff
*))
253 enum ip_conntrack_info ctinfo __maybe_unused
;
254 const struct nf_conn
*ct __maybe_unused
;
257 ret
= nf_nat_fn(ops
, skb
, in
, out
, okfn
);
259 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
260 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
261 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
263 if (ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
!=
264 ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
||
265 ct
->tuplehash
[dir
].tuple
.src
.u
.all
!=
266 ct
->tuplehash
[!dir
].tuple
.dst
.u
.all
)
267 return nf_xfrm_me_harder(skb
, AF_INET
) == 0 ?
274 static unsigned int nf_nat_output(const struct nf_hook_ops
*ops
,
276 const struct net_device
*in
,
277 const struct net_device
*out
,
278 int (*okfn
)(struct sk_buff
*))
280 enum ip_conntrack_info ctinfo
;
281 const struct nf_conn
*ct
;
284 ret
= nf_nat_fn(ops
, skb
, in
, out
, okfn
);
285 if (ret
!= NF_DROP
&& ret
!= NF_STOLEN
&&
286 (ct
= nf_ct_get(skb
, &ctinfo
)) != NULL
) {
287 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
289 if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
!=
290 ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
291 if (ip_route_me_harder(skb
, RTN_UNSPEC
))
295 else if (ct
->tuplehash
[dir
].tuple
.dst
.u
.all
!=
296 ct
->tuplehash
[!dir
].tuple
.src
.u
.all
)
297 if (nf_xfrm_me_harder(skb
, AF_INET
))
304 static struct nft_base_chain nf_chain_nat_prerouting __read_mostly
= {
306 .name
= "PREROUTING",
307 .rules
= LIST_HEAD_INIT(nf_chain_nat_prerouting
.chain
.rules
),
308 .flags
= NFT_BASE_CHAIN
| NFT_CHAIN_BUILTIN
,
311 .hook
= nf_nat_prerouting
,
312 .owner
= THIS_MODULE
,
314 .hooknum
= NF_INET_PRE_ROUTING
,
315 .priority
= NF_IP_PRI_NAT_DST
,
316 .priv
= &nf_chain_nat_prerouting
.chain
,
320 static struct nft_base_chain nf_chain_nat_postrouting __read_mostly
= {
322 .name
= "POSTROUTING",
323 .rules
= LIST_HEAD_INIT(nf_chain_nat_postrouting
.chain
.rules
),
324 .flags
= NFT_BASE_CHAIN
| NFT_CHAIN_BUILTIN
,
327 .hook
= nf_nat_postrouting
,
328 .owner
= THIS_MODULE
,
330 .hooknum
= NF_INET_POST_ROUTING
,
331 .priority
= NF_IP_PRI_NAT_SRC
,
332 .priv
= &nf_chain_nat_postrouting
.chain
,
336 static struct nft_base_chain nf_chain_nat_output __read_mostly
= {
339 .rules
= LIST_HEAD_INIT(nf_chain_nat_output
.chain
.rules
),
340 .flags
= NFT_BASE_CHAIN
| NFT_CHAIN_BUILTIN
,
343 .hook
= nf_nat_output
,
344 .owner
= THIS_MODULE
,
346 .hooknum
= NF_INET_LOCAL_OUT
,
347 .priority
= NF_IP_PRI_NAT_DST
,
348 .priv
= &nf_chain_nat_output
.chain
,
352 static struct nft_base_chain nf_chain_nat_input __read_mostly
= {
355 .rules
= LIST_HEAD_INIT(nf_chain_nat_input
.chain
.rules
),
356 .flags
= NFT_BASE_CHAIN
| NFT_CHAIN_BUILTIN
,
360 .owner
= THIS_MODULE
,
362 .hooknum
= NF_INET_LOCAL_IN
,
363 .priority
= NF_IP_PRI_NAT_SRC
,
364 .priv
= &nf_chain_nat_input
.chain
,
369 static struct nft_table nf_table_nat_ipv4 __read_mostly
= {
371 .chains
= LIST_HEAD_INIT(nf_table_nat_ipv4
.chains
),
374 static int __init
nf_table_nat_init(void)
378 list_add_tail(&nf_chain_nat_prerouting
.chain
.list
,
379 &nf_table_nat_ipv4
.chains
);
380 list_add_tail(&nf_chain_nat_postrouting
.chain
.list
,
381 &nf_table_nat_ipv4
.chains
);
382 list_add_tail(&nf_chain_nat_output
.chain
.list
,
383 &nf_table_nat_ipv4
.chains
);
384 list_add_tail(&nf_chain_nat_input
.chain
.list
,
385 &nf_table_nat_ipv4
.chains
);
387 err
= nft_register_table(&nf_table_nat_ipv4
, NFPROTO_IPV4
);
391 err
= nft_register_expr(&nft_nat_type
);
398 nft_unregister_table(&nf_table_nat_ipv4
, NFPROTO_IPV4
);
403 static void __exit
nf_table_nat_exit(void)
405 nft_unregister_expr(&nft_nat_type
);
406 nft_unregister_table(&nf_table_nat_ipv4
, AF_INET
);
409 module_init(nf_table_nat_init
);
410 module_exit(nf_table_nat_exit
);
412 MODULE_LICENSE("GPL");
413 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
414 MODULE_ALIAS_NFT_TABLE(AF_INET
, "nat");
415 MODULE_ALIAS_NFT_EXPR("nat");