Skip to content

Commit 8a6bf5d

Browse files
committed
netfilter: nft_masq: support port range
Complete masquerading support by allowing port range selection. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent af4610c commit 8a6bf5d

File tree

5 files changed

+59
-14
lines changed

5 files changed

+59
-14
lines changed

include/net/netfilter/nft_masq.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#define _NFT_MASQ_H_
33

44
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;
68
};
79

810
extern const struct nla_policy nft_masq_policy[];

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,10 +951,14 @@ enum nft_nat_attributes {
951951
* enum nft_masq_attributes - nf_tables masquerade expression attributes
952952
*
953953
* @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)
954956
*/
955957
enum nft_masq_attributes {
956958
NFTA_MASQ_UNSPEC,
957959
NFTA_MASQ_FLAGS,
960+
NFTA_MASQ_REG_PROTO_MIN,
961+
NFTA_MASQ_REG_PROTO_MAX,
958962
__NFTA_MASQ_MAX
959963
};
960964
#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)

net/ipv4/netfilter/nft_masq_ipv4.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr,
2525

2626
memset(&range, 0, sizeof(range));
2727
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+
}
2934
regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook,
3035
&range, pkt->out);
3136
}

net/ipv6/netfilter/nft_masq_ipv6.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,
2626

2727
memset(&range, 0, sizeof(range));
2828
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+
}
3035
regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
3136
}
3237

net/netfilter/nft_masq.c

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include <net/netfilter/nft_masq.h>
1818

1919
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 },
2123
};
2224
EXPORT_SYMBOL_GPL(nft_masq_policy);
2325

@@ -40,19 +42,40 @@ int nft_masq_init(const struct nft_ctx *ctx,
4042
const struct nft_expr *expr,
4143
const struct nlattr * const tb[])
4244
{
45+
u32 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
4346
struct nft_masq *priv = nft_expr_priv(expr);
4447
int err;
4548

4649
err = nft_masq_validate(ctx, expr, NULL);
4750
if (err)
4851
return err;
4952

50-
if (tb[NFTA_MASQ_FLAGS] == NULL)
51-
return 0;
52-
53-
priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
54-
if (priv->flags & ~NF_NAT_RANGE_MASK)
55-
return -EINVAL;
53+
if (tb[NFTA_MASQ_FLAGS]) {
54+
priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
55+
if (priv->flags & ~NF_NAT_RANGE_MASK)
56+
return -EINVAL;
57+
}
58+
59+
if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
60+
priv->sreg_proto_min =
61+
nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]);
62+
63+
err = nft_validate_register_load(priv->sreg_proto_min, plen);
64+
if (err < 0)
65+
return err;
66+
67+
if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
68+
priv->sreg_proto_max =
69+
nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]);
70+
71+
err = nft_validate_register_load(priv->sreg_proto_max,
72+
plen);
73+
if (err < 0)
74+
return err;
75+
} else {
76+
priv->sreg_proto_max = priv->sreg_proto_min;
77+
}
78+
}
5679

5780
return 0;
5881
}
@@ -62,12 +85,18 @@ int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
6285
{
6386
const struct nft_masq *priv = nft_expr_priv(expr);
6487

65-
if (priv->flags == 0)
66-
return 0;
67-
68-
if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
88+
if (priv->flags != 0 &&
89+
nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
6990
goto nla_put_failure;
7091

92+
if (priv->sreg_proto_min) {
93+
if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
94+
priv->sreg_proto_min) ||
95+
nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
96+
priv->sreg_proto_max))
97+
goto nla_put_failure;
98+
}
99+
71100
return 0;
72101

73102
nla_put_failure:

0 commit comments

Comments
 (0)