200 lines
5.5 KiB
Diff
200 lines
5.5 KiB
Diff
From ad566e27398e81ed803c4225179bb8df4718a2e9 Mon Sep 17 00:00:00 2001
|
|
From: Phil Sutter <psutter@redhat.com>
|
|
Date: Mon, 12 Jul 2021 17:44:08 +0200
|
|
Subject: [PATCH] json: tcp: add raw tcp option match support
|
|
|
|
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
|
|
Upstream Status: nftables commit cb21869649208
|
|
|
|
commit cb21869649208118ed61354e2674858e4ff6c23c
|
|
Author: Florian Westphal <fw@strlen.de>
|
|
Date: Tue Nov 3 12:04:20 2020 +0100
|
|
|
|
json: tcp: add raw tcp option match support
|
|
|
|
To similar change as in previous one, this time for the
|
|
jason (de)serialization.
|
|
|
|
Re-uses the raw payload match syntax, i.e. base,offset,length.
|
|
|
|
Signed-off-by: Florian Westphal <fw@strlen.de>
|
|
---
|
|
src/json.c | 22 ++++++++--------
|
|
src/parser_json.c | 52 ++++++++++++++++++++++++++------------
|
|
tests/py/any/tcpopt.t.json | 34 +++++++++++++++++++++++++
|
|
3 files changed, 82 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/src/json.c b/src/json.c
|
|
index 1906e7d..b77c6d2 100644
|
|
--- a/src/json.c
|
|
+++ b/src/json.c
|
|
@@ -656,30 +656,32 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
|
|
json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
|
|
{
|
|
const char *desc = expr->exthdr.desc ?
|
|
- expr->exthdr.desc->name :
|
|
- "unknown-exthdr";
|
|
+ expr->exthdr.desc->name : NULL;
|
|
const char *field = expr->exthdr.tmpl->token;
|
|
json_t *root;
|
|
bool is_exists = expr->exthdr.flags & NFT_EXTHDR_F_PRESENT;
|
|
|
|
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
|
|
+ static const char *offstrs[] = { "", "1", "2", "3" };
|
|
unsigned int offset = expr->exthdr.offset / 64;
|
|
+ const char *offstr = "";
|
|
|
|
- if (offset) {
|
|
- const char *offstrs[] = { "0", "1", "2", "3" };
|
|
- const char *offstr = "";
|
|
-
|
|
+ if (desc) {
|
|
if (offset < 4)
|
|
offstr = offstrs[offset];
|
|
|
|
root = json_pack("{s:s+}", "name", desc, offstr);
|
|
+
|
|
+ if (!is_exists)
|
|
+ json_object_set_new(root, "field", json_string(field));
|
|
} else {
|
|
- root = json_pack("{s:s}", "name", desc);
|
|
+ root = json_pack("{s:i, s:i, s:i}",
|
|
+ "base", expr->exthdr.raw_type,
|
|
+ "offset", expr->exthdr.offset,
|
|
+ "len", expr->len);
|
|
+ is_exists = false;
|
|
}
|
|
|
|
- if (!is_exists)
|
|
- json_object_set_new(root, "field", json_string(field));
|
|
-
|
|
return json_pack("{s:o}", "tcp option", root);
|
|
}
|
|
if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
|
|
diff --git a/src/parser_json.c b/src/parser_json.c
|
|
index ab2375f..fbf7db5 100644
|
|
--- a/src/parser_json.c
|
|
+++ b/src/parser_json.c
|
|
@@ -500,6 +500,8 @@ static int json_parse_tcp_option_field(int type, const char *name, int *val)
|
|
return 1;
|
|
|
|
desc = tcpopt_protocols[type];
|
|
+ if (!desc)
|
|
+ return 1;
|
|
|
|
for (i = 0; i < array_size(desc->templates); i++) {
|
|
if (desc->templates[i].token &&
|
|
@@ -599,30 +601,48 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
|
|
static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
|
|
const char *type, json_t *root)
|
|
{
|
|
+ int fieldval, kind, offset, len;
|
|
const char *desc, *field;
|
|
- int descval, fieldval;
|
|
struct expr *expr;
|
|
|
|
- if (json_unpack_err(ctx, root, "{s:s}", "name", &desc))
|
|
- return NULL;
|
|
-
|
|
- if (json_parse_tcp_option_type(desc, &descval)) {
|
|
- json_error(ctx, "Unknown tcp option name '%s'.", desc);
|
|
- return NULL;
|
|
- }
|
|
+ if (!json_unpack(root, "{s:i, s:i, s:i}",
|
|
+ "base", &kind, "offset", &offset, "len", &len)) {
|
|
+ uint32_t flag = 0;
|
|
|
|
- if (json_unpack(root, "{s:s}", "field", &field)) {
|
|
- expr = tcpopt_expr_alloc(int_loc, descval,
|
|
+ expr = tcpopt_expr_alloc(int_loc, kind,
|
|
TCPOPT_COMMON_KIND);
|
|
- expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
|
|
|
|
+ if (kind < 0 || kind > 255)
|
|
+ return NULL;
|
|
+
|
|
+ if (offset == TCPOPT_COMMON_KIND && len == 8)
|
|
+ flag = NFT_EXTHDR_F_PRESENT;
|
|
+
|
|
+ tcpopt_init_raw(expr, kind, offset, len, flag);
|
|
return expr;
|
|
+ } else if (!json_unpack(root, "{s:s}", "name", &desc)) {
|
|
+ if (json_parse_tcp_option_type(desc, &kind)) {
|
|
+ json_error(ctx, "Unknown tcp option name '%s'.", desc);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (json_unpack(root, "{s:s}", "field", &field)) {
|
|
+ expr = tcpopt_expr_alloc(int_loc, kind,
|
|
+ TCPOPT_COMMON_KIND);
|
|
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
|
|
+ return expr;
|
|
+ }
|
|
+
|
|
+ if (json_parse_tcp_option_field(kind, field, &fieldval)) {
|
|
+ json_error(ctx, "Unknown tcp option field '%s'.", field);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return tcpopt_expr_alloc(int_loc, kind, fieldval);
|
|
}
|
|
- if (json_parse_tcp_option_field(descval, field, &fieldval)) {
|
|
- json_error(ctx, "Unknown tcp option field '%s'.", field);
|
|
- return NULL;
|
|
- }
|
|
- return tcpopt_expr_alloc(int_loc, descval, fieldval);
|
|
+
|
|
+ json_error(ctx, "Invalid tcp option expression properties.");
|
|
+ return NULL;
|
|
}
|
|
|
|
static int json_parse_ip_option_type(const char *name, int *val)
|
|
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
|
|
index b15e36e..139e97d 100644
|
|
--- a/tests/py/any/tcpopt.t.json
|
|
+++ b/tests/py/any/tcpopt.t.json
|
|
@@ -414,6 +414,40 @@
|
|
}
|
|
]
|
|
|
|
+# tcp option 255 missing
|
|
+[
|
|
+ {
|
|
+ "match": {
|
|
+ "left": {
|
|
+ "tcp option": {
|
|
+ "base": 255,
|
|
+ "len": 8,
|
|
+ "offset": 0
|
|
+ }
|
|
+ },
|
|
+ "op": "==",
|
|
+ "right": false
|
|
+ }
|
|
+ }
|
|
+]
|
|
+
|
|
+# tcp option @255,8,8 255
|
|
+[
|
|
+ {
|
|
+ "match": {
|
|
+ "left": {
|
|
+ "tcp option": {
|
|
+ "base": 255,
|
|
+ "len": 8,
|
|
+ "offset": 8
|
|
+ }
|
|
+ },
|
|
+ "op": "==",
|
|
+ "right": 255
|
|
+ }
|
|
+ }
|
|
+]
|
|
+
|
|
# tcp option window exists
|
|
[
|
|
{
|
|
--
|
|
2.31.1
|
|
|