Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a6bf5da authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nft_masq: support port range



Complete masquerading support by allowing port range selection.

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent af4610c3
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@

struct nft_masq {
	u32			flags;
	enum nft_registers      sreg_proto_min:8;
	enum nft_registers      sreg_proto_max:8;
};

extern const struct nla_policy nft_masq_policy[];
+4 −0
Original line number Diff line number Diff line
@@ -951,10 +951,14 @@ enum nft_nat_attributes {
 * enum nft_masq_attributes - nf_tables masquerade expression 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)
 */
enum nft_masq_attributes {
	NFTA_MASQ_UNSPEC,
	NFTA_MASQ_FLAGS,
	NFTA_MASQ_REG_PROTO_MIN,
	NFTA_MASQ_REG_PROTO_MAX,
	__NFTA_MASQ_MAX
};
#define NFTA_MASQ_MAX		(__NFTA_MASQ_MAX - 1)
+6 −1
Original line number Diff line number Diff line
@@ -25,7 +25,12 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr,

	memset(&range, 0, sizeof(range));
	range.flags = priv->flags;

	if (priv->sreg_proto_min) {
		range.min_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_min];
		range.max_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_max];
	}
	regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook,
						    &range, pkt->out);
}
+6 −1
Original line number Diff line number Diff line
@@ -26,7 +26,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,

	memset(&range, 0, sizeof(range));
	range.flags = priv->flags;

	if (priv->sreg_proto_min) {
		range.min_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_min];
		range.max_proto.all =
			*(__be16 *)&regs->data[priv->sreg_proto_max];
	}
	regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
}

+40 −11
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

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 },
};
EXPORT_SYMBOL_GPL(nft_masq_policy);

@@ -40,6 +42,7 @@ int nft_masq_init(const struct nft_ctx *ctx,
		  const struct nft_expr *expr,
		  const struct nlattr * const tb[])
{
	u32 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
	struct nft_masq *priv = nft_expr_priv(expr);
	int err;

@@ -47,12 +50,32 @@ int nft_masq_init(const struct nft_ctx *ctx,
	if (err)
		return err;

	if (tb[NFTA_MASQ_FLAGS] == NULL)
		return 0;

	if (tb[NFTA_MASQ_FLAGS]) {
		priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
		if (priv->flags & ~NF_NAT_RANGE_MASK)
			return -EINVAL;
	}

	if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
		priv->sreg_proto_min =
			nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]);

		err = nft_validate_register_load(priv->sreg_proto_min, plen);
		if (err < 0)
			return err;

		if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
			priv->sreg_proto_max =
				nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]);

			err = nft_validate_register_load(priv->sreg_proto_max,
							 plen);
			if (err < 0)
				return err;
		} else {
			priv->sreg_proto_max = priv->sreg_proto_min;
		}
	}

	return 0;
}
@@ -62,11 +85,17 @@ int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
	const struct nft_masq *priv = nft_expr_priv(expr);

	if (priv->flags == 0)
		return 0;
	if (priv->flags != 0 &&
	    nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
		goto nla_put_failure;

	if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
	if (priv->sreg_proto_min) {
		if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
				      priv->sreg_proto_min) ||
		    nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
				      priv->sreg_proto_max))
			goto nla_put_failure;
	}

	return 0;