@@ -1434,6 +1434,7 @@ enum nft_nat_types {
* @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
* @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
* @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ * @NFTA_NAT_REG_PROTO_BASE: source register of proto range base offset (NLA_U32: nft_registers)
*/
enum nft_nat_attributes {
NFTA_NAT_UNSPEC,
@@ -1444,6 +1445,7 @@ enum nft_nat_attributes {
NFTA_NAT_REG_PROTO_MIN,
NFTA_NAT_REG_PROTO_MAX,
NFTA_NAT_FLAGS,
+ NFTA_NAT_REG_PROTO_BASE,
__NFTA_NAT_MAX
};
#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
@@ -25,6 +25,7 @@ struct nft_nat {
u8 sreg_addr_max;
u8 sreg_proto_min;
u8 sreg_proto_max;
+ u8 sreg_proto_base;
enum nf_nat_manip_type type:8;
u8 family;
u16 flags;
@@ -58,6 +59,10 @@ static void nft_nat_setup_proto(struct nf_nat_range2 *range,
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]);
}
static void nft_nat_setup_netmap(struct nf_nat_range2 *range,
@@ -126,13 +131,14 @@ static void nft_nat_eval(const struct nft_expr *expr,
}
static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
- [NFTA_NAT_TYPE] = { .type = NLA_U32 },
- [NFTA_NAT_FAMILY] = { .type = NLA_U32 },
- [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 },
- [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 },
- [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
- [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
- [NFTA_NAT_FLAGS] = { .type = NLA_U32 },
+ [NFTA_NAT_TYPE] = { .type = NLA_U32 },
+ [NFTA_NAT_FAMILY] = { .type = NLA_U32 },
+ [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 },
+ [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 },
+ [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
+ [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
+ [NFTA_NAT_REG_PROTO_BASE] = { .type = NLA_U32 },
+ [NFTA_NAT_FLAGS] = { .type = NLA_U32 },
};
static int nft_nat_validate(const struct nft_ctx *ctx,
@@ -195,10 +201,10 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
switch (family) {
case NFPROTO_IPV4:
- alen = sizeof_field(struct nf_nat_range, min_addr.ip);
+ alen = sizeof_field(struct nf_nat_range2, min_addr.ip);
break;
case NFPROTO_IPV6:
- alen = sizeof_field(struct nf_nat_range, min_addr.ip6);
+ alen = sizeof_field(struct nf_nat_range2, min_addr.ip6);
break;
default:
if (tb[NFTA_NAT_REG_ADDR_MIN])
@@ -226,7 +232,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
priv->flags |= NF_NAT_RANGE_MAP_IPS;
}
- plen = sizeof_field(struct nf_nat_range, min_proto.all);
+ plen = sizeof_field(struct nf_nat_range2, min_proto.all);
if (tb[NFTA_NAT_REG_PROTO_MIN]) {
err = nft_parse_register_load(tb[NFTA_NAT_REG_PROTO_MIN],
&priv->sreg_proto_min, plen);
@@ -239,6 +245,16 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
plen);
if (err < 0)
return err;
+
+ if (tb[NFTA_NAT_REG_PROTO_BASE]) {
+ err = nft_parse_register_load
+ (tb[NFTA_NAT_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;
}
@@ -288,6 +304,11 @@ static int nft_nat_dump(struct sk_buff *skb,
nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX,
priv->sreg_proto_max))
goto nla_put_failure;
+
+ if (priv->sreg_proto_base)
+ if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_BASE,
+ priv->sreg_proto_base))
+ goto nla_put_failure;
}
if (priv->flags != 0) {
Commit 2eb0f624b709 ("netfilter: add NAT support for shifted portmap ranges") introduced support for shifting port-ranges in NAT. This allows one to redirect packets intended for one port to another in a range in such a way that the new port chosen has the same offset in the range as the original port had from a specified base value. For example, by using the base value 2000, one could redirect packets intended for 10.0.0.1:2000-3000 to 10.10.0.1:12000-13000 so that the old and new ports were at the same offset in their respective ranges, i.e.: 10.0.0.1:2345 -> 10.10.0.1:12345 However, while support for this was added to the common NAT infra- structure, only the xt_nat module was updated to make use of it. This commit updates the nft_nat module to allow shifted port-ranges to be used by nftables. In contrast to xt_nat, where shifting is only available for DNAT, both DNAT and SNAT are supported. Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=970672 Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1501 Signed-off-by: Jeremy Sowden <jeremy@azazel.net> --- include/uapi/linux/netfilter/nf_tables.h | 2 ++ net/netfilter/nft_nat.c | 41 ++++++++++++++++++------ 2 files changed, 33 insertions(+), 10 deletions(-)