Skip to content

Commit 3ff7ddb

Browse files
committed
netfilter: nft_nat: add netmap support
This patch allows you to NAT the network address prefix onto another network address prefix, a.k.a. netmapping. Userspace must specify the NF_NAT_RANGE_NETMAP flag and the prefix address through the NFTA_NAT_REG_ADDR_MIN and NFTA_NAT_REG_ADDR_MAX netlink attributes. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent acd766e commit 3ff7ddb

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

include/uapi/linux/netfilter/nf_nat.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
1212
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
1313
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
14+
#define NF_NAT_RANGE_NETMAP (1 << 6)
1415

1516
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
1617
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
1718

1819
#define NF_NAT_RANGE_MASK \
1920
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
2021
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
21-
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET)
22+
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
23+
NF_NAT_RANGE_NETMAP)
2224

2325
struct nf_nat_ipv4_range {
2426
unsigned int flags;

net/netfilter/nft_nat.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,46 @@ static void nft_nat_setup_proto(struct nf_nat_range2 *range,
6060
nft_reg_load16(&regs->data[priv->sreg_proto_max]);
6161
}
6262

63+
static void nft_nat_setup_netmap(struct nf_nat_range2 *range,
64+
const struct nft_pktinfo *pkt,
65+
const struct nft_nat *priv)
66+
{
67+
struct sk_buff *skb = pkt->skb;
68+
union nf_inet_addr new_addr;
69+
__be32 netmask;
70+
int i, len = 0;
71+
72+
switch (priv->type) {
73+
case NFT_NAT_SNAT:
74+
if (nft_pf(pkt) == NFPROTO_IPV4) {
75+
new_addr.ip = ip_hdr(skb)->saddr;
76+
len = sizeof(struct in_addr);
77+
} else {
78+
new_addr.in6 = ipv6_hdr(skb)->saddr;
79+
len = sizeof(struct in6_addr);
80+
}
81+
break;
82+
case NFT_NAT_DNAT:
83+
if (nft_pf(pkt) == NFPROTO_IPV4) {
84+
new_addr.ip = ip_hdr(skb)->daddr;
85+
len = sizeof(struct in_addr);
86+
} else {
87+
new_addr.in6 = ipv6_hdr(skb)->daddr;
88+
len = sizeof(struct in6_addr);
89+
}
90+
break;
91+
}
92+
93+
for (i = 0; i < len / sizeof(__be32); i++) {
94+
netmask = ~(range->min_addr.ip6[i] ^ range->max_addr.ip6[i]);
95+
new_addr.ip6[i] &= ~netmask;
96+
new_addr.ip6[i] |= range->min_addr.ip6[i] & netmask;
97+
}
98+
99+
range->min_addr = new_addr;
100+
range->max_addr = new_addr;
101+
}
102+
63103
static void nft_nat_eval(const struct nft_expr *expr,
64104
struct nft_regs *regs,
65105
const struct nft_pktinfo *pkt)
@@ -70,8 +110,12 @@ static void nft_nat_eval(const struct nft_expr *expr,
70110
struct nf_nat_range2 range;
71111

72112
memset(&range, 0, sizeof(range));
73-
if (priv->sreg_addr_min)
113+
114+
if (priv->sreg_addr_min) {
74115
nft_nat_setup_addr(&range, regs, priv);
116+
if (priv->flags & NF_NAT_RANGE_NETMAP)
117+
nft_nat_setup_netmap(&range, pkt, priv);
118+
}
75119

76120
if (priv->sreg_proto_min)
77121
nft_nat_setup_proto(&range, regs, priv);

0 commit comments

Comments
 (0)