Skip to content

Commit eb31628

Browse files
Tomasz Bursztykaummakynes
authored andcommitted
netfilter: nf_tables: Add support for IPv6 NAT
This patch generalizes the NAT expression to support both IPv4 and IPv6 using the existing IPv4/IPv6 NAT infrastructure. This also adds the NAT chain type for IPv6. This patch collapses the following patches that were posted to the netfilter-devel mailing list, from Tomasz: * nf_tables: Change NFTA_NAT_ attributes to better semantic significance * nf_tables: Split IPv4 NAT into NAT expression and IPv4 NAT chain * nf_tables: Add support for IPv6 NAT expression * nf_tables: Add support for IPv6 NAT chain * nf_tables: Fix up build issue on IPv6 NAT support And, from Pablo Neira Ayuso: * fix missing dependencies in nft_chain_nat Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent 9ddf632 commit eb31628

File tree

9 files changed

+457
-162
lines changed

9 files changed

+457
-162
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -695,18 +695,20 @@ enum nft_nat_types {
695695
* enum nft_nat_attributes - nf_tables nat expression netlink attributes
696696
*
697697
* @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
698-
* @NFTA_NAT_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
699-
* @NFTA_NAT_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
700-
* @NFTA_NAT_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
701-
* @NFTA_NAT_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
698+
* @NFTA_NAT_FAMILY: NAT family (NLA_U32)
699+
* @NFTA_NAT_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
700+
* @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
701+
* @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
702+
* @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
702703
*/
703704
enum nft_nat_attributes {
704705
NFTA_NAT_UNSPEC,
705706
NFTA_NAT_TYPE,
706-
NFTA_NAT_ADDR_MIN,
707-
NFTA_NAT_ADDR_MAX,
708-
NFTA_NAT_PROTO_MIN,
709-
NFTA_NAT_PROTO_MAX,
707+
NFTA_NAT_FAMILY,
708+
NFTA_NAT_REG_ADDR_MIN,
709+
NFTA_NAT_REG_ADDR_MAX,
710+
NFTA_NAT_REG_PROTO_MIN,
711+
NFTA_NAT_REG_PROTO_MAX,
710712
__NFTA_NAT_MAX
711713
};
712714
#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)

net/ipv4/netfilter/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ config NFT_CHAIN_ROUTE_IPV4
5050

5151
config NFT_CHAIN_NAT_IPV4
5252
depends on NF_TABLES_IPV4
53+
depends on NF_NAT_IPV4 && NFT_NAT
5354
tristate "IPv4 nf_tables nat chain support"
5455

5556
config IP_NF_IPTABLES

net/ipv4/netfilter/nft_chain_nat_ipv4.c

Lines changed: 2 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
33
* Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4+
* Copyright (c) 2012 Intel Corporation
45
*
56
* This program is free software; you can redistribute it and/or modify
67
* it under the terms of the GNU General Public License version 2 as
@@ -14,10 +15,8 @@
1415
#include <linux/list.h>
1516
#include <linux/skbuff.h>
1617
#include <linux/ip.h>
17-
#include <linux/netlink.h>
1818
#include <linux/netfilter.h>
1919
#include <linux/netfilter_ipv4.h>
20-
#include <linux/netfilter/nfnetlink.h>
2120
#include <linux/netfilter/nf_tables.h>
2221
#include <net/netfilter/nf_conntrack.h>
2322
#include <net/netfilter/nf_nat.h>
@@ -27,147 +26,6 @@
2726
#include <net/netfilter/nf_nat_l3proto.h>
2827
#include <net/ip.h>
2928

30-
struct nft_nat {
31-
enum nft_registers sreg_addr_min:8;
32-
enum nft_registers sreg_addr_max:8;
33-
enum nft_registers sreg_proto_min:8;
34-
enum nft_registers sreg_proto_max:8;
35-
enum nf_nat_manip_type type;
36-
};
37-
38-
static void nft_nat_eval(const struct nft_expr *expr,
39-
struct nft_data data[NFT_REG_MAX + 1],
40-
const struct nft_pktinfo *pkt)
41-
{
42-
const struct nft_nat *priv = nft_expr_priv(expr);
43-
enum ip_conntrack_info ctinfo;
44-
struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
45-
struct nf_nat_range range;
46-
47-
memset(&range, 0, sizeof(range));
48-
if (priv->sreg_addr_min) {
49-
range.min_addr.ip = data[priv->sreg_addr_min].data[0];
50-
range.max_addr.ip = data[priv->sreg_addr_max].data[0];
51-
range.flags |= NF_NAT_RANGE_MAP_IPS;
52-
}
53-
54-
if (priv->sreg_proto_min) {
55-
range.min_proto.all = data[priv->sreg_proto_min].data[0];
56-
range.max_proto.all = data[priv->sreg_proto_max].data[0];
57-
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
58-
}
59-
60-
data[NFT_REG_VERDICT].verdict =
61-
nf_nat_setup_info(ct, &range, priv->type);
62-
}
63-
64-
static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
65-
[NFTA_NAT_ADDR_MIN] = { .type = NLA_U32 },
66-
[NFTA_NAT_ADDR_MAX] = { .type = NLA_U32 },
67-
[NFTA_NAT_PROTO_MIN] = { .type = NLA_U32 },
68-
[NFTA_NAT_PROTO_MAX] = { .type = NLA_U32 },
69-
[NFTA_NAT_TYPE] = { .type = NLA_U32 },
70-
};
71-
72-
static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
73-
const struct nlattr * const tb[])
74-
{
75-
struct nft_nat *priv = nft_expr_priv(expr);
76-
int err;
77-
78-
if (tb[NFTA_NAT_TYPE] == NULL)
79-
return -EINVAL;
80-
81-
switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
82-
case NFT_NAT_SNAT:
83-
priv->type = NF_NAT_MANIP_SRC;
84-
break;
85-
case NFT_NAT_DNAT:
86-
priv->type = NF_NAT_MANIP_DST;
87-
break;
88-
default:
89-
return -EINVAL;
90-
}
91-
92-
if (tb[NFTA_NAT_ADDR_MIN]) {
93-
priv->sreg_addr_min = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MIN]));
94-
err = nft_validate_input_register(priv->sreg_addr_min);
95-
if (err < 0)
96-
return err;
97-
}
98-
99-
if (tb[NFTA_NAT_ADDR_MAX]) {
100-
priv->sreg_addr_max = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MAX]));
101-
err = nft_validate_input_register(priv->sreg_addr_max);
102-
if (err < 0)
103-
return err;
104-
} else
105-
priv->sreg_addr_max = priv->sreg_addr_min;
106-
107-
if (tb[NFTA_NAT_PROTO_MIN]) {
108-
priv->sreg_proto_min = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MIN]));
109-
err = nft_validate_input_register(priv->sreg_proto_min);
110-
if (err < 0)
111-
return err;
112-
}
113-
114-
if (tb[NFTA_NAT_PROTO_MAX]) {
115-
priv->sreg_proto_max = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MAX]));
116-
err = nft_validate_input_register(priv->sreg_proto_max);
117-
if (err < 0)
118-
return err;
119-
} else
120-
priv->sreg_proto_max = priv->sreg_proto_min;
121-
122-
return 0;
123-
}
124-
125-
static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
126-
{
127-
const struct nft_nat *priv = nft_expr_priv(expr);
128-
129-
switch (priv->type) {
130-
case NF_NAT_MANIP_SRC:
131-
if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
132-
goto nla_put_failure;
133-
break;
134-
case NF_NAT_MANIP_DST:
135-
if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
136-
goto nla_put_failure;
137-
break;
138-
}
139-
140-
if (nla_put_be32(skb, NFTA_NAT_ADDR_MIN, htonl(priv->sreg_addr_min)))
141-
goto nla_put_failure;
142-
if (nla_put_be32(skb, NFTA_NAT_ADDR_MAX, htonl(priv->sreg_addr_max)))
143-
goto nla_put_failure;
144-
if (nla_put_be32(skb, NFTA_NAT_PROTO_MIN, htonl(priv->sreg_proto_min)))
145-
goto nla_put_failure;
146-
if (nla_put_be32(skb, NFTA_NAT_PROTO_MAX, htonl(priv->sreg_proto_max)))
147-
goto nla_put_failure;
148-
return 0;
149-
150-
nla_put_failure:
151-
return -1;
152-
}
153-
154-
static struct nft_expr_type nft_nat_type;
155-
static const struct nft_expr_ops nft_nat_ops = {
156-
.type = &nft_nat_type,
157-
.size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
158-
.eval = nft_nat_eval,
159-
.init = nft_nat_init,
160-
.dump = nft_nat_dump,
161-
};
162-
163-
static struct nft_expr_type nft_nat_type __read_mostly = {
164-
.name = "nat",
165-
.ops = &nft_nat_ops,
166-
.policy = nft_nat_policy,
167-
.maxattr = NFTA_NAT_MAX,
168-
.owner = THIS_MODULE,
169-
};
170-
17129
/*
17230
* NAT chains
17331
*/
@@ -306,7 +164,7 @@ static unsigned int nf_nat_output(const struct nf_hook_ops *ops,
306164
return ret;
307165
}
308166

