Support was recently added to nft_nat to allow shifting port-ranges during NAT. Extend this support to allow them to used in redirecting as well. Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_nat_redirect.c | 1 + net/netfilter/nft_redir.c | 23 ++++++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 08780ed008c7..c737e8583274 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1490,12 +1490,14 @@ enum nft_masq_attributes { * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) * @NFTA_REDIR_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) * @NFTA_REDIR_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_REDIR_REG_PROTO_BASE: source register of proto range base offset (NLA_U32: nft_registers) */ enum nft_redir_attributes { NFTA_REDIR_UNSPEC, NFTA_REDIR_REG_PROTO_MIN, NFTA_REDIR_REG_PROTO_MAX, NFTA_REDIR_FLAGS, + NFTA_REDIR_REG_PROTO_BASE, __NFTA_REDIR_MAX }; #define NFTA_REDIR_MAX (__NFTA_REDIR_MAX - 1) diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c index 6616ba5d0b04..ff58b563ef99 100644 --- a/net/netfilter/nf_nat_redirect.c +++ b/net/netfilter/nf_nat_redirect.c @@ -42,6 +42,7 @@ nf_nat_redirect(struct sk_buff *skb, const struct nf_nat_range2 *range, newrange.max_addr = *newdst; 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_DST); } diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c index a70196ffcb1e..bd9b802c1d64 100644 --- a/net/netfilter/nft_redir.c +++ b/net/netfilter/nft_redir.c @@ -16,12 +16,14 @@ struct nft_redir { u8 sreg_proto_min; u8 sreg_proto_max; + u8 sreg_proto_base; u16 flags; }; static const struct nla_policy nft_redir_policy[NFTA_REDIR_MAX + 1] = { [NFTA_REDIR_REG_PROTO_MIN] = { .type = NLA_U32 }, [NFTA_REDIR_REG_PROTO_MAX] = { .type = NLA_U32 }, + [NFTA_REDIR_REG_PROTO_BASE] = { .type = NLA_U32 }, [NFTA_REDIR_FLAGS] = { .type = NLA_U32 }, }; @@ -48,7 +50,7 @@ static int nft_redir_init(const struct nft_ctx *ctx, unsigned int plen; int err; - plen = sizeof_field(struct nf_nat_range, min_proto.all); + plen = sizeof_field(struct nf_nat_range2, min_proto.all); if (tb[NFTA_REDIR_REG_PROTO_MIN]) { err = nft_parse_register_load(tb[NFTA_REDIR_REG_PROTO_MIN], &priv->sreg_proto_min, plen); @@ -61,6 +63,16 @@ static int nft_redir_init(const struct nft_ctx *ctx, plen); if (err < 0) return err; + + if (tb[NFTA_REDIR_REG_PROTO_BASE]) { + err = nft_parse_register_load + (tb[NFTA_REDIR_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; } @@ -89,6 +101,11 @@ static int nft_redir_dump(struct sk_buff *skb, if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MAX, priv->sreg_proto_max)) goto nla_put_failure; + + if (priv->sreg_proto_base) + if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_BASE, + priv->sreg_proto_base)) + goto nla_put_failure; } if (priv->flags != 0 && @@ -115,6 +132,10 @@ static void nft_redir_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