adds support for nft ... tcp dport != min-max Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- iptables/nft-shared.c | 113 ++++++++++++++++++++++++++++++++++++++++++ iptables/nft-shared.h | 1 + iptables/nft.c | 1 + 3 files changed, 115 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 674c72b35ae7..7f6b4ff392d9 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_complete_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_complete_tcp(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, int sport, int dport, @@ -584,6 +621,20 @@ static void nft_complete_th_port(struct nft_xt_ctx *ctx, } } +static void nft_complete_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_complete_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; + } +} + + static void nft_complete_transport(struct nft_xt_ctx *ctx, struct nftnl_expr *e, void *data) { @@ -632,6 +683,47 @@ static void nft_complete_transport(struct nft_xt_ctx *ctx, } } +static void nft_complete_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_complete_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_complete_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_complete_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 0a8be7099aa2..1468d5608158 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 b5de687c5c4c..f7f5950625d0 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -3529,6 +3529,7 @@ static const char *supported_exprs[] = { "counter", "immediate", "lookup", + "range", }; -- 2.34.1