summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2020-11-03 12:04:20 +0100
committerFlorian Westphal <fw@strlen.de>2020-11-09 12:19:31 +0100
commitcb21869649208118ed61354e2674858e4ff6c23c (patch)
tree40a731079f30640fc112a6c2b73175f63742f880
parent881d8cb21c0b9168787b932f41b801593bde2216 (diff)
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>
-rw-r--r--src/json.c22
-rw-r--r--src/parser_json.c52
-rw-r--r--tests/py/any/tcpopt.t.json34
3 files changed, 82 insertions, 26 deletions
diff --git a/src/json.c b/src/json.c
index 3c4654d6..ac3b1c83 100644
--- a/src/json.c
+++ b/src/json.c
@@ -665,30 +665,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 6e133365..b1de56a4 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -502,6 +502,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 &&
@@ -601,30 +603,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 b15e36ee..139e97d8 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
[
{