|
|
0341a5 |
From 8a4b6cbf58e965d67b0337ba1736bd3691a49890 Mon Sep 17 00:00:00 2001
|
|
|
0341a5 |
From: Phil Sutter <psutter@redhat.com>
|
|
|
0341a5 |
Date: Mon, 12 Jul 2021 17:44:08 +0200
|
|
|
0341a5 |
Subject: [PATCH] tcpopt: allow to check for presence of any tcp option
|
|
|
0341a5 |
|
|
|
0341a5 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
|
|
|
0341a5 |
Upstream Status: nftables commit 24d8da3083422
|
|
|
0341a5 |
|
|
|
0341a5 |
commit 24d8da3083422da8336eeed2ee23b2ccf598ba5a
|
|
|
0341a5 |
Author: Florian Westphal <fw@strlen.de>
|
|
|
0341a5 |
Date: Wed Oct 21 23:54:17 2020 +0200
|
|
|
0341a5 |
|
|
|
0341a5 |
tcpopt: allow to check for presence of any tcp option
|
|
|
0341a5 |
|
|
|
0341a5 |
nft currently doesn't allow to check for presence of arbitrary tcp options.
|
|
|
0341a5 |
Only known options where nft provides a template can be tested for.
|
|
|
0341a5 |
|
|
|
0341a5 |
This allows to test for presence of raw protocol values as well.
|
|
|
0341a5 |
|
|
|
0341a5 |
Example:
|
|
|
0341a5 |
|
|
|
0341a5 |
tcp option 42 exists
|
|
|
0341a5 |
|
|
|
0341a5 |
Signed-off-by: Florian Westphal <fw@strlen.de>
|
|
|
0341a5 |
---
|
|
|
0341a5 |
include/expression.h | 3 +-
|
|
|
0341a5 |
src/exthdr.c | 12 ++++++++
|
|
|
0341a5 |
src/ipopt.c | 1 +
|
|
|
0341a5 |
src/netlink_linearize.c | 2 +-
|
|
|
0341a5 |
src/parser_bison.y | 7 +++++
|
|
|
0341a5 |
src/tcpopt.c | 42 +++++++++++++++++++++++----
|
|
|
0341a5 |
tests/py/any/tcpopt.t | 2 ++
|
|
|
0341a5 |
tests/py/any/tcpopt.t.payload | 53 +++--------------------------------
|
|
|
0341a5 |
8 files changed, 65 insertions(+), 57 deletions(-)
|
|
|
0341a5 |
|
|
|
0341a5 |
diff --git a/include/expression.h b/include/expression.h
|
|
|
0341a5 |
index 2e41aa0..b50183d 100644
|
|
|
0341a5 |
--- a/include/expression.h
|
|
|
0341a5 |
+++ b/include/expression.h
|
|
|
0341a5 |
@@ -299,7 +299,8 @@ struct expr {
|
|
|
0341a5 |
/* EXPR_EXTHDR */
|
|
|
0341a5 |
const struct exthdr_desc *desc;
|
|
|
0341a5 |
const struct proto_hdr_template *tmpl;
|
|
|
0341a5 |
- unsigned int offset;
|
|
|
0341a5 |
+ uint16_t offset;
|
|
|
0341a5 |
+ uint8_t raw_type;
|
|
|
0341a5 |
enum nft_exthdr_op op;
|
|
|
0341a5 |
unsigned int flags;
|
|
|
0341a5 |
} exthdr;
|
|
|
0341a5 |
diff --git a/src/exthdr.c b/src/exthdr.c
|
|
|
0341a5 |
index c28213f..68d5aa5 100644
|
|
|
0341a5 |
--- a/src/exthdr.c
|
|
|
0341a5 |
+++ b/src/exthdr.c
|
|
|
0341a5 |
@@ -32,6 +32,13 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
|
|
|
0341a5 |
*/
|
|
|
0341a5 |
unsigned int offset = expr->exthdr.offset / 64;
|
|
|
0341a5 |
|
|
|
0341a5 |
+ if (expr->exthdr.desc == NULL &&
|
|
|
0341a5 |
+ expr->exthdr.offset == 0 &&
|
|
|
0341a5 |
+ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
|
|
|
0341a5 |
+ nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
|
|
|
0341a5 |
+ return;
|
|
|
0341a5 |
+ }
|
|
|
0341a5 |
+
|
|
|
0341a5 |
nft_print(octx, "tcp option %s", expr->exthdr.desc->name);
|
|
|
0341a5 |
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
|
|
|
0341a5 |
return;
|
|
|
0341a5 |
@@ -59,6 +66,7 @@ static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2)
|
|
|
0341a5 |
return e1->exthdr.desc == e2->exthdr.desc &&
|
|
|
0341a5 |
e1->exthdr.tmpl == e2->exthdr.tmpl &&
|
|
|
0341a5 |
e1->exthdr.op == e2->exthdr.op &&
|
|
|
0341a5 |
+ e1->exthdr.raw_type == e2->exthdr.raw_type &&
|
|
|
0341a5 |
e1->exthdr.flags == e2->exthdr.flags;
|
|
|
0341a5 |
}
|
|
|
0341a5 |
|
|
|
0341a5 |
@@ -69,6 +77,7 @@ static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
|
|
|
0341a5 |
new->exthdr.offset = expr->exthdr.offset;
|
|
|
0341a5 |
new->exthdr.op = expr->exthdr.op;
|
|
|
0341a5 |
new->exthdr.flags = expr->exthdr.flags;
|
|
|
0341a5 |
+ new->exthdr.raw_type = expr->exthdr.raw_type;
|
|
|
0341a5 |
}
|
|
|
0341a5 |
|
|
|
0341a5 |
const struct expr_ops exthdr_expr_ops = {
|
|
|
0341a5 |
@@ -98,6 +107,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
|
|
|
0341a5 |
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
|
|
|
0341a5 |
BYTEORDER_BIG_ENDIAN, tmpl->len);
|
|
|
0341a5 |
expr->exthdr.desc = desc;
|
|
|
0341a5 |
+ expr->exthdr.raw_type = desc ? desc->type : 0;
|
|
|
0341a5 |
expr->exthdr.tmpl = tmpl;
|
|
|
0341a5 |
expr->exthdr.offset = tmpl->offset;
|
|
|
0341a5 |
return expr;
|
|
|
0341a5 |
@@ -176,6 +186,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
|
|
|
0341a5 |
unsigned int i;
|
|
|
0341a5 |
|
|
|
0341a5 |
assert(expr->etype == EXPR_EXTHDR);
|
|
|
0341a5 |
+ expr->exthdr.raw_type = type;
|
|
|
0341a5 |
+
|
|
|
0341a5 |
if (op == NFT_EXTHDR_OP_TCPOPT)
|
|
|
0341a5 |
return tcpopt_init_raw(expr, type, offset, len, flags);
|
|
|
0341a5 |
if (op == NFT_EXTHDR_OP_IPV4)
|
|
|
0341a5 |
diff --git a/src/ipopt.c b/src/ipopt.c
|
|
|
0341a5 |
index 7ecb8b9..5f9f908 100644
|
|
|
0341a5 |
--- a/src/ipopt.c
|
|
|
0341a5 |
+++ b/src/ipopt.c
|
|
|
0341a5 |
@@ -103,6 +103,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
|
|
|
0341a5 |
expr->exthdr.tmpl = tmpl;
|
|
|
0341a5 |
expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
|
|
|
0341a5 |
expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr);
|
|
|
0341a5 |
+ expr->exthdr.raw_type = desc->type;
|
|
|
0341a5 |
|
|
|
0341a5 |
return expr;
|
|
|
0341a5 |
}
|
|
|
0341a5 |
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
|
|
|
0341a5 |
index 9d1a064..28b0e6a 100644
|
|
|
0341a5 |
--- a/src/netlink_linearize.c
|
|
|
0341a5 |
+++ b/src/netlink_linearize.c
|
|
|
0341a5 |
@@ -174,7 +174,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
|
|
|
0341a5 |
nle = alloc_nft_expr("exthdr");
|
|
|
0341a5 |
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
|
|
|
0341a5 |
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
|
|
|
0341a5 |
- expr->exthdr.desc->type);
|
|
|
0341a5 |
+ expr->exthdr.raw_type);
|
|
|
0341a5 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
|
|
|
0341a5 |
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
|
|
|
0341a5 |
div_round_up(expr->len, BITS_PER_BYTE));
|
|
|
0341a5 |
diff --git a/src/parser_bison.y b/src/parser_bison.y
|
|
|
0341a5 |
index 114b289..4ea9364 100644
|
|
|
0341a5 |
--- a/src/parser_bison.y
|
|
|
0341a5 |
+++ b/src/parser_bison.y
|
|
|
0341a5 |
@@ -4744,6 +4744,13 @@ tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; }
|
|
|
0341a5 |
| SACK3 { $$ = TCPOPT_KIND_SACK3; }
|
|
|
0341a5 |
| ECHO { $$ = TCPOPT_KIND_ECHO; }
|
|
|
0341a5 |
| TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
|
|
|
0341a5 |
+ | NUM {
|
|
|
0341a5 |
+ if ($1 > 255) {
|
|
|
0341a5 |
+ erec_queue(error(&@1, "value too large"), state->msgs);
|
|
|
0341a5 |
+ YYERROR;
|
|
|
0341a5 |
+ }
|
|
|
0341a5 |
+ $$ = $1;
|
|
|
0341a5 |
+ }
|
|
|
0341a5 |
;
|
|
|
0341a5 |
|
|
|
0341a5 |
tcp_hdr_option_field : KIND { $$ = TCPOPT_COMMON_KIND; }
|
|
|
0341a5 |
diff --git a/src/tcpopt.c b/src/tcpopt.c
|
|
|
0341a5 |
index d1dd13b..1cf97a5 100644
|
|
|
0341a5 |
--- a/src/tcpopt.c
|
|
|
0341a5 |
+++ b/src/tcpopt.c
|
|
|
0341a5 |
@@ -103,6 +103,19 @@ const struct exthdr_desc *tcpopt_protocols[] = {
|
|
|
0341a5 |
[TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
|
|
|
0341a5 |
};
|
|
|
0341a5 |
|
|
|
0341a5 |
+/**
|
|
|
0341a5 |
+ * tcpopt_expr_alloc - allocate tcp option extension expression
|
|
|
0341a5 |
+ *
|
|
|
0341a5 |
+ * @loc: location from parser
|
|
|
0341a5 |
+ * @kind: raw tcp option value to find in packet
|
|
|
0341a5 |
+ * @field: highlevel field to find in the option if @kind is present in packet
|
|
|
0341a5 |
+ *
|
|
|
0341a5 |
+ * Allocate a new tcp option expression.
|
|
|
0341a5 |
+ * @kind is the raw option value to find in the packet.
|
|
|
0341a5 |
+ * Exception: SACK may use extra OOB data that is mangled here.
|
|
|
0341a5 |
+ *
|
|
|
0341a5 |
+ * @field is the optional field to extract from the @type option.
|
|
|
0341a5 |
+ */
|
|
|
0341a5 |
struct expr *tcpopt_expr_alloc(const struct location *loc,
|
|
|
0341a5 |
unsigned int kind,
|
|
|
0341a5 |
unsigned int field)
|
|
|
0341a5 |
@@ -138,8 +151,22 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
|
|
|
0341a5 |
if (kind < array_size(tcpopt_protocols))
|
|
|
0341a5 |
desc = tcpopt_protocols[kind];
|
|
|
0341a5 |
|
|
|
0341a5 |
- if (!desc)
|
|
|
0341a5 |
- return NULL;
|
|
|
0341a5 |
+ if (!desc) {
|
|
|
0341a5 |
+ if (field != TCPOPT_COMMON_KIND || kind > 255)
|
|
|
0341a5 |
+ return NULL;
|
|
|
0341a5 |
+
|
|
|
0341a5 |
+ expr = expr_alloc(loc, EXPR_EXTHDR, &integer_type,
|
|
|
0341a5 |
+ BYTEORDER_BIG_ENDIAN, 8);
|
|
|
0341a5 |
+
|
|
|
0341a5 |
+ desc = tcpopt_protocols[TCPOPT_NOP];
|
|
|
0341a5 |
+ tmpl = &desc->templates[field];
|
|
|
0341a5 |
+ expr->exthdr.desc = desc;
|
|
|
0341a5 |
+ expr->exthdr.tmpl = tmpl;
|
|
|
0341a5 |
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
|
|
|
0341a5 |
+ expr->exthdr.raw_type = kind;
|
|
|
0341a5 |
+ return expr;
|
|
|
0341a5 |
+ }
|
|
|
0341a5 |
+
|
|
|
0341a5 |
tmpl = &desc->templates[field];
|
|
|
0341a5 |
if (!tmpl)
|
|
|
0341a5 |
return NULL;
|
|
|
0341a5 |
@@ -149,6 +176,7 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
|
|
|
0341a5 |
expr->exthdr.desc = desc;
|
|
|
0341a5 |
expr->exthdr.tmpl = tmpl;
|
|
|
0341a5 |
expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
|
|
|
0341a5 |
+ expr->exthdr.raw_type = desc->type;
|
|
|
0341a5 |
expr->exthdr.offset = tmpl->offset;
|
|
|
0341a5 |
|
|
|
0341a5 |
return expr;
|
|
|
0341a5 |
@@ -165,6 +193,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
|
|
|
0341a5 |
expr->len = len;
|
|
|
0341a5 |
expr->exthdr.flags = flags;
|
|
|
0341a5 |
expr->exthdr.offset = off;
|
|
|
0341a5 |
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
|
|
|
0341a5 |
+
|
|
|
0341a5 |
+ if (flags & NFT_EXTHDR_F_PRESENT)
|
|
|
0341a5 |
+ datatype_set(expr, &boolean_type);
|
|
|
0341a5 |
|
|
|
0341a5 |
if (type >= array_size(tcpopt_protocols))
|
|
|
0341a5 |
return;
|
|
|
0341a5 |
@@ -178,12 +210,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
|
|
|
0341a5 |
if (tmpl->offset != off || tmpl->len != len)
|
|
|
0341a5 |
continue;
|
|
|
0341a5 |
|
|
|
0341a5 |
- if (flags & NFT_EXTHDR_F_PRESENT)
|
|
|
0341a5 |
- datatype_set(expr, &boolean_type);
|
|
|
0341a5 |
- else
|
|
|
0341a5 |
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
|
|
|
0341a5 |
datatype_set(expr, tmpl->dtype);
|
|
|
0341a5 |
+
|
|
|
0341a5 |
expr->exthdr.tmpl = tmpl;
|
|
|
0341a5 |
- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
|
|
|
0341a5 |
break;
|
|
|
0341a5 |
}
|
|
|
0341a5 |
}
|
|
|
0341a5 |
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
|
|
|
0341a5 |
index 1d42de8..7b17014 100644
|
|
|
0341a5 |
--- a/tests/py/any/tcpopt.t
|
|
|
0341a5 |
+++ b/tests/py/any/tcpopt.t
|
|
|
0341a5 |
@@ -30,6 +30,7 @@ tcp option timestamp kind 1;ok
|
|
|
0341a5 |
tcp option timestamp length 1;ok
|
|
|
0341a5 |
tcp option timestamp tsval 1;ok
|
|
|
0341a5 |
tcp option timestamp tsecr 1;ok
|
|
|
0341a5 |
+tcp option 255 missing;ok
|
|
|
0341a5 |
|
|
|
0341a5 |
tcp option foobar;fail
|
|
|
0341a5 |
tcp option foo bar;fail
|
|
|
0341a5 |
@@ -38,6 +39,7 @@ tcp option eol left 1;fail
|
|
|
0341a5 |
tcp option eol left 1;fail
|
|
|
0341a5 |
tcp option sack window;fail
|
|
|
0341a5 |
tcp option sack window 1;fail
|
|
|
0341a5 |
+tcp option 256 exists;fail
|
|
|
0341a5 |
|
|
|
0341a5 |
tcp option window exists;ok
|
|
|
0341a5 |
tcp option window missing;ok
|
|
|
0341a5 |
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
|
|
|
0341a5 |
index 9c480c8..34f8e26 100644
|
|
|
0341a5 |
--- a/tests/py/any/tcpopt.t.payload
|
|
|
0341a5 |
+++ b/tests/py/any/tcpopt.t.payload
|
|
|
0341a5 |
@@ -509,20 +509,6 @@ inet
|
|
|
0341a5 |
[ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
|
|
|
0341a5 |
[ cmp eq reg 1 0x01000000 ]
|
|
|
0341a5 |
|
|
|
0341a5 |
-# tcp option timestamp tsecr 1
|
|
|
0341a5 |
-ip
|
|
|
0341a5 |
- [ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x01000000 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
-# tcp option timestamp tsecr 1
|
|
|
0341a5 |
-ip6
|
|
|
0341a5 |
- [ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x01000000 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
# tcp option timestamp tsecr 1
|
|
|
0341a5 |
inet
|
|
|
0341a5 |
[ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
@@ -530,19 +516,12 @@ inet
|
|
|
0341a5 |
[ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
|
|
|
0341a5 |
[ cmp eq reg 1 0x01000000 ]
|
|
|
0341a5 |
|
|
|
0341a5 |
-# tcp option window exists
|
|
|
0341a5 |
-ip
|
|
|
0341a5 |
- [ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000001 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
-# tcp option window exists
|
|
|
0341a5 |
-ip6
|
|
|
0341a5 |
+# tcp option 255 missing
|
|
|
0341a5 |
+inet
|
|
|
0341a5 |
[ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
[ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000001 ]
|
|
|
0341a5 |
+ [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ]
|
|
|
0341a5 |
+ [ cmp eq reg 1 0x00000000 ]
|
|
|
0341a5 |
|
|
|
0341a5 |
# tcp option window exists
|
|
|
0341a5 |
inet
|
|
|
0341a5 |
@@ -551,20 +530,6 @@ inet
|
|
|
0341a5 |
[ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
[ cmp eq reg 1 0x00000001 ]
|
|
|
0341a5 |
|
|
|
0341a5 |
-# tcp option window missing
|
|
|
0341a5 |
-ip
|
|
|
0341a5 |
- [ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000000 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
-# tcp option window missing
|
|
|
0341a5 |
-ip6
|
|
|
0341a5 |
- [ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000006 ]
|
|
|
0341a5 |
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
- [ cmp eq reg 1 0x00000000 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
# tcp option window missing
|
|
|
0341a5 |
inet
|
|
|
0341a5 |
[ meta load l4proto => reg 1 ]
|
|
|
0341a5 |
@@ -572,16 +537,6 @@ inet
|
|
|
0341a5 |
[ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
|
|
|
0341a5 |
[ cmp eq reg 1 0x00000000 ]
|
|
|
0341a5 |
|
|
|
0341a5 |
-# tcp option maxseg size set 1360
|
|
|
0341a5 |
-ip
|
|
|
0341a5 |
- [ immediate reg 1 0x00005005 ]
|
|
|
0341a5 |
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
-# tcp option maxseg size set 1360
|
|
|
0341a5 |
-ip6
|
|
|
0341a5 |
- [ immediate reg 1 0x00005005 ]
|
|
|
0341a5 |
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
|
|
|
0341a5 |
-
|
|
|
0341a5 |
# tcp option maxseg size set 1360
|
|
|
0341a5 |
inet
|
|
|
0341a5 |
[ immediate reg 1 0x00005005 ]
|
|
|
0341a5 |
--
|
|
|
0341a5 |
2.31.1
|
|
|
0341a5 |
|