]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
json: tcp: add raw tcp option match support
authorFlorian Westphal <fw@strlen.de>
Tue, 3 Nov 2020 11:04:20 +0000 (12:04 +0100)
committerFlorian Westphal <fw@strlen.de>
Mon, 9 Nov 2020 11:19:31 +0000 (12:19 +0100)
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
src/parser_json.c
tests/py/any/tcpopt.t.json

index 3c4654d6dada1253a1c512fdbe37a827c86a79ab..ac3b1c833d864a8115e40dcc85aff43e1554f1b0 100644 (file)
@@ -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) {
index 6e1333659f81ab1d7ac33ee2f9cc449212ab7696..b1de56a4a0d27f8ba0ed944c5719b82f7e18971a 100644 (file)
@@ -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)
index b15e36ee7f4ca7631a6be4cf7c2f0b868e801220..139e97d8f0432c35607e4adf63d28c41cae90e48 100644 (file)
     }
 ]
 
+# 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
 [
     {