From 5795a1b5b611fbf7a64be34b2675f88e8f9bbaef Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 25 Jan 2022 17:52:56 +0100 Subject: nft-shared: support native tcp port range delinearize adds support for nft ... tcp dport != min-max Signed-off-by: Florian Westphal --- iptables/nft-shared.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++- iptables/nft-shared.h | 1 + iptables/nft.c | 1 + 3 files changed, 116 insertions(+), 1 deletion(-) (limited to 'iptables') 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); } diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 0a8be709..1468d560 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -45,6 +45,7 @@ enum { NFT_XT_CTX_BITWISE = (1 << 2), NFT_XT_CTX_IMMEDIATE = (1 << 3), NFT_XT_CTX_PREV_PAYLOAD = (1 << 4), + NFT_XT_CTX_RANGE = (1 << 5), }; struct nft_xt_ctx { diff --git a/iptables/nft.c b/iptables/nft.c index b5de687c..f7f59506 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3529,6 +3529,7 @@ static const char *supported_exprs[] = { "counter", "immediate", "lookup", + "range", }; -- cgit v1.2.3