Signed-off-by: lingsheng <860373352@qq.com> (cherry picked from commit 757a6bc4a7db26ad71cdecec0548ca6250ceaffc)
147 lines
4.7 KiB
Diff
147 lines
4.7 KiB
Diff
From c10464b84d2fe06e137f2d690e347802fcb50821 Mon Sep 17 00:00:00 2001
|
|
From: Florian Westphal <fw@strlen.de>
|
|
Date: Sun, 21 Nov 2021 23:33:19 +0100
|
|
Subject: [PATCH] exthdr: fix tcpopt_find_template to use length after mask
|
|
adjustment
|
|
|
|
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 | 4 ++--
|
|
src/exthdr.c | 46 ++++++++++++++++++++++------------------------
|
|
src/tcpopt.c | 7 +++----
|
|
3 files changed, 27 insertions(+), 30 deletions(-)
|
|
|
|
diff --git a/include/tcpopt.h b/include/tcpopt.h
|
|
index bb5c1329..3a0b8424 100644
|
|
--- a/include/tcpopt.h
|
|
+++ b/include/tcpopt.h
|
|
@@ -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 {
|
|
diff --git a/src/exthdr.c b/src/exthdr.c
|
|
index c02b17d3..2357ab60 100644
|
|
--- a/src/exthdr.c
|
|
+++ b/src/exthdr.c
|
|
@@ -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) \
|
|
diff --git a/src/tcpopt.c b/src/tcpopt.c
|
|
index 641daa73..c3e07d78 100644
|
|
--- a/src/tcpopt.c
|
|
+++ b/src/tcpopt.c
|
|
@@ -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;
|
|
--
|
|
2.33.0
|
|
|