]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft-shared: support native tcp port range delinearize
authorFlorian Westphal <fw@strlen.de>
Tue, 25 Jan 2022 16:52:56 +0000 (17:52 +0100)
committerFlorian Westphal <fw@strlen.de>
Sat, 29 Jan 2022 12:36:25 +0000 (13:36 +0100)
adds support for
nft ... tcp dport != min-max

Signed-off-by: Florian Westphal <fw@strlen.de>
iptables/nft-shared.c
iptables/nft-shared.h
iptables/nft.c

index 061893cf876d1ec5fc0bcb9d4fda71ab94adee81..6989a29f45e118875a67d6816a16af0c50eb52f2 100644 (file)
@@ -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);
        }
index 0a8be7099aa20d47ab4d793925a7a8ca311b4603..1468d560815815dd55a99d0a54ea1eda2296f121 100644 (file)
@@ -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 {
index b5de687c5c4cd2993648671783323456154f19f5..f7f5950625d040c46c513909b7acce54bf58b677 100644 (file)
@@ -3529,6 +3529,7 @@ static const char *supported_exprs[] = {
        "counter",
        "immediate",
        "lookup",
+       "range",
 };