summaryrefslogtreecommitdiffstats
path: root/iptables/nft-shared.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2022-01-25 17:52:56 +0100
committerFlorian Westphal <fw@strlen.de>2022-01-29 13:36:25 +0100
commit5795a1b5b611fbf7a64be34b2675f88e8f9bbaef (patch)
tree5893e51e1eed0602d6abe365250e43da697787ee /iptables/nft-shared.c
parent250dce876d924b9467ffa035af445912e86ea93b (diff)
nft-shared: support native tcp port range delinearize
adds support for nft ... tcp dport != min-max Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'iptables/nft-shared.c')
-rw-r--r--iptables/nft-shared.c115
1 files changed, 114 insertions, 1 deletions
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 061893cf..6989a29f 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -513,6 +513,43 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
return tcp;
}
+static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
+
+ if (!tcp)
+ return;
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ tcp->invflags |= XT_TCP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ tcp->spts[0] = sport_from;
+ tcp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->dpts[0] = dport_from;
+ tcp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
+
static void nft_parse_tcp(struct nft_xt_ctx *ctx,
struct iptables_command_state *cs,
int sport, int dport,
@@ -584,8 +621,22 @@ static void nft_parse_th_port(struct nft_xt_ctx *ctx,
}
}
+static void nft_parse_th_port_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_TCP:
+ nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
+ }
+}
+
+
static void nft_parse_transport(struct nft_xt_ctx *ctx,
- struct nftnl_expr *e, void *data)
+ struct nftnl_expr *e, void *data)
{
struct iptables_command_state *cs = data;
uint32_t sdport;
@@ -632,6 +683,47 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx,
}
}
+static void nft_parse_transport_range(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e,
+ struct iptables_command_state *cs)
+{
+ unsigned int len_from, len_to;
+ uint8_t proto, op;
+ uint16_t from, to;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_from);
+ nftnl_expr_get(e, NFTNL_EXPR_RANGE_FROM_DATA, &len_to);
+ if (len_to != len_from || len_to != 2)
+ return;
+
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_OP);
+
+ from = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_FROM_DATA));
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+
+ switch(ctx->payload.offset) {
+ case 0:
+ nft_parse_th_port_range(ctx, cs, proto, from, to, -1, -1, op);
+ return;
+ case 2:
+ to = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_RANGE_TO_DATA));
+ nft_parse_th_port_range(ctx, cs, proto, -1, -1, from, to, op);
+ return;
+ }
+}
+
static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
void *data = ctx->cs;
@@ -811,6 +903,25 @@ static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h,
ctx->h->ops->parse_lookup(ctx, e, NULL);
}
+static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
+{
+ uint32_t reg;
+
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_RANGE_SREG);
+ if (reg != ctx->reg)
+ return;
+
+ if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
+ switch (ctx->payload.base) {
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_parse_transport_range(ctx, e, ctx->cs);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs)
@@ -855,6 +966,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h,
nft_parse_lookup(&ctx, h, expr);
else if (strcmp(name, "log") == 0)
nft_parse_log(&ctx, expr);
+ else if (strcmp(name, "range") == 0)
+ nft_parse_range(&ctx, expr);
expr = nftnl_expr_iter_next(iter);
}