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

netfilter: nft_masq: support port range

Complete masquerading support by allowing port range selection.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+58 -13
+3 -1
include/net/netfilter/nft_masq.h
··· 2 2 #define _NFT_MASQ_H_ 3 3 4 4 struct nft_masq { 5 - u32 flags; 5 + u32 flags; 6 + enum nft_registers sreg_proto_min:8; 7 + enum nft_registers sreg_proto_max:8; 6 8 }; 7 9 8 10 extern const struct nla_policy nft_masq_policy[];
+4
include/uapi/linux/netfilter/nf_tables.h
··· 951 951 * enum nft_masq_attributes - nf_tables masquerade expression attributes 952 952 * 953 953 * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) 954 + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) 955 + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) 954 956 */ 955 957 enum nft_masq_attributes { 956 958 NFTA_MASQ_UNSPEC, 957 959 NFTA_MASQ_FLAGS, 960 + NFTA_MASQ_REG_PROTO_MIN, 961 + NFTA_MASQ_REG_PROTO_MAX, 958 962 __NFTA_MASQ_MAX 959 963 }; 960 964 #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)
+6 -1
net/ipv4/netfilter/nft_masq_ipv4.c
··· 25 25 26 26 memset(&range, 0, sizeof(range)); 27 27 range.flags = priv->flags; 28 - 28 + if (priv->sreg_proto_min) { 29 + range.min_proto.all = 30 + *(__be16 *)&regs->data[priv->sreg_proto_min]; 31 + range.max_proto.all = 32 + *(__be16 *)&regs->data[priv->sreg_proto_max]; 33 + } 29 34 regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook, 30 35 &range, pkt->out); 31 36 }
+6 -1
net/ipv6/netfilter/nft_masq_ipv6.c
··· 26 26 27 27 memset(&range, 0, sizeof(range)); 28 28 range.flags = priv->flags; 29 - 29 + if (priv->sreg_proto_min) { 30 + range.min_proto.all = 31 + *(__be16 *)&regs->data[priv->sreg_proto_min]; 32 + range.max_proto.all = 33 + *(__be16 *)&regs->data[priv->sreg_proto_max]; 34 + } 30 35 regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); 31 36 } 32 37
+39 -10
net/netfilter/nft_masq.c
··· 17 17 #include <net/netfilter/nft_masq.h> 18 18 19 19 const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { 20 - [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, 20 + [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, 21 + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, 22 + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, 21 23 }; 22 24 EXPORT_SYMBOL_GPL(nft_masq_policy); 23 25 ··· 42 40 const struct nft_expr *expr, 43 41 const struct nlattr * const tb[]) 44 42 { 43 + u32 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all); 45 44 struct nft_masq *priv = nft_expr_priv(expr); 46 45 int err; 47 46 ··· 50 47 if (err) 51 48 return err; 52 49 53 - if (tb[NFTA_MASQ_FLAGS] == NULL) 54 - return 0; 50 + if (tb[NFTA_MASQ_FLAGS]) { 51 + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); 52 + if (priv->flags & ~NF_NAT_RANGE_MASK) 53 + return -EINVAL; 54 + } 55 55 56 - priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); 57 - if (priv->flags & ~NF_NAT_RANGE_MASK) 58 - return -EINVAL; 56 + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { 57 + priv->sreg_proto_min = 58 + nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]); 59 + 60 + err = nft_validate_register_load(priv->sreg_proto_min, plen); 61 + if (err < 0) 62 + return err; 63 + 64 + if (tb[NFTA_MASQ_REG_PROTO_MAX]) { 65 + priv->sreg_proto_max = 66 + nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]); 67 + 68 + err = nft_validate_register_load(priv->sreg_proto_max, 69 + plen); 70 + if (err < 0) 71 + return err; 72 + } else { 73 + priv->sreg_proto_max = priv->sreg_proto_min; 74 + } 75 + } 59 76 60 77 return 0; 61 78 } ··· 85 62 { 86 63 const struct nft_masq *priv = nft_expr_priv(expr); 87 64 88 - if (priv->flags == 0) 89 - return 0; 90 - 91 - if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) 65 + if (priv->flags != 0 && 66 + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) 92 67 goto nla_put_failure; 68 + 69 + if (priv->sreg_proto_min) { 70 + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, 71 + priv->sreg_proto_min) || 72 + nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX, 73 + priv->sreg_proto_max)) 74 + goto nla_put_failure; 75 + } 93 76 94 77 return 0; 95 78