]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
exthdr: fix tcpopt_find_template to use length after mask adjustment
authorFlorian Westphal <fw@strlen.de>
Sun, 21 Nov 2021 22:33:19 +0000 (23:33 +0100)
committerFlorian Westphal <fw@strlen.de>
Wed, 1 Dec 2021 13:12:59 +0000 (14:12 +0100)
Unify binop handling for ipv6 extension header, ip option and tcp option
processing.

Pass the real offset and length expected, not the one used in the kernel.
This was already done for extension headers and ip options, but tcp
option parsing did not do this.

This was fine before because no existing tcp option template
had a non-byte sized member.

With mptcp addition this isn't the case anymore, subtype field is
only 4 bits wide, but tcp option delinearization passed 8bits instead.

Pass the offset and mask delta, just like ip option/ipv6 exthdr.

This makes nft show 'tcp option mptcp subtype 1' instead of
'tcp option mptcp unknown & 240 == 16'.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/tcpopt.h
src/exthdr.c
src/tcpopt.c

index bb5c1329018e45559804f3b15b6fb86525aad2de..3a0b8424a9908843405304774552680ca0c230d5 100644 (file)
@@ -12,8 +12,8 @@ extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
                            unsigned int offset, unsigned int len,
                            uint32_t flags);
 
-extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
-                                unsigned int *shift);
+extern bool tcpopt_find_template(struct expr *expr, unsigned int offset,
+                                unsigned int len);
 
 /* TCP option numbers used on wire */
 enum tcpopt_kind {
index c02b17d31754b834c392e97c3c0a13695eb45e58..2357ab60648d58e97f4ae6a94b98c45594bd775f 100644 (file)
@@ -348,16 +348,7 @@ static unsigned int mask_length(const struct expr *mask)
 bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned int *shift)
 {
        unsigned int off, mask_offset, mask_len;
-
-       if (expr->exthdr.op != NFT_EXTHDR_OP_IPV4 &&
-           expr->exthdr.tmpl != &exthdr_unknown_template)
-               return false;
-
-       /* In case we are handling tcp options instead of the default ipv6
-        * extension headers.
-        */
-       if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT)
-               return tcpopt_find_template(expr, mask, shift);
+       bool found;
 
        mask_offset = mpz_scan1(mask->value, 0);
        mask_len = mask_length(mask);
@@ -366,24 +357,31 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
        off += round_up(mask->len, BITS_PER_BYTE) - mask_len;
 
        /* Handle ip options after the offset and mask have been calculated. */
-       if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
-               if (ipopt_find_template(expr, off, mask_len - mask_offset)) {
-                       *shift = mask_offset;
-                       return true;
-               } else {
+       switch (expr->exthdr.op) {
+       case NFT_EXTHDR_OP_IPV4:
+               found = ipopt_find_template(expr, off, mask_len - mask_offset);
+               break;
+       case NFT_EXTHDR_OP_TCPOPT:
+               found = tcpopt_find_template(expr, off, mask_len - mask_offset);
+               break;
+       case NFT_EXTHDR_OP_IPV6:
+               exthdr_init_raw(expr, expr->exthdr.desc->type,
+                               off, mask_len - mask_offset, expr->exthdr.op, 0);
+
+               /* still failed to find a template... Bug. */
+               if (expr->exthdr.tmpl == &exthdr_unknown_template)
                        return false;
-               }
+               found = true;
+               break;
+       default:
+               found = false;
+               break;
        }
 
-       exthdr_init_raw(expr, expr->exthdr.desc->type,
-                       off, mask_len - mask_offset, expr->exthdr.op, 0);
-
-       /* still failed to find a template... Bug. */
-       if (expr->exthdr.tmpl == &exthdr_unknown_template)
-               return false;
+       if (found)
+               *shift = mask_offset;
 
-       *shift = mask_offset;
-       return true;
+       return found;
 }
 
 #define HDR_TEMPLATE(__name, __dtype, __type, __member)                        \
index 641daa7359a305f72b792feaf32cc031270ec994..c3e07d7889ab4724934d026aad9220d2a7d16f42 100644 (file)
@@ -225,6 +225,7 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
        expr->exthdr.flags = flags;
        expr->exthdr.offset = off;
        expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+       expr->exthdr.tmpl = &tcpopt_unknown_template;
 
        if (flags & NFT_EXTHDR_F_PRESENT)
                datatype_set(expr, &boolean_type);
@@ -252,14 +253,12 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
        }
 }
 
-bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
-                         unsigned int *shift)
+bool tcpopt_find_template(struct expr *expr, unsigned int offset, unsigned int len)
 {
        if (expr->exthdr.tmpl != &tcpopt_unknown_template)
                return false;
 
-       tcpopt_init_raw(expr, expr->exthdr.desc->type, expr->exthdr.offset,
-                       expr->len, 0);
+       tcpopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0);
 
        if (expr->exthdr.tmpl == &tcpopt_unknown_template)
                return false;