Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+48 -2
+3 -1
include/uapi/linux/netfilter/nf_nat.h
··· 11 11 #define NF_NAT_RANGE_PERSISTENT (1 << 3) 12 12 #define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4) 13 13 #define NF_NAT_RANGE_PROTO_OFFSET (1 << 5) 14 + #define NF_NAT_RANGE_NETMAP (1 << 6) 14 15 15 16 #define NF_NAT_RANGE_PROTO_RANDOM_ALL \ 16 17 (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY) ··· 19 18 #define NF_NAT_RANGE_MASK \ 20 19 (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \ 21 20 NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \ 22 - NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET) 21 + NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \ 22 + NF_NAT_RANGE_NETMAP) 23 23 24 24 struct nf_nat_ipv4_range { 25 25 unsigned int flags;
+45 -1
net/netfilter/nft_nat.c
··· 60 60 nft_reg_load16(&regs->data[priv->sreg_proto_max]); 61 61 } 62 62 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 + 63 103 static void nft_nat_eval(const struct nft_expr *expr, 64 104 struct nft_regs *regs, 65 105 const struct nft_pktinfo *pkt) ··· 110 70 struct nf_nat_range2 range; 111 71 112 72 memset(&range, 0, sizeof(range)); 113 - if (priv->sreg_addr_min) 73 + 74 + if (priv->sreg_addr_min) { 114 75 nft_nat_setup_addr(&range, regs, priv); 76 + if (priv->flags & NF_NAT_RANGE_NETMAP) 77 + nft_nat_setup_netmap(&range, pkt, priv); 78 + } 115 79 116 80 if (priv->sreg_proto_min) 117 81 nft_nat_setup_proto(&range, regs, priv);