]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
json: deal appropriately with multidevice in chain
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Nov 2023 09:36:50 +0000 (10:36 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 27 Nov 2023 11:56:23 +0000 (12:56 +0100)
commit 4dfb5b2010917da3f9f11c83931069931a7d6fb3 upstream.

Chain device support is broken in JSON: listing does not include devices
and parser only deals with one single device.

Use existing json_parse_flowtable_devs() function, rename it to
json_parse_devs() to parse the device array.

Use the dev_array that contains the device names (as string) for the
listing.

Update incorrect .json-nft files in tests/shell.

Fixes: 3fdc7541fba0 ("src: add multidevice support for netdev chain")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/json.c
src/parser_json.c

index 6031544140467a01baf4b30ca3779ac5d4e08099..f167c88a9c4f62aed6ba653b191f3aa3ddd2ea40 100644 (file)
@@ -247,9 +247,8 @@ static json_t *rule_print_json(struct output_ctx *octx,
 
 static json_t *chain_print_json(const struct chain *chain)
 {
-       int priority, policy, n = 0;
-       struct expr *dev, *expr;
-       json_t *root, *tmp;
+       json_t *root, *tmp, *devs = NULL;
+       int priority, policy, i;
 
        root = json_pack("{s:s, s:s, s:s, s:I}",
                         "family", family2str(chain->handle.family),
@@ -268,17 +267,19 @@ static json_t *chain_print_json(const struct chain *chain)
                                                    chain->hook.num),
                                "prio", priority,
                                "policy", chain_policy2str(policy));
-               if (chain->dev_expr) {
-                       list_for_each_entry(expr, &chain->dev_expr->expressions, list) {
-                               dev = expr;
-                               n++;
-                       }
-               }
 
-               if (n == 1) {
-                       json_object_set_new(tmp, "dev",
-                                           json_string(dev->identifier));
+               for (i = 0; i < chain->dev_array_len; i++) {
+                       const char *dev = chain->dev_array[i];
+                       if (!devs)
+                               devs = json_string(dev);
+                       else if (json_is_string(devs))
+                               devs = json_pack("[o, s]", devs, dev);
+                       else
+                               json_array_append_new(devs, json_string(dev));
                }
+               if (devs)
+                       json_object_set_new(root, "dev", devs);
+
                json_object_update(root, tmp);
                json_decref(tmp);
        }
index 357b2d86630b1bbeac2f77154c936cb13064e231..eb73848aa2440e83538acbc69be9af8639a730e1 100644 (file)
@@ -2897,14 +2897,49 @@ static struct expr *parse_policy(const char *policy)
                                   sizeof(int) * BITS_PER_BYTE, &policy_num);
 }
 
+static struct expr *json_parse_devs(struct json_ctx *ctx, json_t *root)
+{
+       struct expr *tmp, *expr = compound_expr_alloc(int_loc, EXPR_LIST);
+       const char *dev;
+       json_t *value;
+       size_t index;
+
+       if (!json_unpack(root, "s", &dev)) {
+               tmp = constant_expr_alloc(int_loc, &string_type,
+                                         BYTEORDER_HOST_ENDIAN,
+                                         strlen(dev) * BITS_PER_BYTE, dev);
+               compound_expr_add(expr, tmp);
+               return expr;
+       }
+       if (!json_is_array(root)) {
+               expr_free(expr);
+               return NULL;
+       }
+
+       json_array_foreach(root, index, value) {
+               if (json_unpack(value, "s", &dev)) {
+                       json_error(ctx, "Invalid device at index %zu.",
+                                  index);
+                       expr_free(expr);
+                       return NULL;
+               }
+               tmp = constant_expr_alloc(int_loc, &string_type,
+                                         BYTEORDER_HOST_ENDIAN,
+                                         strlen(dev) * BITS_PER_BYTE, dev);
+               compound_expr_add(expr, tmp);
+       }
+       return expr;
+}
+
 static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
                                            enum cmd_ops op, enum cmd_obj obj)
 {
        struct handle h = {
                .table.location = *int_loc,
        };
-       const char *family = "", *policy = "", *type, *hookstr, *name;
+       const char *family = "", *policy = "", *type, *hookstr;
        struct chain *chain;
+       json_t *devs = NULL;
        int prio;
 
        if (json_unpack_err(ctx, root, "{s:s, s:s}",
@@ -2949,16 +2984,15 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
                return NULL;
        }
 
-       if (!json_unpack(root, "{s:s}", "dev", &name)) {
-               struct expr *dev_expr, *expr;
+       json_unpack(root, "{s:o}", "dev", &devs);
 
-               dev_expr = compound_expr_alloc(int_loc, EXPR_LIST);
-               expr = constant_expr_alloc(int_loc, &integer_type,
-                                          BYTEORDER_HOST_ENDIAN,
-                                          strlen(name) * BITS_PER_BYTE,
-                                          name);
-               compound_expr_add(dev_expr, expr);
-               chain->dev_expr = dev_expr;
+       if (devs) {
+               chain->dev_expr = json_parse_devs(ctx, devs);
+               if (!chain->dev_expr) {
+                       json_error(ctx, "Invalid chain dev.");
+                       chain_free(chain);
+                       return NULL;
+               }
        }
 
        if (!json_unpack(root, "{s:s}", "policy", &policy)) {
@@ -3251,41 +3285,6 @@ static struct cmd *json_parse_cmd_add_element(struct json_ctx *ctx,
        return cmd_alloc(op, cmd_obj, &h, int_loc, expr);
 }
 
-static struct expr *json_parse_flowtable_devs(struct json_ctx *ctx,
-                                             json_t *root)
-{
-       struct expr *tmp, *expr = compound_expr_alloc(int_loc, EXPR_LIST);
-       const char *dev;
-       json_t *value;
-       size_t index;
-
-       if (!json_unpack(root, "s", &dev)) {
-               tmp = constant_expr_alloc(int_loc, &string_type,
-                                         BYTEORDER_HOST_ENDIAN,
-                                         strlen(dev) * BITS_PER_BYTE, dev);
-               compound_expr_add(expr, tmp);
-               return expr;
-       }
-       if (!json_is_array(root)) {
-               expr_free(expr);
-               return NULL;
-       }
-
-       json_array_foreach(root, index, value) {
-               if (json_unpack(value, "s", &dev)) {
-                       json_error(ctx, "Invalid flowtable dev at index %zu.",
-                                  index);
-                       expr_free(expr);
-                       return NULL;
-               }
-               tmp = constant_expr_alloc(int_loc, &string_type,
-                                         BYTEORDER_HOST_ENDIAN,
-                                         strlen(dev) * BITS_PER_BYTE, dev);
-               compound_expr_add(expr, tmp);
-       }
-       return expr;
-}
-
 static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
                                                json_t *root, enum cmd_ops op,
                                                enum cmd_obj cmd_obj)
@@ -3346,7 +3345,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
                                    sizeof(int) * BITS_PER_BYTE, &prio);
 
        if (devs) {
-               flowtable->dev_expr = json_parse_flowtable_devs(ctx, devs);
+               flowtable->dev_expr = json_parse_devs(ctx, devs);
                if (!flowtable->dev_expr) {
                        json_error(ctx, "Invalid flowtable dev.");
                        flowtable_free(flowtable);