diff options
author | Fernando Fernandez Mancera <ffmancera@riseup.net> | 2022-09-01 12:31:43 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2022-09-01 13:11:19 +0200 |
commit | 07958ec53830d4c14b65fa4115c02715dc9c0d47 (patch) | |
tree | 9d3f43772573758ad56d41eacef5d21d48089d31 | |
parent | c5204d07bb22db2362260f2f99e0ffa8ea02ce7b (diff) |
json: add set statement list support
When listing a set with statements with JSON support, the statements were
ignored.
Output example:
{
"set": {
"op": "add",
"elem": {
"payload": {
"protocol": "ip",
"field": "saddr"
}
},
"stmt": [
{
"limit": {
"rate": 10,
"burst": 5,
"per": "second"
}
},
{
"counter": {
"packets": 0,
"bytes": 0
}
}
],
"set": "@my_ssh_meter"
}
}
Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1495
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | src/json.c | 19 | ||||
-rw-r--r-- | src/parser_json.c | 29 | ||||
-rwxr-xr-x | tests/shell/testcases/json/0001set_statements_0 | 9 | ||||
-rw-r--r-- | tests/shell/testcases/json/dumps/0001set_statements_0.nft | 12 |
4 files changed, 67 insertions, 2 deletions
@@ -1439,11 +1439,28 @@ json_t *counter_stmt_json(const struct stmt *stmt, struct output_ctx *octx) "bytes", stmt->counter.bytes); } +static json_t *set_stmt_list_json(const struct list_head *stmt_list, + struct output_ctx *octx) +{ + json_t *root, *tmp; + struct stmt *i; + + root = json_array(); + + list_for_each_entry(i, stmt_list, list) { + tmp = stmt_print_json(i, octx); + json_array_append_new(root, tmp); + } + + return root; +} + json_t *set_stmt_json(const struct stmt *stmt, struct output_ctx *octx) { - return json_pack("{s:{s:s, s:o, s:s+}}", "set", + return json_pack("{s:{s:s, s:o, s:o, s:s+}}", "set", "op", set_stmt_op_names[stmt->set.op], "elem", expr_print_json(stmt->set.key, octx), + "stmt", set_stmt_list_json(&stmt->set.stmt_list, octx), "set", "@", stmt->set.set->set->handle.set.name); } diff --git a/src/parser_json.c b/src/parser_json.c index 2437b1ba..fc72c25f 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -2230,13 +2230,36 @@ static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx, return stmt; } +static void json_parse_set_stmt_list(struct json_ctx *ctx, + struct list_head *stmt_list, + json_t *stmt_json) +{ + struct list_head *head; + struct stmt *tmp; + json_t *value; + size_t index; + + if (!stmt_json) + return; + + if (!json_is_array(stmt_json)) + json_error(ctx, "Unexpected object type in stmt"); + + head = stmt_list; + json_array_foreach(stmt_json, index, value) { + tmp = json_parse_stmt(ctx, value); + list_add(&tmp->list, head); + head = &tmp->list; + } +} + static struct stmt *json_parse_set_stmt(struct json_ctx *ctx, const char *key, json_t *value) { const char *opstr, *set; struct expr *expr, *expr2; + json_t *elem, *stmt_json; struct stmt *stmt; - json_t *elem; int op; if (json_unpack_err(ctx, value, "{s:s, s:o, s:s}", @@ -2271,6 +2294,10 @@ static struct stmt *json_parse_set_stmt(struct json_ctx *ctx, stmt->set.op = op; stmt->set.key = expr; stmt->set.set = expr2; + + if (!json_unpack(value, "{s:o}", "stmt", &stmt_json)) + json_parse_set_stmt_list(ctx, &stmt->set.stmt_list, stmt_json); + return stmt; } diff --git a/tests/shell/testcases/json/0001set_statements_0 b/tests/shell/testcases/json/0001set_statements_0 new file mode 100755 index 00000000..1c72d35b --- /dev/null +++ b/tests/shell/testcases/json/0001set_statements_0 @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +$NFT flush ruleset + +RULESET='{"nftables": [{"metainfo": {"version": "1.0.5", "release_name": "Lester Gooch #4", "json_schema_version": 1}}, {"table": {"family": "ip", "name": "testt", "handle": 3}}, {"set": {"family": "ip", "name": "ssh_meter", "table": "testt", "type": "ipv4_addr", "handle": 2, "size": 65535}}, {"chain": {"family": "ip", "table": "testt", "name": "testc", "handle": 1, "type": "filter", "hook": "input", "prio": 0, "policy": "accept"}}, {"rule": {"family": "ip", "table": "testt", "chain": "testc", "handle": 3, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 22}}, {"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": "new"}}, {"set": {"op": "add", "elem": {"payload": {"protocol": "ip", "field": "saddr"}}, "stmt": [{"limit": {"rate": 10, "burst": 5, "per": "second"}}], "set": "@ssh_meter"}}, {"accept": null}]}}]}' + +$NFT -j -f - <<< $RULESET diff --git a/tests/shell/testcases/json/dumps/0001set_statements_0.nft b/tests/shell/testcases/json/dumps/0001set_statements_0.nft new file mode 100644 index 00000000..ee4a8670 --- /dev/null +++ b/tests/shell/testcases/json/dumps/0001set_statements_0.nft @@ -0,0 +1,12 @@ +table ip testt { + set ssh_meter { + type ipv4_addr + size 65535 + flags dynamic + } + + chain testc { + type filter hook input priority filter; policy accept; + tcp dport 22 ct state new add @ssh_meter { ip saddr limit rate 10/second } accept + } +} |