]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft-shared: Lookup matches in iptables_command_state
authorPhil Sutter <phil@nwl.cc>
Thu, 16 Feb 2023 20:55:54 +0000 (21:55 +0100)
committerPhil Sutter <phil@nwl.cc>
Fri, 17 Feb 2023 17:18:48 +0000 (18:18 +0100)
Some matches may turn into multiple nft statements (naturally or via
translation). Such statements must parse into a single extension again
in order to rebuild the rule as it was.

Introduce nft_find_match_in_cs() to iterate through the lists and drop
tcp/udp port match caching in struct nft_xt_ctx which is not needed
anymore.

Note: Match reuse is not enabled unconditionally for all matches,
because iptables supports having multiple instances of the same
extension.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-shared.c
iptables/nft-shared.h

index 4a7b5406892c4a1799ef629db109cb5b7674342d..df3cc6ac994cf19801b3e0d5f2b4f7b83b1dd698 100644 (file)
@@ -304,7 +304,7 @@ static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned
 static struct xtables_match *
 nft_create_match(struct nft_xt_ctx *ctx,
                 struct iptables_command_state *cs,
-                const char *name);
+                const char *name, bool reuse);
 
 static uint32_t get_meta_mask(struct nft_xt_ctx *ctx, enum nft_registers sreg)
 {
@@ -322,7 +322,7 @@ static int parse_meta_mark(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
        struct xtables_match *match;
        uint32_t value;
 
-       match = nft_create_match(ctx, ctx->cs, "mark");
+       match = nft_create_match(ctx, ctx->cs, "mark", false);
        if (!match)
                return -1;
 
@@ -344,7 +344,7 @@ static int parse_meta_pkttype(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
        struct xtables_match *match;
        uint8_t value;
 
-       match = nft_create_match(ctx, ctx->cs, "pkttype");
+       match = nft_create_match(ctx, ctx->cs, "pkttype", false);
        if (!match)
                return -1;
 
@@ -641,15 +641,39 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
        dreg->bitwise.set = true;
 }
 
+static struct xtables_match *
+nft_find_match_in_cs(struct iptables_command_state *cs, const char *name)
+{
+       struct xtables_rule_match *rm;
+       struct ebt_match *ebm;
+
+       for (ebm = cs->match_list; ebm; ebm = ebm->next) {
+               if (ebm->ismatch &&
+                   !strcmp(ebm->u.match->m->u.user.name, name))
+                       return ebm->u.match;
+       }
+       for (rm = cs->matches; rm; rm = rm->next) {
+               if (!strcmp(rm->match->m->u.user.name, name))
+                       return rm->match;
+       }
+       return NULL;
+}
+
 static struct xtables_match *
 nft_create_match(struct nft_xt_ctx *ctx,
                 struct iptables_command_state *cs,
-                const char *name)
+                const char *name, bool reuse)
 {
        struct xtables_match *match;
        struct xt_entry_match *m;
        unsigned int size;
 
+       if (reuse) {
+               match = nft_find_match_in_cs(cs, name);
+               if (match)
+                       return match;
+       }
+
        match = xtables_find_match(name, XTF_TRY_LOAD,
                                   &cs->matches);
        if (!match)
@@ -671,38 +695,26 @@ nft_create_match(struct nft_xt_ctx *ctx,
 static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx,
                                    struct iptables_command_state *cs)
 {
-       struct xt_udp *udp = ctx->tcpudp.udp;
        struct xtables_match *match;
 
-       if (!udp) {
-               match = nft_create_match(ctx, cs, "udp");
-               if (!match)
-                       return NULL;
-
-               udp = (void*)match->m->data;
-               ctx->tcpudp.udp = udp;
-       }
+       match = nft_create_match(ctx, cs, "udp", true);
+       if (!match)
+               return NULL;
 
-       return udp;
+       return (struct xt_udp *)match->m->data;
 }
 
 static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
                                    struct iptables_command_state *cs)
 {
-       struct xt_tcp *tcp = ctx->tcpudp.tcp;
        struct xtables_match *match;
 
-       if (!tcp) {
-               match = nft_create_match(ctx, cs, "tcp");
-               if (!match) {
-                       ctx->errmsg = "tcp match extension not found";
-                       return NULL;
-               }
-               tcp = (void*)match->m->data;
-               ctx->tcpudp.tcp = tcp;
+       match = nft_create_match(ctx, cs, "tcp", true);
+       if (!match) {
+               ctx->errmsg = "tcp match extension not found";
+               return NULL;
        }
-
-       return tcp;
+       return (struct xt_tcp *)match->m->data;
 }
 
 static void nft_parse_udp_range(struct nft_xt_ctx *ctx,
@@ -872,14 +884,14 @@ static void nft_parse_icmp(struct nft_xt_ctx *ctx,
 
        switch (ctx->h->family) {
        case NFPROTO_IPV4:
-               match = nft_create_match(ctx, cs, "icmp");
+               match = nft_create_match(ctx, cs, "icmp", false);
                break;
        case NFPROTO_IPV6:
                if (icmp.type == UINT8_MAX) {
                        ctx->errmsg = "icmp6 code with any type match not supported";
                        return;
                }
-               match = nft_create_match(ctx, cs, "icmp6");
+               match = nft_create_match(ctx, cs, "icmp6", false);
                break;
        default:
                ctx->errmsg = "unexpected family for icmp match";
@@ -1640,10 +1652,10 @@ int nft_parse_hl(struct nft_xt_ctx *ctx,
         */
        switch (ctx->h->family) {
        case NFPROTO_IPV4:
-               match = nft_create_match(ctx, ctx->cs, "ttl");
+               match = nft_create_match(ctx, ctx->cs, "ttl", false);
                break;
        case NFPROTO_IPV6:
-               match = nft_create_match(ctx, ctx->cs, "hl");
+               match = nft_create_match(ctx, ctx->cs, "hl", false);
                break;
        default:
                return -1;
index 07d39131cb0d6eda38410fd0bde67dfd0411672d..b8bc1a6ce2e9398ad39d00002d53e6869d41ffde 100644 (file)
@@ -76,10 +76,6 @@ struct nft_xt_ctx {
        struct nft_handle *h;
        uint32_t flags;
        const char *table;
-       union {
-               struct xt_tcp *tcp;
-               struct xt_udp *udp;
-       } tcpudp;
 
        struct nft_xt_ctx_reg regs[1 + 16];