Support was recently added to nft_nat to allow shifting port-ranges during NAT. Extend this support to allow them to used in masquerading as well. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_nat_masquerade.c | 2 ++ net/netfilter/nft_masq.c | 25 +++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index af6032720c78..bab3e3c6de74 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1470,12 +1470,14 @@ enum nft_tproxy_attributes { * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_BASE: source register of proto range base offset (NLA_U32: nft_registers) */ enum nft_masq_attributes { NFTA_MASQ_UNSPEC, NFTA_MASQ_FLAGS, NFTA_MASQ_REG_PROTO_MIN, NFTA_MASQ_REG_PROTO_MAX, + NFTA_MASQ_REG_PROTO_BASE, __NFTA_MASQ_MAX }; #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) diff --git a/net/netfilter/nf_nat_masquerade.c b/net/netfilter/nf_nat_masquerade.c index 1a506b0c6511..8d40b507d4ad 100644 --- a/net/netfilter/nf_nat_masquerade.c +++ b/net/netfilter/nf_nat_masquerade.c @@ -69,6 +69,7 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, newrange.max_addr.ip = newsrc; newrange.min_proto = range->min_proto; newrange.max_proto = range->max_proto; + newrange.base_proto = range->base_proto; /* Hand modified range to generic setup. */ return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); @@ -264,6 +265,7 @@ nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range2 *range, newrange.max_addr.in6 = src; newrange.min_proto = range->min_proto; newrange.max_proto = range->max_proto; + newrange.base_proto = range->base_proto; return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); } diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c index 4bd79306eebd..4c46822e5b60 100644 --- a/net/netfilter/nft_masq.c +++ b/net/netfilter/nft_masq.c @@ -17,12 +17,14 @@ struct nft_masq { u32 flags; u8 sreg_proto_min; u8 sreg_proto_max; + u8 sreg_proto_base; }; static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_BASE] = { .type = NLA_U32 }, }; static int nft_masq_validate(const struct nft_ctx *ctx, @@ -43,7 +45,7 @@ static int nft_masq_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { - u32 plen = sizeof_field(struct nf_nat_range, min_addr.all); + u32 plen = sizeof_field(struct nf_nat_range2, min_addr.all); struct nft_masq *priv = nft_expr_priv(expr); int err; @@ -65,9 +67,21 @@ static int nft_masq_init(const struct nft_ctx *ctx, plen); if (err < 0) return err; + + if (tb[NFTA_MASQ_REG_PROTO_BASE]) { + err = nft_parse_register_load + (tb[NFTA_MASQ_REG_PROTO_BASE], + &priv->sreg_proto_base, plen); + if (err < 0) + return err; + + priv->flags |= NF_NAT_RANGE_PROTO_OFFSET; + } } else { priv->sreg_proto_max = priv->sreg_proto_min; } + + priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; } return nf_ct_netns_get(ctx->net, ctx->family); @@ -88,6 +102,11 @@ static int nft_masq_dump(struct sk_buff *skb, nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX, priv->sreg_proto_max)) goto nla_put_failure; + + if (priv->sreg_proto_base) + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_BASE, + priv->sreg_proto_base)) + goto nla_put_failure; } return 0; @@ -110,6 +129,10 @@ static void nft_masq_eval(const struct nft_expr *expr, nft_reg_load16(®s->data[priv->sreg_proto_min]); range.max_proto.all = (__force __be16) nft_reg_load16(®s->data[priv->sreg_proto_max]); + + if (priv->sreg_proto_base) + range.base_proto.all = (__force __be16) + nft_reg_load16(®s->data[priv->sreg_proto_base]); } switch (nft_pf(pkt)) { -- 2.39.2