309-
struct nf_chain_type nft_chain_nat_ipv4 = {
167+
static struct nf_chain_type nft_chain_nat_ipv4 = {
310168
.family = NFPROTO_IPV4,
311169
.name = "nat",
312170
.type = NFT_CHAIN_T_NAT,
@@ -331,20 +189,11 @@ static int __init nft_chain_nat_init(void)
331189
if (err < 0)
332190
return err;
333191

334-
err = nft_register_expr(&nft_nat_type);
335-
if (err < 0)
336-
goto err;
337-
338192
return 0;
339-
340-
err:
341-
nft_unregister_chain_type(&nft_chain_nat_ipv4);
342-
return err;
343193
}
344194

345195
static void __exit nft_chain_nat_exit(void)
346196
{
347-
nft_unregister_expr(&nft_nat_type);
348197
nft_unregister_chain_type(&nft_chain_nat_ipv4);
349198
}
350199

@@ -354,4 +203,3 @@ module_exit(nft_chain_nat_exit);
354203
MODULE_LICENSE("GPL");
355204
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
356205
MODULE_ALIAS_NFT_CHAIN(AF_INET, "nat");
357-
MODULE_ALIAS_NFT_EXPR("nat");

net/ipv6/netfilter/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ config NFT_CHAIN_ROUTE_IPV6
3333
depends on NF_TABLES_IPV6
3434
tristate "IPv6 nf_tables route chain support"
3535

36+
config NFT_CHAIN_NAT_IPV6
37+
depends on NF_TABLES_IPV6
38+
depends on NF_NAT_IPV6 && NFT_NAT
39+
tristate "IPv6 nf_tables nat chain support"
40+
3641
config IP6_NF_IPTABLES
3742
tristate "IP6 tables support (required for filtering)"
3843
depends on INET && IPV6

net/ipv6/netfilter/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
2626
# nf_tables
2727
obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
2828
obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
29+
obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
2930

3031
# matches
3132
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o

0 commit comments

Comments
 (0)