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

netfilter: nft_nat: include a flag attribute

Both SNAT and DNAT (and the upcoming masquerade) can have additional
configuration parameters, such as port randomization and NAT addressing
persistence. We can cover these scenarios by simply adding a flag
attribute for userspace to fill when needed.

The flags to use are defined in include/uapi/linux/netfilter/nf_nat.h:

NF_NAT_RANGE_MAP_IPS
NF_NAT_RANGE_PROTO_SPECIFIED
NF_NAT_RANGE_PROTO_RANDOM
NF_NAT_RANGE_PERSISTENT
NF_NAT_RANGE_PROTO_RANDOM_FULLY
NF_NAT_RANGE_PROTO_RANDOM_ALL

The caller must take care of not messing up with the flags, as they are
added unconditionally to the final resulting nf_nat_range.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Arturo Borrero and committed by
Pablo Neira Ayuso
e42eff8a b9ac12ef

+23
+5
include/uapi/linux/netfilter/nf_nat.h
··· 13 13 #define NF_NAT_RANGE_PROTO_RANDOM_ALL \ 14 14 (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY) 15 15 16 + #define NF_NAT_RANGE_MASK \ 17 + (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \ 18 + NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \ 19 + NF_NAT_RANGE_PROTO_RANDOM_FULLY) 20 + 16 21 struct nf_nat_ipv4_range { 17 22 unsigned int flags; 18 23 __be32 min_ip;
+2
include/uapi/linux/netfilter/nf_tables.h
··· 785 785 * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers) 786 786 * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) 787 787 * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) 788 + * @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) 788 789 */ 789 790 enum nft_nat_attributes { 790 791 NFTA_NAT_UNSPEC, ··· 795 794 NFTA_NAT_REG_ADDR_MAX, 796 795 NFTA_NAT_REG_PROTO_MIN, 797 796 NFTA_NAT_REG_PROTO_MAX, 797 + NFTA_NAT_FLAGS, 798 798 __NFTA_NAT_MAX 799 799 }; 800 800 #define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
+16
net/netfilter/nft_nat.c
··· 33 33 enum nft_registers sreg_proto_max:8; 34 34 enum nf_nat_manip_type type:8; 35 35 u8 family; 36 + u16 flags; 36 37 }; 37 38 38 39 static void nft_nat_eval(const struct nft_expr *expr, ··· 72 71 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 73 72 } 74 73 74 + range.flags |= priv->flags; 75 + 75 76 data[NFT_REG_VERDICT].verdict = 76 77 nf_nat_setup_info(ct, &range, priv->type); 77 78 } ··· 85 82 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 86 83 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 87 84 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 85 + [NFTA_NAT_FLAGS] = { .type = NLA_U32 }, 88 86 }; 89 87 90 88 static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, ··· 153 149 } else 154 150 priv->sreg_proto_max = priv->sreg_proto_min; 155 151 152 + if (tb[NFTA_NAT_FLAGS]) { 153 + priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); 154 + if (priv->flags & ~NF_NAT_RANGE_MASK) 155 + return -EINVAL; 156 + } 157 + 156 158 return 0; 157 159 } 158 160 ··· 193 183 htonl(priv->sreg_proto_max))) 194 184 goto nla_put_failure; 195 185 } 186 + 187 + if (priv->flags != 0) { 188 + if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags))) 189 + goto nla_put_failure; 190 + } 191 + 196 192 return 0; 197 193 198 194 nla_put_failure: