diff --git a/.gitignore b/.gitignore index f8f5b8b..c9b6c1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/nftables-0.9.8.tar.bz2 +SOURCES/nftables-1.0.4.tar.bz2 diff --git a/.nftables.metadata b/.nftables.metadata index 55ded3f..b9af18b 100644 --- a/.nftables.metadata +++ b/.nftables.metadata @@ -1 +1 @@ -c15ac5552959c8358975f6b3e15757841c6904c8 SOURCES/nftables-0.9.8.tar.bz2 +e2e8b324cece1409a311284ff4fe26c3a5554809 SOURCES/nftables-1.0.4.tar.bz2 diff --git a/SOURCES/0001-payload-check-icmp-dependency-before-removing-previo.patch b/SOURCES/0001-payload-check-icmp-dependency-before-removing-previo.patch deleted file mode 100644 index 7c234c4..0000000 --- a/SOURCES/0001-payload-check-icmp-dependency-before-removing-previo.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 9230899c6d2be8913646ff1a3b560865c330de7b Mon Sep 17 00:00:00 2001 -From: Florian Westphal -Date: Mon, 1 Feb 2021 22:08:54 +0100 -Subject: [PATCH] payload: check icmp dependency before removing previous icmp - expression - -nft is too greedy when removing icmp dependencies. -'icmp code 1 type 2' did remove the type when printing. - -Be more careful and check that the icmp type dependency of the -candidate expression (earlier icmp payload expression) has the same -type dependency as the new expression. - -Reported-by: Eric Garver -Reported-by: Michael Biebl -Tested-by: Eric Garver -Fixes: d0f3b9eaab8d77e ("payload: auto-remove simple icmp/icmpv6 dependency expressions") -Signed-off-by: Florian Westphal -(cherry picked from commit 533565244d88a818d8828ebabd7625e5a8a4c374) -Signed-off-by: Phil Sutter ---- - src/payload.c | 63 ++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 42 insertions(+), 21 deletions(-) - -diff --git a/src/payload.c b/src/payload.c -index 48529bcf5c514..a77ca55005509 100644 ---- a/src/payload.c -+++ b/src/payload.c -@@ -627,6 +627,40 @@ void payload_dependency_release(struct payload_dep_ctx *ctx) - ctx->pdep = NULL; - } - -+static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t) -+{ -+ switch (t) { -+ case PROTO_ICMP_ANY: -+ BUG("Invalid map for simple dependency"); -+ case PROTO_ICMP_ECHO: return ICMP_ECHO; -+ case PROTO_ICMP6_ECHO: return ICMP6_ECHO_REQUEST; -+ case PROTO_ICMP_MTU: return ICMP_DEST_UNREACH; -+ case PROTO_ICMP_ADDRESS: return ICMP_REDIRECT; -+ case PROTO_ICMP6_MTU: return ICMP6_PACKET_TOO_BIG; -+ case PROTO_ICMP6_MGMQ: return MLD_LISTENER_QUERY; -+ case PROTO_ICMP6_PPTR: return ICMP6_PARAM_PROB; -+ } -+ -+ BUG("Missing icmp type mapping"); -+} -+ -+static bool payload_may_dependency_kill_icmp(struct payload_dep_ctx *ctx, struct expr *expr) -+{ -+ const struct expr *dep = ctx->pdep->expr; -+ uint8_t icmp_type; -+ -+ icmp_type = expr->payload.tmpl->icmp_dep; -+ if (icmp_type == PROTO_ICMP_ANY) -+ return false; -+ -+ if (dep->left->payload.desc != expr->payload.desc) -+ return false; -+ -+ icmp_type = icmp_dep_to_type(expr->payload.tmpl->icmp_dep); -+ -+ return ctx->icmp_type == icmp_type; -+} -+ - static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx, - unsigned int family, struct expr *expr) - { -@@ -661,6 +695,14 @@ static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx, - break; - } - -+ if (expr->payload.base == PROTO_BASE_TRANSPORT_HDR && -+ dep->left->payload.base == PROTO_BASE_TRANSPORT_HDR) { -+ if (dep->left->payload.desc == &proto_icmp) -+ return payload_may_dependency_kill_icmp(ctx, expr); -+ if (dep->left->payload.desc == &proto_icmp6) -+ return payload_may_dependency_kill_icmp(ctx, expr); -+ } -+ - return true; - } - -@@ -680,10 +722,6 @@ void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, - if (payload_dependency_exists(ctx, expr->payload.base) && - payload_may_dependency_kill(ctx, family, expr)) - payload_dependency_release(ctx); -- else if (ctx->icmp_type && ctx->pdep) { -- fprintf(stderr, "Did not kill \n"); -- payload_dependency_release(ctx); -- } - } - - void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, -@@ -707,23 +745,6 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr, - } - } - --static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t) --{ -- switch (t) { -- case PROTO_ICMP_ANY: -- BUG("Invalid map for simple dependency"); -- case PROTO_ICMP_ECHO: return ICMP_ECHO; -- case PROTO_ICMP6_ECHO: return ICMP6_ECHO_REQUEST; -- case PROTO_ICMP_MTU: return ICMP_DEST_UNREACH; -- case PROTO_ICMP_ADDRESS: return ICMP_REDIRECT; -- case PROTO_ICMP6_MTU: return ICMP6_PACKET_TOO_BIG; -- case PROTO_ICMP6_MGMQ: return MLD_LISTENER_QUERY; -- case PROTO_ICMP6_PPTR: return ICMP6_PARAM_PROB; -- } -- -- BUG("Missing icmp type mapping"); --} -- - /** - * payload_expr_complete - fill in type information of a raw payload expr - * --- -2.31.1 - diff --git a/SOURCES/0001-tests-shell-runtime-set-element-automerge.patch b/SOURCES/0001-tests-shell-runtime-set-element-automerge.patch new file mode 100644 index 0000000..12386d2 --- /dev/null +++ b/SOURCES/0001-tests-shell-runtime-set-element-automerge.patch @@ -0,0 +1,97 @@ +From 2a4f76ff5d5cc8d26a663ef8f8cd79c06560ca24 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 24 Jun 2022 16:02:59 +0200 +Subject: [PATCH] tests: shell: runtime set element automerge + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398 +Upstream Status: nftables commit 8fafe4e6b5b30 + +commit 8fafe4e6b5b30f2539f16403da8d5c5f819e523b +Author: Pablo Neira Ayuso +Date: Mon Jun 13 17:05:22 2022 +0200 + + tests: shell: runtime set element automerge + + Add a test to cover runtime set element automerge. + + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + tests/shell/testcases/sets/automerge_0 | 64 ++++++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + create mode 100755 tests/shell/testcases/sets/automerge_0 + +diff --git a/tests/shell/testcases/sets/automerge_0 b/tests/shell/testcases/sets/automerge_0 +new file mode 100755 +index 0000000..c9fb609 +--- /dev/null ++++ b/tests/shell/testcases/sets/automerge_0 +@@ -0,0 +1,64 @@ ++#!/bin/bash ++ ++set -e ++ ++RULESET="table inet x { ++ set y { ++ type inet_service ++ flags interval ++ auto-merge ++ } ++}" ++ ++$NFT -f - <<< $RULESET ++ ++tmpfile=$(mktemp) ++echo -n "add element inet x y { " > $tmpfile ++for ((i=0;i<65535;i+=2)) ++do ++ echo -n "$i, " >> $tmpfile ++ if [ $i -eq 65534 ] ++ then ++ echo -n "$i" >> $tmpfile ++ fi ++done ++echo "}" >> $tmpfile ++ ++$NFT -f $tmpfile ++ ++tmpfile2=$(mktemp) ++for ((i=1;i<65535;i+=2)) ++do ++ echo "$i" >> $tmpfile2 ++done ++ ++tmpfile3=$(mktemp) ++shuf $tmpfile2 > $tmpfile3 ++i=0 ++cat $tmpfile3 | while read line && [ $i -lt 10 ] ++do ++ $NFT add element inet x y { $line } ++ i=$((i+1)) ++done ++ ++for ((i=0;i<10;i++)) ++do ++ from=$(($RANDOM%65535)) ++ to=$(($from+100)) ++ $NFT add element inet x y { $from-$to } ++ if [ $? -ne 0 ] ++ then ++ echo "failed to add $from-$to" ++ exit 1 ++ fi ++ $NFT get element inet x y { $from-$to } ++ if [ $? -ne 0 ] ++ then ++ echo "failed to get $from-$to" ++ exit 1 ++ fi ++done ++ ++rm -f $tmpfile ++rm -f $tmpfile2 ++rm -f $tmpfile3 +-- +2.36.1 + diff --git a/SOURCES/0002-rule-collapse-set-element-commands.patch b/SOURCES/0002-rule-collapse-set-element-commands.patch new file mode 100644 index 0000000..abc1374 --- /dev/null +++ b/SOURCES/0002-rule-collapse-set-element-commands.patch @@ -0,0 +1,236 @@ +From 0fb0e506d01f99548dbb9cabfef713bea7e447b5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 24 Jun 2022 16:02:59 +0200 +Subject: [PATCH] rule: collapse set element commands + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398 +Upstream Status: nftables commit 498a5f0c219d8 + +commit 498a5f0c219d8a118af4f172f248647d9b077101 +Author: Pablo Neira Ayuso +Date: Mon Jun 13 17:22:44 2022 +0200 + + rule: collapse set element commands + + Robots might generate a long list of singleton element commands such as: + + add element t s { 1.0.1.0/24 } + ... + add element t s { 1.0.2.0/23 } + + collapse them into one single command before the evaluation step, ie. + + add element t s { 1.0.1.0/24, ..., 1.0.2.0/23 } + + this speeds up overlap detection and set element automerge operations in + this worst case scenario. + + Since 3da9643fb9ff9 ("intervals: add support to automerge with kernel + elements"), the new interval tracking relies on mergesort. The pattern + above triggers the set sorting for each element. + + This patch adds a list to cmd objects that store collapsed commands. + Moreover, expressions also contain a reference to the original command, + to uncollapse the commands after the evaluation step. + + These commands are uncollapsed after the evaluation step to ensure error + reporting works as expected (command and netlink message are mapped + 1:1). + + For the record: + + - nftables versions <= 1.0.2 did not perform any kind of overlap + check for the described scenario above (because set cache only contained + elements in the kernel in this case). This is a problem for kernels < 5.7 + which rely on userspace to detect overlaps. + + - the overlap detection could be skipped for kernels >= 5.7. + + - The extended netlink error reporting available for set elements + since 5.19-rc might allow to remove the uncollapse step, in this case, + error reporting does not rely on the netlink sequence to refer to the + command triggering the problem. + + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/expression.h | 1 + + include/rule.h | 3 ++ + src/libnftables.c | 17 ++++++++-- + src/rule.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 93 insertions(+), 3 deletions(-) + +diff --git a/include/expression.h b/include/expression.h +index 2c3818e..53194c9 100644 +--- a/include/expression.h ++++ b/include/expression.h +@@ -243,6 +243,7 @@ struct expr { + enum expr_types etype:8; + enum ops op:8; + unsigned int len; ++ struct cmd *cmd; + + union { + struct { +diff --git a/include/rule.h b/include/rule.h +index e232b97..9081225 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -700,6 +700,7 @@ struct cmd { + enum cmd_obj obj; + struct handle handle; + uint32_t seqnum; ++ struct list_head collapse_list; + union { + void *data; + struct expr *expr; +@@ -728,6 +729,8 @@ extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, + const struct handle *h, const struct location *loc, + void *data); + extern void nft_cmd_expand(struct cmd *cmd); ++extern bool nft_cmd_collapse(struct list_head *cmds); ++extern void nft_cmd_uncollapse(struct list_head *cmds); + extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type, + const struct handle *h, + const struct location *loc, struct obj *obj); +diff --git a/src/libnftables.c b/src/libnftables.c +index 6a22ea0..aac682b 100644 +--- a/src/libnftables.c ++++ b/src/libnftables.c +@@ -501,7 +501,9 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, + { + struct nft_cache_filter *filter; + struct cmd *cmd, *next; ++ bool collapsed = false; + unsigned int flags; ++ int err = 0; + + filter = nft_cache_filter_init(); + flags = nft_cache_evaluate(nft, cmds, filter); +@@ -512,17 +514,26 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, + + nft_cache_filter_fini(filter); + ++ if (nft_cmd_collapse(cmds)) ++ collapsed = true; ++ + list_for_each_entry_safe(cmd, next, cmds, list) { + struct eval_ctx ectx = { + .nft = nft, + .msgs = msgs, + }; ++ + if (cmd_evaluate(&ectx, cmd) < 0 && +- ++nft->state->nerrs == nft->parser_max_errors) +- return -1; ++ ++nft->state->nerrs == nft->parser_max_errors) { ++ err = -1; ++ break; ++ } + } + +- if (nft->state->nerrs) ++ if (collapsed) ++ nft_cmd_uncollapse(cmds); ++ ++ if (err < 0 || nft->state->nerrs) + return -1; + + list_for_each_entry(cmd, cmds, list) { +diff --git a/src/rule.c b/src/rule.c +index 7f61bdc..0526a14 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -1279,6 +1279,8 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, + cmd->handle = *h; + cmd->location = *loc; + cmd->data = data; ++ init_list_head(&cmd->collapse_list); ++ + return cmd; + } + +@@ -1379,6 +1381,79 @@ void nft_cmd_expand(struct cmd *cmd) + } + } + ++bool nft_cmd_collapse(struct list_head *cmds) ++{ ++ struct cmd *cmd, *next, *elems = NULL; ++ struct expr *expr, *enext; ++ bool collapse = false; ++ ++ list_for_each_entry_safe(cmd, next, cmds, list) { ++ if (cmd->op != CMD_ADD && ++ cmd->op != CMD_CREATE) { ++ elems = NULL; ++ continue; ++ } ++ ++ if (cmd->obj != CMD_OBJ_ELEMENTS) { ++ elems = NULL; ++ continue; ++ } ++ ++ if (!elems) { ++ elems = cmd; ++ continue; ++ } ++ ++ if (cmd->op != elems->op) { ++ elems = cmd; ++ continue; ++ } ++ ++ if (strcmp(elems->handle.table.name, cmd->handle.table.name) || ++ strcmp(elems->handle.set.name, cmd->handle.set.name)) { ++ elems = cmd; ++ continue; ++ } ++ ++ collapse = true; ++ list_for_each_entry_safe(expr, enext, &cmd->expr->expressions, list) { ++ expr->cmd = cmd; ++ list_move_tail(&expr->list, &elems->expr->expressions); ++ } ++ elems->expr->size += cmd->expr->size; ++ list_move_tail(&cmd->list, &elems->collapse_list); ++ } ++ ++ return collapse; ++} ++ ++void nft_cmd_uncollapse(struct list_head *cmds) ++{ ++ struct cmd *cmd, *cmd_next, *collapse_cmd, *collapse_cmd_next; ++ struct expr *expr, *next; ++ ++ list_for_each_entry_safe(cmd, cmd_next, cmds, list) { ++ if (list_empty(&cmd->collapse_list)) ++ continue; ++ ++ assert(cmd->obj == CMD_OBJ_ELEMENTS); ++ ++ list_for_each_entry_safe(expr, next, &cmd->expr->expressions, list) { ++ if (!expr->cmd) ++ continue; ++ ++ list_move_tail(&expr->list, &expr->cmd->expr->expressions); ++ cmd->expr->size--; ++ expr->cmd = NULL; ++ } ++ ++ list_for_each_entry_safe(collapse_cmd, collapse_cmd_next, &cmd->collapse_list, list) { ++ collapse_cmd->elem.set = set_get(cmd->elem.set); ++ list_add(&collapse_cmd->list, &cmd->list); ++ } ++ } ++} ++ + struct markup *markup_alloc(uint32_t format) + { + struct markup *markup; +-- +2.36.1 + diff --git a/SOURCES/0002-tests-add-icmp-6-test-where-dependency-should-be-lef.patch b/SOURCES/0002-tests-add-icmp-6-test-where-dependency-should-be-lef.patch deleted file mode 100644 index f412459..0000000 --- a/SOURCES/0002-tests-add-icmp-6-test-where-dependency-should-be-lef.patch +++ /dev/null @@ -1,165 +0,0 @@ -From bcd7ef679ca12700970e84fdd8ed38d8f58557ea Mon Sep 17 00:00:00 2001 -From: Florian Westphal -Date: Mon, 1 Feb 2021 22:44:25 +0100 -Subject: [PATCH] tests: add icmp/6 test where dependency should be left alone - -These tests fail: nft should leave the type as-is. - -Signed-off-by: Florian Westphal -(cherry picked from commit 3eb14fd93093c5e084d3ac1c4b0171cf80fb264f) - -Conflicts: - tests/py/ip/icmp.t.json - tests/py/ip6/icmpv6.t.json --> Context change it seems. - -Signed-off-by: Phil Sutter ---- - tests/py/ip/icmp.t | 2 ++ - tests/py/ip/icmp.t.json | 28 ++++++++++++++++++++ - tests/py/ip/icmp.t.payload.ip | 6 +++++ - tests/py/ip6/icmpv6.t | 2 ++ - tests/py/ip6/icmpv6.t.json | 44 +++++++++++++++++++++++++++++++ - tests/py/ip6/icmpv6.t.payload.ip6 | 7 +++++ - 6 files changed, 89 insertions(+) - -diff --git a/tests/py/ip/icmp.t b/tests/py/ip/icmp.t -index c22b55eb1e3f4..11f3662e2b027 100644 ---- a/tests/py/ip/icmp.t -+++ b/tests/py/ip/icmp.t -@@ -86,3 +86,5 @@ icmp gateway != { 33-55};ok - icmp gateway != 34;ok - icmp gateway != { 333, 334};ok - -+icmp code 1 icmp type 2;ok;icmp type 2 icmp code host-unreachable -+icmp code != 1 icmp type 2 icmp mtu 5;fail -diff --git a/tests/py/ip/icmp.t.json b/tests/py/ip/icmp.t.json -index 965eb10be9edf..2ea5b1a3e5e02 100644 ---- a/tests/py/ip/icmp.t.json -+++ b/tests/py/ip/icmp.t.json -@@ -1424,3 +1424,31 @@ - } - ] - -+# icmp code 1 icmp type 2 -+[ -+ { -+ "match": { -+ "left": { -+ "payload": { -+ "field": "type", -+ "protocol": "icmp" -+ } -+ }, -+ "op": "==", -+ "right": 2 -+ } -+ }, -+ { -+ "match": { -+ "left": { -+ "payload": { -+ "field": "code", -+ "protocol": "icmp" -+ } -+ }, -+ "op": "==", -+ "right": "host-unreachable" -+ } -+ } -+] -+ -diff --git a/tests/py/ip/icmp.t.payload.ip b/tests/py/ip/icmp.t.payload.ip -index d75d12a061252..97464a08379e3 100644 ---- a/tests/py/ip/icmp.t.payload.ip -+++ b/tests/py/ip/icmp.t.payload.ip -@@ -787,3 +787,9 @@ ip test-ip4 input - [ lookup reg 1 set __set%d ] - [ immediate reg 0 accept ] - -+# icmp code 1 icmp type 2 -+ip -+ [ meta load l4proto => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ [ payload load 2b @ transport header + 0 => reg 1 ] -+ [ cmp eq reg 1 0x00000102 ] -diff --git a/tests/py/ip6/icmpv6.t b/tests/py/ip6/icmpv6.t -index 8b411a8bf4392..d07c34bd939dc 100644 ---- a/tests/py/ip6/icmpv6.t -+++ b/tests/py/ip6/icmpv6.t -@@ -92,3 +92,5 @@ icmpv6 max-delay {33, 55, 67, 88};ok - icmpv6 max-delay != {33, 55, 67, 88};ok - icmpv6 max-delay {33-55};ok - icmpv6 max-delay != {33-55};ok -+ -+icmpv6 type parameter-problem icmpv6 code no-route;ok -diff --git a/tests/py/ip6/icmpv6.t.json b/tests/py/ip6/icmpv6.t.json -index f6cfbf172f562..be2f1b462bb18 100644 ---- a/tests/py/ip6/icmpv6.t.json -+++ b/tests/py/ip6/icmpv6.t.json -@@ -1300,3 +1300,47 @@ - } - ] - -+# icmpv6 type packet-too-big icmpv6 mtu 1280 -+[ -+ { -+ "match": { -+ "left": { -+ "payload": { -+ "field": "mtu", -+ "protocol": "icmpv6" -+ } -+ }, -+ "op": "==", -+ "right": 1280 -+ } -+ } -+] -+ -+# icmpv6 type parameter-problem icmpv6 code no-route -+[ -+ { -+ "match": { -+ "left": { -+ "payload": { -+ "field": "type", -+ "protocol": "icmpv6" -+ } -+ }, -+ "op": "==", -+ "right": "parameter-problem" -+ } -+ }, -+ { -+ "match": { -+ "left": { -+ "payload": { -+ "field": "code", -+ "protocol": "icmpv6" -+ } -+ }, -+ "op": "==", -+ "right": "no-route" -+ } -+ } -+] -+ -diff --git a/tests/py/ip6/icmpv6.t.payload.ip6 b/tests/py/ip6/icmpv6.t.payload.ip6 -index 171b7eade6d3e..448779d16922c 100644 ---- a/tests/py/ip6/icmpv6.t.payload.ip6 -+++ b/tests/py/ip6/icmpv6.t.payload.ip6 -@@ -682,3 +682,10 @@ ip6 test-ip6 input - [ payload load 2b @ transport header + 4 => reg 1 ] - [ lookup reg 1 set __set%d 0x1 ] - -+# icmpv6 type parameter-problem icmpv6 code no-route -+ip6 -+ [ meta load l4proto => reg 1 ] -+ [ cmp eq reg 1 0x0000003a ] -+ [ payload load 2b @ transport header + 0 => reg 1 ] -+ [ cmp eq reg 1 0x00000004 ] -+ --- -2.31.1 - diff --git a/SOURCES/0003-intervals-do-not-report-exact-overlaps-for-new-eleme.patch b/SOURCES/0003-intervals-do-not-report-exact-overlaps-for-new-eleme.patch new file mode 100644 index 0000000..4be2549 --- /dev/null +++ b/SOURCES/0003-intervals-do-not-report-exact-overlaps-for-new-eleme.patch @@ -0,0 +1,84 @@ +From afd566b56629bac4c8ca622413c8c001e2e7edfa Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 24 Jun 2022 16:02:59 +0200 +Subject: [PATCH] intervals: do not report exact overlaps for new elements + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398 +Upstream Status: nftables commit 87ba510fc704f + +commit 87ba510fc704f766b5417d3bfc326e8ab9378c2a +Author: Pablo Neira Ayuso +Date: Mon Jun 13 17:22:47 2022 +0200 + + intervals: do not report exact overlaps for new elements + + Two new elements that represent an exact overlap should not trigger an error. + + add table t + add set t s { type ipv4_addr; flags interval; } + add element t s { 1.0.1.0/24 } + ... + add element t s { 1.0.1.0/24 } + + result in a bogus error. + + # nft -f set.nft + set.nft:1002:19-28: Error: conflicting intervals specified + add element t s { 1.0.1.0/24 } + ^^^^^^^^^^ + + Fixes: 3da9643fb9ff ("intervals: add support to automerge with kernel elements") + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + src/intervals.c | 3 +-- + tests/shell/testcases/sets/exact_overlap_0 | 22 ++++++++++++++++++++++ + 2 files changed, 23 insertions(+), 2 deletions(-) + create mode 100755 tests/shell/testcases/sets/exact_overlap_0 + +diff --git a/src/intervals.c b/src/intervals.c +index bc414d6..89f5c33 100644 +--- a/src/intervals.c ++++ b/src/intervals.c +@@ -540,8 +540,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set, + } + + if (mpz_cmp(prev_range.low, range.low) == 0 && +- mpz_cmp(prev_range.high, range.high) == 0 && +- (elem->flags & EXPR_F_KERNEL || prev->flags & EXPR_F_KERNEL)) ++ mpz_cmp(prev_range.high, range.high) == 0) + goto next; + + if (mpz_cmp(prev_range.low, range.low) <= 0 && +diff --git a/tests/shell/testcases/sets/exact_overlap_0 b/tests/shell/testcases/sets/exact_overlap_0 +new file mode 100755 +index 0000000..1ce9304 +--- /dev/null ++++ b/tests/shell/testcases/sets/exact_overlap_0 +@@ -0,0 +1,22 @@ ++#!/bin/bash ++ ++RULESET="add table t ++add set t s { type ipv4_addr; flags interval; } ++add element t s { 1.0.1.0/24 } ++add element t s { 1.0.2.0/23 } ++add element t s { 1.0.8.0/21 } ++add element t s { 1.0.32.0/19 } ++add element t s { 1.1.0.0/24 } ++add element t s { 1.1.2.0/23 } ++add element t s { 1.1.4.0/22 } ++add element t s { 1.1.8.0/24 } ++add element t s { 1.1.9.0/24 } ++add element t s { 1.1.10.0/23 } ++add element t s { 1.1.12.0/22 } ++add element t s { 1.1.16.0/20 } ++add element t s { 1.1.32.0/19 } ++add element t s { 1.0.1.0/24 }" ++ ++$NFT -f - <<< $RULESET || exit 1 ++ ++$NFT add element t s { 1.0.1.0/24 } +-- +2.36.1 + diff --git a/SOURCES/0003-main-fix-nft-help-output-fallout-from-719e4427.patch b/SOURCES/0003-main-fix-nft-help-output-fallout-from-719e4427.patch deleted file mode 100644 index a9293bc..0000000 --- a/SOURCES/0003-main-fix-nft-help-output-fallout-from-719e4427.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 5f91359f1bbcd73346e4469f0b5a30e04f107a06 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= -Date: Mon, 22 Feb 2021 13:03:19 +0100 -Subject: [PATCH] main: fix nft --help output fallout from 719e4427 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Long options were missing the double dash. - -Fixes: 719e44277f8e ("main: use one data-structure to initialize getopt_long(3) arguments and help.") -Cc: Jeremy Sowden -Signed-off-by: Štěpán Němec -Signed-off-by: Pablo Neira Ayuso -(cherry picked from commit b8c6dd1a9c0c6e937febc113e7ea89079aa945be) -Signed-off-by: Phil Sutter ---- - src/main.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/src/main.c b/src/main.c -index 80cf1acf0f7f4..8c47064459ecb 100644 ---- a/src/main.c -+++ b/src/main.c -@@ -175,16 +175,17 @@ static const struct option *get_options(void) - - static void print_option(const struct nft_opt *opt) - { -- char optbuf[33] = ""; -+ char optbuf[35] = ""; - int i; - - i = snprintf(optbuf, sizeof(optbuf), " -%c", opt->val); - if (opt->name) -- i += snprintf(optbuf + i, sizeof(optbuf) - i, ", %s", opt->name); -+ i += snprintf(optbuf + i, sizeof(optbuf) - i, ", --%s", -+ opt->name); - if (opt->arg) - i += snprintf(optbuf + i, sizeof(optbuf) - i, " %s", opt->arg); - -- printf("%-32s%s\n", optbuf, opt->help); -+ printf("%-34s%s\n", optbuf, opt->help); - } - - static void show_help(const char *name) --- -2.31.1 - diff --git a/SOURCES/0004-intervals-do-not-empty-cache-for-maps.patch b/SOURCES/0004-intervals-do-not-empty-cache-for-maps.patch new file mode 100644 index 0000000..684d2a1 --- /dev/null +++ b/SOURCES/0004-intervals-do-not-empty-cache-for-maps.patch @@ -0,0 +1,55 @@ +From 5a1d00b37a06bdf37bf392af05236469b6636fb9 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 24 Jun 2022 16:02:59 +0200 +Subject: [PATCH] intervals: do not empty cache for maps + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398 +Upstream Status: nftables commit d434de8b50dcf + +commit d434de8b50dcf3f5f4ca027e122a7df9d4e5d8e1 +Author: Pablo Neira Ayuso +Date: Thu Jun 16 10:53:56 2022 +0200 + + intervals: do not empty cache for maps + + Translate set element to range and sort in maps for the NFT_SET_MAP + case, which does not support for automerge yet. + + Fixes: 81e36530fcac ("src: replace interval segment tree overlap and automerge") + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + src/intervals.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/intervals.c b/src/intervals.c +index 89f5c33..e203413 100644 +--- a/src/intervals.c ++++ b/src/intervals.c +@@ -216,6 +216,12 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, + struct cmd *purge_cmd; + struct handle h = {}; + ++ if (set->flags & NFT_SET_MAP) { ++ set_to_range(init); ++ list_expr_sort(&init->expressions); ++ return 0; ++ } ++ + if (existing_set) { + if (existing_set->init) { + list_splice_init(&existing_set->init->expressions, +@@ -229,9 +235,6 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, + set_to_range(init); + list_expr_sort(&init->expressions); + +- if (set->flags & NFT_SET_MAP) +- return 0; +- + ctx.purge = set_expr_alloc(&internal_location, set); + + setelem_automerge(&ctx); +-- +2.36.1 + diff --git a/SOURCES/0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch b/SOURCES/0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch deleted file mode 100644 index 6573573..0000000 --- a/SOURCES/0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch +++ /dev/null @@ -1,30 +0,0 @@ -From f09f39704d8bfa15d236b6891aabef270ec43d73 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:03:32 +0200 -Subject: [PATCH] parser_bison: Fix for implicit declaration of isalnum - -Have to include ctype.h to make it known. - -Fixes: e76bb37940181 ("src: allow for variables in the log prefix string") -Signed-off-by: Phil Sutter -(cherry picked from commit 7c3b2a7acbdc793b822a230ec0c28086c7d0365d) -Signed-off-by: Phil Sutter ---- - src/parser_bison.y | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/parser_bison.y b/src/parser_bison.y -index 519e8efe5ab7e..8644f66106496 100644 ---- a/src/parser_bison.y -+++ b/src/parser_bison.y -@@ -10,6 +10,7 @@ - - %{ - -+#include - #include - #include - #include --- -2.31.1 - diff --git a/SOURCES/0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch b/SOURCES/0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch new file mode 100644 index 0000000..6a4122f --- /dev/null +++ b/SOURCES/0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch @@ -0,0 +1,139 @@ +From 013a3b226a0fa5f7a8469bae736150cbf2d092c4 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 24 Jun 2022 16:02:59 +0200 +Subject: [PATCH] intervals: Do not sort cached set elements over and over + again + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398 +Upstream Status: nftables commit 59e3a59221fb8 + +commit 59e3a59221fb81c289a0868a85140dd452fb1c30 +Author: Phil Sutter +Date: Thu Jun 16 10:56:12 2022 +0200 + + intervals: Do not sort cached set elements over and over again + + When adding element(s) to a non-empty set, code merged the two lists and + sorted the result. With many individual 'add element' commands this + causes substantial overhead. Make use of the fact that + existing_set->init is sorted already, sort only the list of new elements + and use list_splice_sorted() to merge the two sorted lists. + + Add set_sort_splice() and use it for set element overlap detection and + automerge. + + A test case adding ~25k elements in individual commands completes in + about 1/4th of the time with this patch applied. + + Joint work with Pablo. + + Fixes: 3da9643fb9ff9 ("intervals: add support to automerge with kernel elements") + Signed-off-by: Phil Sutter + Signed-off-by: Pablo Neira Ayuso + +Signed-off-by: Phil Sutter +--- + include/expression.h | 1 + + src/intervals.c | 46 +++++++++++++++++++++----------------------- + src/mergesort.c | 2 +- + 3 files changed, 24 insertions(+), 25 deletions(-) + +diff --git a/include/expression.h b/include/expression.h +index 53194c9..cf7319b 100644 +--- a/include/expression.h ++++ b/include/expression.h +@@ -481,6 +481,7 @@ extern struct expr *compound_expr_alloc(const struct location *loc, + extern void compound_expr_add(struct expr *compound, struct expr *expr); + extern void compound_expr_remove(struct expr *compound, struct expr *expr); + extern void list_expr_sort(struct list_head *head); ++extern void list_splice_sorted(struct list_head *list, struct list_head *head); + + extern struct expr *concat_expr_alloc(const struct location *loc); + +diff --git a/src/intervals.c b/src/intervals.c +index e203413..dcc06d1 100644 +--- a/src/intervals.c ++++ b/src/intervals.c +@@ -118,6 +118,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx, + return false; + } + ++static void set_sort_splice(struct expr *init, struct set *set) ++{ ++ struct set *existing_set = set->existing_set; ++ ++ set_to_range(init); ++ list_expr_sort(&init->expressions); ++ ++ if (!existing_set) ++ return; ++ ++ if (existing_set->init) { ++ set_to_range(existing_set->init); ++ list_splice_sorted(&existing_set->init->expressions, ++ &init->expressions); ++ init_list_head(&existing_set->init->expressions); ++ } else { ++ existing_set->init = set_expr_alloc(&internal_location, set); ++ } ++} ++ + static void setelem_automerge(struct set_automerge_ctx *ctx) + { + struct expr *i, *next, *prev = NULL; +@@ -222,18 +242,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set, + return 0; + } + +- if (existing_set) { +- if (existing_set->init) { +- list_splice_init(&existing_set->init->expressions, +- &init->expressions); +- } else { +- existing_set->init = set_expr_alloc(&internal_location, +- set); +- } +- } +- +- set_to_range(init); +- list_expr_sort(&init->expressions); ++ set_sort_splice(init, set); + + ctx.purge = set_expr_alloc(&internal_location, set); + +@@ -591,18 +600,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init) + struct expr *i, *n, *clone; + int err; + +- if (existing_set) { +- if (existing_set->init) { +- list_splice_init(&existing_set->init->expressions, +- &init->expressions); +- } else { +- existing_set->init = set_expr_alloc(&internal_location, +- set); +- } +- } +- +- set_to_range(init); +- list_expr_sort(&init->expressions); ++ set_sort_splice(init, set); + + err = setelem_overlap(msgs, set, init); + +diff --git a/src/mergesort.c b/src/mergesort.c +index 8e6aac5..dca7142 100644 +--- a/src/mergesort.c ++++ b/src/mergesort.c +@@ -70,7 +70,7 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2) + return ret; + } + +-static void list_splice_sorted(struct list_head *list, struct list_head *head) ++void list_splice_sorted(struct list_head *list, struct list_head *head) + { + struct list_head *h = head->next; + struct list_head *l = list->next; +-- +2.36.1 + diff --git a/SOURCES/0005-parser_json-Fix-for-memleak-in-tcp-option-error-path.patch b/SOURCES/0005-parser_json-Fix-for-memleak-in-tcp-option-error-path.patch deleted file mode 100644 index 5a4a726..0000000 --- a/SOURCES/0005-parser_json-Fix-for-memleak-in-tcp-option-error-path.patch +++ /dev/null @@ -1,39 +0,0 @@ -From a79e92c0f6761a748ef3cbffd26a4f1db82b4b3e Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:07:02 +0200 -Subject: [PATCH] parser_json: Fix for memleak in tcp option error path - -If 'kind' value is invalid, the function returned without freeing 'expr' -first. Fix this by performing the check before allocation. - -Fixes: cb21869649208 ("json: tcp: add raw tcp option match support") -Signed-off-by: Phil Sutter -(cherry picked from commit f7b0eef8391ae7f89a3a82f6eeecaebe199224d7) -Signed-off-by: Phil Sutter ---- - src/parser_json.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/parser_json.c b/src/parser_json.c -index f0486b77a225a..85d05ce27eef3 100644 ---- a/src/parser_json.c -+++ b/src/parser_json.c -@@ -611,12 +611,12 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx, - "base", &kind, "offset", &offset, "len", &len)) { - uint32_t flag = 0; - -- expr = tcpopt_expr_alloc(int_loc, kind, -- TCPOPT_COMMON_KIND); -- - if (kind < 0 || kind > 255) - return NULL; - -+ expr = tcpopt_expr_alloc(int_loc, kind, -+ TCPOPT_COMMON_KIND); -+ - if (offset == TCPOPT_COMMON_KIND && len == 8) - flag = NFT_EXTHDR_F_PRESENT; - --- -2.31.1 - diff --git a/SOURCES/0006-evaluate-Mark-fall-through-case-in-str2hooknum.patch b/SOURCES/0006-evaluate-Mark-fall-through-case-in-str2hooknum.patch deleted file mode 100644 index 04180b5..0000000 --- a/SOURCES/0006-evaluate-Mark-fall-through-case-in-str2hooknum.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 07ebd0fa9300176f818789fde2498422fa421090 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:19:18 +0200 -Subject: [PATCH] evaluate: Mark fall through case in str2hooknum() - -It is certainly intentional, so just mark it as such. - -Fixes: b4775dec9f80b ("src: ingress inet support") -Signed-off-by: Phil Sutter -(cherry picked from commit c2e06beef3390867901080c0d789e3b6257e2b98) -Signed-off-by: Phil Sutter ---- - src/evaluate.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/evaluate.c b/src/evaluate.c -index c830dcdbd9651..2a897f469434a 100644 ---- a/src/evaluate.c -+++ b/src/evaluate.c -@@ -4030,6 +4030,7 @@ static uint32_t str2hooknum(uint32_t family, const char *hook) - case NFPROTO_INET: - if (!strcmp(hook, "ingress")) - return NF_INET_INGRESS; -+ /* fall through */ - case NFPROTO_IPV4: - case NFPROTO_BRIDGE: - case NFPROTO_IPV6: --- -2.31.1 - diff --git a/SOURCES/0007-json-Drop-pointless-assignment-in-exthdr_expr_json.patch b/SOURCES/0007-json-Drop-pointless-assignment-in-exthdr_expr_json.patch deleted file mode 100644 index 2a97351..0000000 --- a/SOURCES/0007-json-Drop-pointless-assignment-in-exthdr_expr_json.patch +++ /dev/null @@ -1,30 +0,0 @@ -From a7da4f45cc1c8419b38e3e9adf0e15bedb8b0257 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:23:22 +0200 -Subject: [PATCH] json: Drop pointless assignment in exthdr_expr_json() - -The updated value of 'is_exists' is no longer read at this point. - -Fixes: cb21869649208 ("json: tcp: add raw tcp option match support") -Signed-off-by: Phil Sutter -(cherry picked from commit c1616dfd1ce40bac197924c8947e1c646e915dca) -Signed-off-by: Phil Sutter ---- - src/json.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/json.c b/src/json.c -index 585d35326ac01..1fb5015124e16 100644 ---- a/src/json.c -+++ b/src/json.c -@@ -692,7 +692,6 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) - "base", expr->exthdr.raw_type, - "offset", expr->exthdr.offset, - "len", expr->len); -- is_exists = false; - } - - return json_pack("{s:o}", "tcp option", root); --- -2.31.1 - diff --git a/SOURCES/0008-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch b/SOURCES/0008-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch deleted file mode 100644 index 253acbf..0000000 --- a/SOURCES/0008-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 2344a35f90ef4a467b6bb9779fc687b17f4a4b51 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:43:21 +0200 -Subject: [PATCH] netlink: Avoid memleak in error path of - netlink_delinearize_set() - -Duplicate string 'comment' later when the function does not fail -anymore. - -Fixes: 0864c2d49ee8a ("src: add comment support for set declarations") -Signed-off-by: Phil Sutter -(cherry picked from commit accd7a346fd19f1ffc503b3f681323abf1157c1a) -Signed-off-by: Phil Sutter ---- - src/netlink.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/netlink.c b/src/netlink.c -index ec2dad29ace1c..5c38a9f157d38 100644 ---- a/src/netlink.c -+++ b/src/netlink.c -@@ -840,7 +840,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, - if (ud[NFTNL_UDATA_SET_DATA_TYPEOF]) - typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]); - if (ud[NFTNL_UDATA_SET_COMMENT]) -- comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT])); -+ comment = nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT]); - } - - key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE); -@@ -878,7 +878,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, - set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME)); - set->automerge = automerge; - if (comment) -- set->comment = comment; -+ set->comment = xstrdup(comment); - - init_list_head(&set_parse_ctx.stmt_list); - --- -2.31.1 - diff --git a/SOURCES/0009-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch b/SOURCES/0009-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch deleted file mode 100644 index d8539ab..0000000 --- a/SOURCES/0009-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 6cbc04136a91eca237476827b57e78ac29e00aeb Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 18:32:13 +0200 -Subject: [PATCH] netlink: Avoid memleak in error path of - netlink_delinearize_chain() - -If parsing udata fails, 'chain' has to be freed before returning to -caller. - -Fixes: 702ac2b72c0e8 ("src: add comment support for chains") -Signed-off-by: Phil Sutter -(cherry picked from commit 04f7af9dd66d3a0f627f43bc4bf55bae9856efc8) -Signed-off-by: Phil Sutter ---- - src/netlink.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/netlink.c b/src/netlink.c -index 5c38a9f157d38..22140afc3fd7e 100644 ---- a/src/netlink.c -+++ b/src/netlink.c -@@ -573,6 +573,7 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, - udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen); - if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) { - netlink_io_error(ctx, NULL, "Cannot parse userdata"); -+ chain_free(chain); - return NULL; - } - if (ud[NFTNL_UDATA_CHAIN_COMMENT]) --- -2.31.1 - diff --git a/SOURCES/0010-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch b/SOURCES/0010-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch deleted file mode 100644 index 67fad59..0000000 --- a/SOURCES/0010-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c47e6d3b1ccb166b807d19fd585d6b5b3cd0b7f7 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 18:33:44 +0200 -Subject: [PATCH] netlink: Avoid memleak in error path of - netlink_delinearize_table() - -If parsing udata fails, 'table' has to be freed before returning to -caller. - -Fixes: c156232a530b3 ("src: add comment support when adding tables") -Signed-off-by: Phil Sutter -(cherry picked from commit 47640634cff9932784a1a96836d6c5809cc8264d) -Signed-off-by: Phil Sutter ---- - src/netlink.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/netlink.c b/src/netlink.c -index 22140afc3fd7e..fd82b16cb9f6e 100644 ---- a/src/netlink.c -+++ b/src/netlink.c -@@ -620,6 +620,7 @@ struct table *netlink_delinearize_table(struct netlink_ctx *ctx, - udata = nftnl_table_get_data(nlt, NFTNL_TABLE_USERDATA, &ulen); - if (nftnl_udata_parse(udata, ulen, table_parse_udata_cb, ud) < 0) { - netlink_io_error(ctx, NULL, "Cannot parse userdata"); -+ table_free(table); - return NULL; - } - if (ud[NFTNL_UDATA_TABLE_COMMENT]) --- -2.31.1 - diff --git a/SOURCES/0011-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch b/SOURCES/0011-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch deleted file mode 100644 index 9b4e889..0000000 --- a/SOURCES/0011-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3ec01f287b0b61c0e6d885a7e96dcfa5afa800b8 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 16:46:48 +0200 -Subject: [PATCH] netlink: Avoid memleak in error path of - netlink_delinearize_obj() - -If parsing udata fails, 'obj' has to be freed before returning to -caller. - -Fixes: 293c9b114faef ("src: add comment support for objects") -Signed-off-by: Phil Sutter -(cherry picked from commit 97b5d4bbcac4d3237f114c1c6a57c37968ebe0fc) -Signed-off-by: Phil Sutter ---- - src/netlink.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/netlink.c b/src/netlink.c -index fd82b16cb9f6e..4c03baeff5d66 100644 ---- a/src/netlink.c -+++ b/src/netlink.c -@@ -1445,6 +1445,7 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx, - udata = nftnl_obj_get_data(nlo, NFTNL_OBJ_USERDATA, &ulen); - if (nftnl_udata_parse(udata, ulen, obj_parse_udata_cb, ud) < 0) { - netlink_io_error(ctx, NULL, "Cannot parse userdata"); -+ obj_free(obj); - return NULL; - } - if (ud[NFTNL_UDATA_OBJ_COMMENT]) --- -2.31.1 - diff --git a/SOURCES/0012-netlink_delinearize-Fix-suspicious-calloc-call.patch b/SOURCES/0012-netlink_delinearize-Fix-suspicious-calloc-call.patch deleted file mode 100644 index ac21f56..0000000 --- a/SOURCES/0012-netlink_delinearize-Fix-suspicious-calloc-call.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d8322b08998a6945b659078b5cc4bd7423194f70 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 17:02:01 +0200 -Subject: [PATCH] netlink_delinearize: Fix suspicious calloc() call - -Parameter passed to sizeof() was wrong. While being at it, replace the -whole call with xmalloc_array() which takes care of error checking. - -Fixes: 913979f882d13 ("src: add expression handler hashtable") -Signed-off-by: Phil Sutter -(cherry picked from commit c4058f96c6a55e4fcd49d4380ac07b5466ec01c0) -Signed-off-by: Phil Sutter ---- - src/netlink_delinearize.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c -index 7315072284119..152b3e6cf8c65 100644 ---- a/src/netlink_delinearize.c -+++ b/src/netlink_delinearize.c -@@ -1732,9 +1732,8 @@ void expr_handler_init(void) - unsigned int i; - uint32_t hash; - -- expr_handle_ht = calloc(NFT_EXPR_HSIZE, sizeof(expr_handle_ht)); -- if (!expr_handle_ht) -- memory_allocation_error(); -+ expr_handle_ht = xmalloc_array(NFT_EXPR_HSIZE, -+ sizeof(expr_handle_ht[0])); - - for (i = 0; i < array_size(netlink_parsers); i++) { - hash = djb_hash(netlink_parsers[i].name) % NFT_EXPR_HSIZE; --- -2.31.1 - diff --git a/SOURCES/0013-rule-Fix-for-potential-off-by-one-in-cmd_add_loc.patch b/SOURCES/0013-rule-Fix-for-potential-off-by-one-in-cmd_add_loc.patch deleted file mode 100644 index ae87cde..0000000 --- a/SOURCES/0013-rule-Fix-for-potential-off-by-one-in-cmd_add_loc.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 5fbf4169fba1dfef0f461c4fe31bed70610ebce2 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Fri, 11 Jun 2021 17:08:34 +0200 -Subject: [PATCH] rule: Fix for potential off-by-one in cmd_add_loc() - -Using num_attrs as index means it must be at max one less than the -array's size at function start. - -Fixes: 27362a5bfa433 ("rule: larger number of error locations") -Signed-off-by: Phil Sutter -(cherry picked from commit 2d0a7a9adeb30708d6fbbee57476c0d4b9214dbd) -Signed-off-by: Phil Sutter ---- - src/rule.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/rule.c b/src/rule.c -index e4bb6bae276a0..03422da3a7560 100644 ---- a/src/rule.c -+++ b/src/rule.c -@@ -1491,7 +1491,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, - - void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc) - { -- if (cmd->num_attrs > NFT_NLATTR_LOC_MAX) -+ if (cmd->num_attrs >= NFT_NLATTR_LOC_MAX) - return; - - cmd->attr[cmd->num_attrs].offset = offset; --- -2.31.1 - diff --git a/SOURCES/0014-src-add-xzalloc_array-and-use-it-to-allocate-the-exp.patch b/SOURCES/0014-src-add-xzalloc_array-and-use-it-to-allocate-the-exp.patch deleted file mode 100644 index 0845e96..0000000 --- a/SOURCES/0014-src-add-xzalloc_array-and-use-it-to-allocate-the-exp.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 6509f63cb68ea2dd737f9b52c146803402efcd7a Mon Sep 17 00:00:00 2001 -From: Pablo Neira Ayuso -Date: Mon, 14 Jun 2021 14:47:47 +0200 -Subject: [PATCH] src: add xzalloc_array() and use it to allocate the - expression hashtable - -Otherwise, assertion to ensure that no colission occur is hit due to -uninitialized hashtable memory area: - -nft: netlink_delinearize.c:1741: expr_handler_init: Assertion `expr_handle_ht[hash] == NULL' failed. - -Fixes: c4058f96c6a5 ("netlink_delinearize: Fix suspicious calloc() call") -Acked-by: Phil Sutter -Signed-off-by: Pablo Neira Ayuso -(cherry picked from commit b0e7b294224030abc534c396fffcab9fbce12b11) -Signed-off-by: Phil Sutter ---- - include/utils.h | 1 + - src/netlink_delinearize.c | 2 +- - src/utils.c | 10 ++++++++++ - 3 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/include/utils.h b/include/utils.h -index f45f25132d18d..ffbe2cbb75be5 100644 ---- a/include/utils.h -+++ b/include/utils.h -@@ -133,6 +133,7 @@ extern void *xmalloc(size_t size); - extern void *xmalloc_array(size_t nmemb, size_t size); - extern void *xrealloc(void *ptr, size_t size); - extern void *xzalloc(size_t size); -+extern void *xzalloc_array(size_t nmemb, size_t size); - extern char *xstrdup(const char *s); - extern void xstrunescape(const char *in, char *out); - -diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c -index 152b3e6cf8c65..7665d6f29c602 100644 ---- a/src/netlink_delinearize.c -+++ b/src/netlink_delinearize.c -@@ -1732,7 +1732,7 @@ void expr_handler_init(void) - unsigned int i; - uint32_t hash; - -- expr_handle_ht = xmalloc_array(NFT_EXPR_HSIZE, -+ expr_handle_ht = xzalloc_array(NFT_EXPR_HSIZE, - sizeof(expr_handle_ht[0])); - - for (i = 0; i < array_size(netlink_parsers); i++) { -diff --git a/src/utils.c b/src/utils.c -index 47f5b791547b1..925841c571f5d 100644 ---- a/src/utils.c -+++ b/src/utils.c -@@ -50,6 +50,16 @@ void *xmalloc_array(size_t nmemb, size_t size) - return xmalloc(nmemb * size); - } - -+void *xzalloc_array(size_t nmemb, size_t size) -+{ -+ void *ptr; -+ -+ ptr = xmalloc_array(nmemb, size); -+ memset(ptr, 0, nmemb * size); -+ -+ return ptr; -+} -+ - void *xrealloc(void *ptr, size_t size) - { - ptr = realloc(ptr, size); --- -2.31.1 - diff --git a/SOURCES/0015-json-init-parser-state-for-every-new-buffer-file.patch b/SOURCES/0015-json-init-parser-state-for-every-new-buffer-file.patch deleted file mode 100644 index 16a0630..0000000 --- a/SOURCES/0015-json-init-parser-state-for-every-new-buffer-file.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 27f931c935f27a00fe0ecbe8c4bcb3be6ba41096 Mon Sep 17 00:00:00 2001 -From: Eric Garver -Date: Fri, 19 Feb 2021 10:11:26 -0500 -Subject: [PATCH] json: init parser state for every new buffer/file - -Otherwise invalid error states cause subsequent json parsing to fail -when it should not. - -Signed-off-by: Eric Garver -Signed-off-by: Phil Sutter -(cherry picked from commit 267338ec392346ef55ed51509e5f8e8354d6c19a) ---- - src/parser_json.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/parser_json.c b/src/parser_json.c -index 85d05ce27eef3..9bba77dad5f0d 100644 ---- a/src/parser_json.c -+++ b/src/parser_json.c -@@ -3893,6 +3893,7 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf, - }; - int ret; - -+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope); - nft->json_root = json_loads(buf, 0, NULL); - if (!nft->json_root) - return -EINVAL; -@@ -3921,6 +3922,7 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename, - json_error_t err; - int ret; - -+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope); - nft->json_root = json_load_file(filename, 0, &err); - if (!nft->json_root) - return -EINVAL; --- -2.31.1 - diff --git a/SOURCES/0016-segtree-Fix-segfault-when-restoring-a-huge-interval-.patch b/SOURCES/0016-segtree-Fix-segfault-when-restoring-a-huge-interval-.patch deleted file mode 100644 index 5051a9e..0000000 --- a/SOURCES/0016-segtree-Fix-segfault-when-restoring-a-huge-interval-.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 24d7383ca9e7f056153cc305ee16fa9fd8580909 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Wed, 9 Jun 2021 15:49:52 +0200 -Subject: [PATCH] segtree: Fix segfault when restoring a huge interval set - -Restoring a set of IPv4 prefixes with about 1.1M elements crashes nft as -set_to_segtree() exhausts the stack. Prevent this by allocating the -pointer array on heap and make sure it is freed before returning to -caller. - -With this patch in place, restoring said set succeeds with allocation of -about 3GB of memory, according to valgrind. - -Signed-off-by: Phil Sutter -(cherry picked from commit baecd1cf26851a4c5b7d469206a488f14fe5b147) ---- - src/segtree.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/src/segtree.c b/src/segtree.c -index 9aa39e52d8a09..163a7bb755f9c 100644 ---- a/src/segtree.c -+++ b/src/segtree.c -@@ -429,10 +429,10 @@ static int set_to_segtree(struct list_head *msgs, struct set *set, - struct expr *init, struct seg_tree *tree, - bool add, bool merge) - { -- struct elementary_interval *intervals[init->size]; -+ struct elementary_interval **intervals; - struct expr *i, *next; - unsigned int n; -- int err; -+ int err = 0; - - /* We are updating an existing set with new elements, check if the new - * interval overlaps with any of the existing ones. -@@ -443,6 +443,7 @@ static int set_to_segtree(struct list_head *msgs, struct set *set, - return err; - } - -+ intervals = xmalloc_array(init->size, sizeof(intervals[0])); - n = expr_to_intervals(init, tree->keylen, intervals); - - list_for_each_entry_safe(i, next, &init->expressions, list) { -@@ -461,10 +462,11 @@ static int set_to_segtree(struct list_head *msgs, struct set *set, - for (n = 0; n < init->size; n++) { - err = ei_insert(msgs, tree, intervals[n], merge); - if (err < 0) -- return err; -+ break; - } - -- return 0; -+ xfree(intervals); -+ return err; - } - - static bool segtree_needs_first_segment(const struct set *set, --- -2.33.0 - diff --git a/SOURCES/0017-tests-cover-baecd1cf2685-segtree-Fix-segfault-when-r.patch b/SOURCES/0017-tests-cover-baecd1cf2685-segtree-Fix-segfault-when-r.patch deleted file mode 100644 index a0d7945..0000000 --- a/SOURCES/0017-tests-cover-baecd1cf2685-segtree-Fix-segfault-when-r.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 2c4a6a4f1d51358a196a7039c41b7d50df656985 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= -Date: Wed, 20 Oct 2021 14:42:20 +0200 -Subject: [PATCH] tests: cover baecd1cf2685 ("segtree: Fix segfault when - restoring a huge interval set") -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Test inspired by [1] with both the set and stack size reduced by the -same power of 2, to preserve the (pre-baecd1cf2685) segfault on one -hand, and make the test successfully complete (post-baecd1cf2685) in a -few seconds even on weaker hardware on the other. - -(The reason I stopped at 128kB stack size is that with 64kB I was -getting segfaults even with baecd1cf2685 applied.) - -[1] https://bugzilla.redhat.com/show_bug.cgi?id=1908127 - -Signed-off-by: Štěpán Němec -Helped-by: Phil Sutter -Signed-off-by: Phil Sutter -(cherry picked from commit d8ccad2a2b73c4189934eb5fd0e3d096699b5043) ---- - .../sets/0068interval_stack_overflow_0 | 29 +++++++++++++++++++ - 1 file changed, 29 insertions(+) - create mode 100755 tests/shell/testcases/sets/0068interval_stack_overflow_0 - -diff --git a/tests/shell/testcases/sets/0068interval_stack_overflow_0 b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -new file mode 100755 -index 0000000000000..134282de28268 ---- /dev/null -+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -@@ -0,0 +1,29 @@ -+#!/bin/bash -+ -+set -e -+ -+ruleset_file=$(mktemp) -+ -+trap 'rm -f "$ruleset_file"' EXIT -+ -+{ -+ echo 'define big_set = {' -+ for ((i = 1; i < 255; i++)); do -+ for ((j = 1; j < 80; j++)); do -+ echo "10.0.$i.$j," -+ done -+ done -+ echo '10.1.0.0/24 }' -+} >"$ruleset_file" -+ -+cat >>"$ruleset_file" <<\EOF -+table inet test68_table { -+ set test68_set { -+ type ipv4_addr -+ flags interval -+ elements = { $big_set } -+ } -+} -+EOF -+ -+( ulimit -s 128 && "$NFT" -f "$ruleset_file" ) --- -2.33.0 - diff --git a/SOURCES/0018-doc-nft.8-Extend-monitor-description-by-trace.patch b/SOURCES/0018-doc-nft.8-Extend-monitor-description-by-trace.patch deleted file mode 100644 index b58ed8a..0000000 --- a/SOURCES/0018-doc-nft.8-Extend-monitor-description-by-trace.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 7f5707d93a62cf7474d94e038188a0a8ae2924e7 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Wed, 19 May 2021 13:12:48 +0200 -Subject: [PATCH] doc: nft.8: Extend monitor description by trace - -Briefly describe 'nft monitor trace' command functionality. - -Signed-off-by: Phil Sutter -(cherry picked from commit 2acf8b2caea19d8abd46d475a908f8d6afb33aa0) ---- - doc/nft.txt | 25 ++++++++++++++++++++++--- - 1 file changed, 22 insertions(+), 3 deletions(-) - -diff --git a/doc/nft.txt b/doc/nft.txt -index 2642d8903787f..7b3c70d82a127 100644 ---- a/doc/nft.txt -+++ b/doc/nft.txt -@@ -805,13 +805,26 @@ These are some additional commands included in nft. - MONITOR - ~~~~~~~~ - The monitor command allows you to listen to Netlink events produced by the --nf_tables subsystem, related to creation and deletion of objects. When they -+nf_tables subsystem. These are either related to creation and deletion of -+objects or to packets for which *meta nftrace* was enabled. When they - occur, nft will print to stdout the monitored events in either JSON or - native nft format. + - --To filter events related to a concrete object, use one of the keywords 'tables', 'chains', 'sets', 'rules', 'elements', 'ruleset'. + -+[verse] -+____ -+*monitor* [*new* | *destroy*] 'MONITOR_OBJECT' -+*monitor* *trace* -+ -+'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset* -+____ - --To filter events related to a concrete action, use keyword 'new' or 'destroy'. -+To filter events related to a concrete object, use one of the keywords in -+'MONITOR_OBJECT'. -+ -+To filter events related to a concrete action, use keyword *new* or *destroy*. -+ -+The second form of invocation takes no further options and exclusively prints -+events generated for packets with *nftrace* enabled. - - Hit ^C to finish the monitor operation. - -@@ -835,6 +848,12 @@ Hit ^C to finish the monitor operation. - % nft monitor ruleset - --------------------- - -+.Trace incoming packets from host 10.0.0.1 -+------------------------------------------ -+% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1 -+% nft monitor trace -+------------------------------------------ -+ - ERROR REPORTING - --------------- - When an error is detected, nft shows the line(s) containing the error, the --- -2.33.0 - diff --git a/SOURCES/0019-tests-shell-NFT-needs-to-be-invoked-unquoted.patch b/SOURCES/0019-tests-shell-NFT-needs-to-be-invoked-unquoted.patch deleted file mode 100644 index 5290318..0000000 --- a/SOURCES/0019-tests-shell-NFT-needs-to-be-invoked-unquoted.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 4bd60613ea60da4bf9da226be352dd47f585e8d0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= -Date: Fri, 5 Nov 2021 12:39:11 +0100 -Subject: [PATCH] tests: shell: $NFT needs to be invoked unquoted -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The variable has to undergo word splitting, otherwise the shell tries -to find the variable value as an executable, which breaks in cases that -7c8a44b25c22 ("tests: shell: Allow wrappers to be passed as nft command") -intends to support. - -Mention this in the shell tests README. - -Fixes: d8ccad2a2b73 ("tests: cover baecd1cf2685 ("segtree: Fix segfault when restoring a huge interval set")") -Signed-off-by: Štěpán Němec -Signed-off-by: Phil Sutter -(cherry picked from commit dad3338f1f76a4a5bd782bae9c6b48941dfb1e31) - -Conflicts: - tests/shell/README --> Context change due to missing other patches. ---- - tests/shell/README | 3 +++ - tests/shell/testcases/sets/0068interval_stack_overflow_0 | 2 +- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/tests/shell/README b/tests/shell/README -index e0279bbdc30c3..aee50e3d668b1 100644 ---- a/tests/shell/README -+++ b/tests/shell/README -@@ -25,4 +25,7 @@ path to the nftables binary being tested. - You can pass an arbitrary $NFT value as well: - # NFT=/usr/local/sbin/nft ./run-tests.sh - -+Note that, to support usage such as NFT='valgrind nft', tests must -+invoke $NFT unquoted. -+ - By default the tests are run with the nft binary at '../../src/nft' -diff --git a/tests/shell/testcases/sets/0068interval_stack_overflow_0 b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -index 134282de28268..6620572449c3c 100755 ---- a/tests/shell/testcases/sets/0068interval_stack_overflow_0 -+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -@@ -26,4 +26,4 @@ table inet test68_table { - } - EOF - --( ulimit -s 128 && "$NFT" -f "$ruleset_file" ) -+( ulimit -s 128 && $NFT -f "$ruleset_file" ) --- -2.33.0 - diff --git a/SOURCES/0020-tests-shell-better-parameters-for-the-interval-stack.patch b/SOURCES/0020-tests-shell-better-parameters-for-the-interval-stack.patch deleted file mode 100644 index 39a6426..0000000 --- a/SOURCES/0020-tests-shell-better-parameters-for-the-interval-stack.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0c34164a245bdd03085e906bc9b3327d559535a4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20N=C4=9Bmec?= -Date: Wed, 1 Dec 2021 12:12:00 +0100 -Subject: [PATCH] tests: shell: better parameters for the interval stack - overflow test -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Wider testing has shown that 128 kB stack is too low (e.g. for systems -with 64 kB page size), leading to false failures in some environments. - -Based on results from a matrix of RHEL 8 and RHEL 9 systems across -x86_64, aarch64, ppc64le and s390x architectures as well as some -anecdotal testing of other Linux distros on x86_64 machines, 400 kB -seems safe: the normal nft stack (which should stay constant during -this test) on all tested systems doesn't exceed 200 kB (stays around -100 kB on typical systems with 4 kB page size), while always growing -beyond 500 kB in the failing case (nftables before baecd1cf2685) with -the increased set size. - -Fixes: d8ccad2a2b73 ("tests: cover baecd1cf2685 ("segtree: Fix segfault when restoring a huge interval set")") -Signed-off-by: Štěpán Němec -Signed-off-by: Phil Sutter -(cherry picked from commit 7b81d9cb094ffa96ad821528cf19269dc348f617) ---- - tests/shell/testcases/sets/0068interval_stack_overflow_0 | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tests/shell/testcases/sets/0068interval_stack_overflow_0 b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -index 6620572449c3c..2cbc986802644 100755 ---- a/tests/shell/testcases/sets/0068interval_stack_overflow_0 -+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0 -@@ -9,7 +9,7 @@ trap 'rm -f "$ruleset_file"' EXIT - { - echo 'define big_set = {' - for ((i = 1; i < 255; i++)); do -- for ((j = 1; j < 80; j++)); do -+ for ((j = 1; j < 255; j++)); do - echo "10.0.$i.$j," - done - done -@@ -26,4 +26,4 @@ table inet test68_table { - } - EOF - --( ulimit -s 128 && $NFT -f "$ruleset_file" ) -+( ulimit -s 400 && $NFT -f "$ruleset_file" ) --- -2.33.0 - diff --git a/SOURCES/0021-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch b/SOURCES/0021-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch deleted file mode 100644 index 000a191..0000000 --- a/SOURCES/0021-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 92f73f85dbd6559905679133cdf61e70004c805d Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Tue, 4 May 2021 13:18:11 +0200 -Subject: [PATCH] json: Simplify non-tcpopt exthdr printing a bit - -This was just duplicate code apart from the object's name. - -Signed-off-by: Phil Sutter -(cherry picked from commit fd81d3ec3ae8b8d1d54a708d63b2dab2c8508c90) ---- - src/json.c | 18 +++++++----------- - 1 file changed, 7 insertions(+), 11 deletions(-) - -diff --git a/src/json.c b/src/json.c -index 1fb5015124e16..6607d83f4e8f8 100644 ---- a/src/json.c -+++ b/src/json.c -@@ -696,21 +696,17 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) - - return json_pack("{s:o}", "tcp option", root); - } -- if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) { -- root = json_pack("{s:s}", "name", desc); - -- if (!is_exists) -- json_object_set_new(root, "field", json_string(field)); -- -- return json_pack("{s:o}", "ip option", root); -- } -- -- root = json_pack("{s:s}", -- "name", desc); -+ root = json_pack("{s:s}", "name", desc); - if (!is_exists) - json_object_set_new(root, "field", json_string(field)); - -- return json_pack("{s:o}", "exthdr", root); -+ switch (expr->exthdr.op) { -+ case NFT_EXTHDR_OP_IPV4: -+ return json_pack("{s:o}", "ip option", root); -+ default: -+ return json_pack("{s:o}", "exthdr", root); -+ } - } - - json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx) --- -2.33.0 - diff --git a/SOURCES/0022-scanner-introduce-start-condition-stack.patch b/SOURCES/0022-scanner-introduce-start-condition-stack.patch deleted file mode 100644 index 1bc0e4e..0000000 --- a/SOURCES/0022-scanner-introduce-start-condition-stack.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 80f3c19bc1b989ab7ba2b917193e8bd3f998ba39 Mon Sep 17 00:00:00 2001 -From: Florian Westphal -Date: Mon, 8 Mar 2021 18:18:33 +0100 -Subject: [PATCH] scanner: introduce start condition stack - -Add a small initial chunk of flex start conditionals. - -This starts with two low-hanging fruits, numgen and j/symhash. - -NUMGEN and HASH start conditions are entered from flex when -the corresponding expression token is encountered. - -Flex returns to the INIT condition when the bison parser -has seen a complete numgen/hash statement. - -This intentionally uses a stack rather than BEGIN() -to eventually support nested states. - -The scanner_pop_start_cond() function argument is not used yet, but -will need to be used later to deal with nesting. - -Signed-off-by: Florian Westphal -(cherry picked from commit 5896772fe3c5f01696188ea04957a825ee601b12) ---- - include/parser.h | 8 ++++++++ - src/parser_bison.y | 11 +++++++---- - src/scanner.l | 36 +++++++++++++++++++++++++++++------- - 3 files changed, 44 insertions(+), 11 deletions(-) - -diff --git a/include/parser.h b/include/parser.h -index 9baa3a4db789f..b2ebd7aa226c5 100644 ---- a/include/parser.h -+++ b/include/parser.h -@@ -26,6 +26,12 @@ struct parser_state { - struct list_head *cmds; - }; - -+enum startcond_type { -+ PARSER_SC_BEGIN, -+ PARSER_SC_EXPR_HASH, -+ PARSER_SC_EXPR_NUMGEN, -+}; -+ - struct mnl_socket; - - extern void parser_init(struct nft_ctx *nft, struct parser_state *state, -@@ -45,4 +51,6 @@ extern void scanner_push_buffer(void *scanner, - const struct input_descriptor *indesc, - const char *buffer); - -+extern void scanner_pop_start_cond(void *scanner, enum startcond_type sc); -+ - #endif /* NFTABLES_PARSER_H */ -diff --git a/src/parser_bison.y b/src/parser_bison.y -index 8644f66106496..da3fafcd1eeb1 100644 ---- a/src/parser_bison.y -+++ b/src/parser_bison.y -@@ -857,6 +857,9 @@ opt_newline : NEWLINE - | /* empty */ - ; - -+close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; -+close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; -+ - common_block : INCLUDE QUOTED_STRING stmt_separator - { - if (scanner_include_file(nft, scanner, $2, &@$) < 0) { -@@ -4811,7 +4814,7 @@ numgen_type : INC { $$ = NFT_NG_INCREMENTAL; } - | RANDOM { $$ = NFT_NG_RANDOM; } - ; - --numgen_expr : NUMGEN numgen_type MOD NUM offset_opt -+numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen - { - $$ = numgen_expr_alloc(&@$, $2, $4, $5); - } -@@ -4868,17 +4871,17 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key - } - ; - --hash_expr : JHASH expr MOD NUM SEED NUM offset_opt -+hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash - { - $$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS); - $$->hash.expr = $2; - } -- | JHASH expr MOD NUM offset_opt -+ | JHASH expr MOD NUM offset_opt close_scope_hash - { - $$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS); - $$->hash.expr = $2; - } -- | SYMHASH MOD NUM offset_opt -+ | SYMHASH MOD NUM offset_opt close_scope_hash - { - $$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM); - } -diff --git a/src/scanner.l b/src/scanner.l -index 8bde1fbe912d8..ec8f252fbc8c8 100644 ---- a/src/scanner.l -+++ b/src/scanner.l -@@ -98,6 +98,8 @@ static void reset_pos(struct parser_state *state, struct location *loc) - state->indesc->column = 1; - } - -+static void scanner_push_start_cond(void *scanner, enum startcond_type type); -+ - #define YY_USER_ACTION { \ - update_pos(yyget_extra(yyscanner), yylloc, yyleng); \ - update_offset(yyget_extra(yyscanner), yylloc, yyleng); \ -@@ -193,6 +195,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - %option yylineno - %option nodefault - %option warn -+%option stack -+%s SCANSTATE_EXPR_HASH -+%s SCANSTATE_EXPR_NUMGEN - - %% - -@@ -551,15 +556,21 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - "state" { return STATE; } - "status" { return STATUS; } - --"numgen" { return NUMGEN; } --"inc" { return INC; } --"mod" { return MOD; } --"offset" { return OFFSET; } -+"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; } -+{ -+ "inc" { return INC; } -+} - --"jhash" { return JHASH; } --"symhash" { return SYMHASH; } --"seed" { return SEED; } -+"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; } -+"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; } - -+{ -+ "seed" { return SEED; } -+} -+{ -+ "mod" { return MOD; } -+ "offset" { return OFFSET; } -+} - "dup" { return DUP; } - "fwd" { return FWD; } - -@@ -973,3 +984,14 @@ void scanner_destroy(struct nft_ctx *nft) - input_descriptor_list_destroy(state); - yylex_destroy(nft->scanner); - } -+ -+static void scanner_push_start_cond(void *scanner, enum startcond_type type) -+{ -+ yy_push_state((int)type, scanner); -+} -+ -+void scanner_pop_start_cond(void *scanner, enum startcond_type t) -+{ -+ yy_pop_state(scanner); -+ (void)yy_top_state(scanner); /* suppress gcc warning wrt. unused function */ -+} --- -2.33.0 - diff --git a/SOURCES/0023-scanner-sctp-Move-to-own-scope.patch b/SOURCES/0023-scanner-sctp-Move-to-own-scope.patch deleted file mode 100644 index 3aa28a6..0000000 --- a/SOURCES/0023-scanner-sctp-Move-to-own-scope.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 5009b467a06a86f5dcc3218fb860cd81bc5e067f Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Tue, 4 May 2021 13:06:32 +0200 -Subject: [PATCH] scanner: sctp: Move to own scope - -This isolates only "vtag" token for now. - -Signed-off-by: Phil Sutter -Reviewed-by: Florian Westphal -(cherry picked from commit 0925d7e214825628e7db4a86d5ebbad578ab0777) - - Conflicts: - include/parser.h - src/parser_bison.y - src/scanner.l - -> Context changes due to missing other scopes. ---- - include/parser.h | 1 + - src/parser_bison.y | 5 +++-- - src/scanner.l | 8 ++++++-- - 3 files changed, 10 insertions(+), 4 deletions(-) - -diff --git a/include/parser.h b/include/parser.h -index b2ebd7aa226c5..4e7b4ef430966 100644 ---- a/include/parser.h -+++ b/include/parser.h -@@ -28,6 +28,7 @@ struct parser_state { - - enum startcond_type { - PARSER_SC_BEGIN, -+ PARSER_SC_SCTP, - PARSER_SC_EXPR_HASH, - PARSER_SC_EXPR_NUMGEN, - }; -diff --git a/src/parser_bison.y b/src/parser_bison.y -index da3fafcd1eeb1..383908fa3742f 100644 ---- a/src/parser_bison.y -+++ b/src/parser_bison.y -@@ -859,6 +859,7 @@ opt_newline : NEWLINE - - close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; - close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; -+close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }; - - common_block : INCLUDE QUOTED_STRING stmt_separator - { -@@ -4620,7 +4621,7 @@ primary_rhs_expr : symbol_expr { $$ = $1; } - BYTEORDER_HOST_ENDIAN, - sizeof(data) * BITS_PER_BYTE, &data); - } -- | SCTP -+ | SCTP close_scope_sctp - { - uint8_t data = IPPROTO_SCTP; - $$ = constant_expr_alloc(&@$, &inet_protocol_type, -@@ -5345,7 +5346,7 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } - | TYPE { $$ = DCCPHDR_TYPE; } - ; - --sctp_hdr_expr : SCTP sctp_hdr_field -+sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp - { - $$ = payload_expr_alloc(&@$, &proto_sctp, $2); - } -diff --git a/src/scanner.l b/src/scanner.l -index ec8f252fbc8c8..c8e74e685f3d7 100644 ---- a/src/scanner.l -+++ b/src/scanner.l -@@ -196,6 +196,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - %option nodefault - %option warn - %option stack -+%s SCANSTATE_SCTP - %s SCANSTATE_EXPR_HASH - %s SCANSTATE_EXPR_NUMGEN - -@@ -491,8 +492,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - - "dccp" { return DCCP; } - --"sctp" { return SCTP; } --"vtag" { return VTAG; } -+"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; } -+ -+{ -+ "vtag" { return VTAG; } -+} - - "rt" { return RT; } - "rt0" { return RT0; } --- -2.33.0 - diff --git a/SOURCES/0024-exthdr-Implement-SCTP-Chunk-matching.patch b/SOURCES/0024-exthdr-Implement-SCTP-Chunk-matching.patch deleted file mode 100644 index e2b5ba2..0000000 --- a/SOURCES/0024-exthdr-Implement-SCTP-Chunk-matching.patch +++ /dev/null @@ -1,1622 +0,0 @@ -From 9a599d5fbc903271281f9d0b9a9b6da4300d7279 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Tue, 4 May 2021 13:41:38 +0200 -Subject: [PATCH] exthdr: Implement SCTP Chunk matching - -Extend exthdr expression to support scanning through SCTP packet chunks -and matching on fixed fields' values. - -Signed-off-by: Phil Sutter -Acked-by: Florian Westphal -(cherry picked from commit 0e3871cfd9a1e32a4ac041ce87a8057b11a89924) - - Conflicts: - include/parser.h - src/evaluate.c - src/parser_bison.y - src/scanner.l - -> Context changes due to missing other scopes. - -> Context change due to missing commit 6e6ef00028f1c - ("exthdr: remove tcp dependency for tcp option matching"). ---- - doc/libnftables-json.adoc | 13 + - doc/payload-expression.txt | 53 +++ - include/linux/netfilter/nf_tables.h | 2 + - include/parser.h | 1 + - include/sctp_chunk.h | 87 +++++ - src/Makefile.am | 1 + - src/evaluate.c | 2 + - src/exthdr.c | 8 + - src/json.c | 2 + - src/parser_bison.y | 148 ++++++++- - src/parser_json.c | 49 +++ - src/scanner.l | 38 +++ - src/sctp_chunk.c | 261 +++++++++++++++ - tests/py/inet/sctp.t | 37 +++ - tests/py/inet/sctp.t.json | 478 ++++++++++++++++++++++++++++ - tests/py/inet/sctp.t.payload | 155 +++++++++ - 16 files changed, 1333 insertions(+), 2 deletions(-) - create mode 100644 include/sctp_chunk.h - create mode 100644 src/sctp_chunk.c - -diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc -index 858abbf73fbfc..fba4cb08ccb68 100644 ---- a/doc/libnftables-json.adoc -+++ b/doc/libnftables-json.adoc -@@ -1200,6 +1200,19 @@ Create a reference to a field (*field*) of a TCP option header (*name*). - If the *field* property is not given, the expression is to be used as a TCP option - existence check in a *match* statement with a boolean on the right hand side. - -+=== SCTP CHUNK -+[verse] -+*{ "sctp chunk": { -+ "name":* 'STRING'*, -+ "field":* 'STRING' -+*}}* -+ -+Create a reference to a field (*field*) of an SCTP chunk (*name*). -+ -+If the *field* property is not given, the expression is to be used as an SCTP -+chunk existence check in a *match* statement with a boolean on the right hand -+side. -+ - === META - [verse] - ____ -diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt -index a593e2e7b947d..a338dcf044505 100644 ---- a/doc/payload-expression.txt -+++ b/doc/payload-expression.txt -@@ -369,7 +369,33 @@ integer (16 bit) - SCTP HEADER EXPRESSION - ~~~~~~~~~~~~~~~~~~~~~~~ - [verse] -+____ - *sctp* {*sport* | *dport* | *vtag* | *checksum*} -+*sctp chunk* 'CHUNK' [ 'FIELD' ] -+ -+'CHUNK' := *data* | *init* | *init-ack* | *sack* | *heartbeat* | -+ *heartbeat-ack* | *abort* | *shutdown* | *shutdown-ack* | *error* | -+ *cookie-echo* | *cookie-ack* | *ecne* | *cwr* | *shutdown-complete* -+ | *asconf-ack* | *forward-tsn* | *asconf* -+ -+'FIELD' := 'COMMON_FIELD' | 'DATA_FIELD' | 'INIT_FIELD' | 'INIT_ACK_FIELD' | -+ 'SACK_FIELD' | 'SHUTDOWN_FIELD' | 'ECNE_FIELD' | 'CWR_FIELD' | -+ 'ASCONF_ACK_FIELD' | 'FORWARD_TSN_FIELD' | 'ASCONF_FIELD' -+ -+'COMMON_FIELD' := *type* | *flags* | *length* -+'DATA_FIELD' := *tsn* | *stream* | *ssn* | *ppid* -+'INIT_FIELD' := *init-tag* | *a-rwnd* | *num-outbound-streams* | -+ *num-inbound-streams* | *initial-tsn* -+'INIT_ACK_FIELD' := 'INIT_FIELD' -+'SACK_FIELD' := *cum-tsn-ack* | *a-rwnd* | *num-gap-ack-blocks* | -+ *num-dup-tsns* -+'SHUTDOWN_FIELD' := *cum-tsn-ack* -+'ECNE_FIELD' := *lowest-tsn* -+'CWR_FIELD' := *lowest-tsn* -+'ASCONF_ACK_FIELD' := *seqno* -+'FORWARD_TSN_FIELD' := *new-cum-tsn* -+'ASCONF_FIELD' := *seqno* -+____ - - .SCTP header expression - [options="header"] -@@ -387,8 +413,35 @@ integer (32 bit) - |checksum| - Checksum| - integer (32 bit) -+|chunk| -+Search chunk in packet| -+without 'FIELD', boolean indicating existence - |================ - -+.SCTP chunk fields -+[options="header"] -+|================== -+|Name| Width in bits | Chunk | Notes -+|type| 8 | all | not useful, defined by chunk type -+|flags| 8 | all | semantics defined on per-chunk basis -+|length| 16 | all | length of this chunk in bytes excluding padding -+|tsn| 32 | data | transmission sequence number -+|stream| 16 | data | stream identifier -+|ssn| 16 | data | stream sequence number -+|ppid| 32 | data | payload protocol identifier -+|init-tag| 32 | init, init-ack | initiate tag -+|a-rwnd| 32 | init, init-ack, sack | advertised receiver window credit -+|num-outbound-streams| 16 | init, init-ack | number of outbound streams -+|num-inbound-streams| 16 | init, init-ack | number of inbound streams -+|initial-tsn| 32 | init, init-ack | initial transmit sequence number -+|cum-tsn-ack| 32 | sack, shutdown | cumulative transmission sequence number acknowledged -+|num-gap-ack-blocks| 16 | sack | number of Gap Ack Blocks included -+|num-dup-tsns| 16 | sack | number of duplicate transmission sequence numbers received -+|lowest-tsn| 32 | ecne, cwr | lowest transmission sequence number -+|seqno| 32 | asconf-ack, asconf | sequence number -+|new-cum-tsn| 32 | forward-tsn | new cumulative transmission sequence number -+|================== -+ - DCCP HEADER EXPRESSION - ~~~~~~~~~~~~~~~~~~~~~~ - [verse] -diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h -index b1633e7ba5296..7f9fc203f6f82 100644 ---- a/include/linux/netfilter/nf_tables.h -+++ b/include/linux/netfilter/nf_tables.h -@@ -806,11 +806,13 @@ enum nft_exthdr_flags { - * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers - * @NFT_EXTHDR_OP_TCP: match against tcp options - * @NFT_EXTHDR_OP_IPV4: match against ipv4 options -+ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks - */ - enum nft_exthdr_op { - NFT_EXTHDR_OP_IPV6, - NFT_EXTHDR_OP_TCPOPT, - NFT_EXTHDR_OP_IPV4, -+ NFT_EXTHDR_OP_SCTP, - __NFT_EXTHDR_OP_MAX - }; - #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) -diff --git a/include/parser.h b/include/parser.h -index 4e7b4ef430966..f0c5996dd3dd3 100644 ---- a/include/parser.h -+++ b/include/parser.h -@@ -31,6 +31,7 @@ enum startcond_type { - PARSER_SC_SCTP, - PARSER_SC_EXPR_HASH, - PARSER_SC_EXPR_NUMGEN, -+ PARSER_SC_EXPR_SCTP_CHUNK, - }; - - struct mnl_socket; -diff --git a/include/sctp_chunk.h b/include/sctp_chunk.h -new file mode 100644 -index 0000000000000..3819200f9f0a4 ---- /dev/null -+++ b/include/sctp_chunk.h -@@ -0,0 +1,87 @@ -+/* -+ * Copyright Red Hat -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 (or any -+ * later) as published by the Free Software Foundation. -+ */ -+ -+#ifndef NFTABLES_SCTP_CHUNK_H -+#define NFTABLES_SCTP_CHUNK_H -+ -+/* SCTP chunk types used on wire */ -+enum sctp_hdr_chunk_types { -+ SCTP_CHUNK_TYPE_DATA = 0, -+ SCTP_CHUNK_TYPE_INIT = 1, -+ SCTP_CHUNK_TYPE_INIT_ACK = 2, -+ SCTP_CHUNK_TYPE_SACK = 3, -+ SCTP_CHUNK_TYPE_HEARTBEAT = 4, -+ SCTP_CHUNK_TYPE_HEARTBEAT_ACK = 5, -+ SCTP_CHUNK_TYPE_ABORT = 6, -+ SCTP_CHUNK_TYPE_SHUTDOWN = 7, -+ SCTP_CHUNK_TYPE_SHUTDOWN_ACK = 8, -+ SCTP_CHUNK_TYPE_ERROR = 9, -+ SCTP_CHUNK_TYPE_COOKIE_ECHO = 10, -+ SCTP_CHUNK_TYPE_COOKIE_ACK = 11, -+ SCTP_CHUNK_TYPE_ECNE = 12, -+ SCTP_CHUNK_TYPE_CWR = 13, -+ SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE = 14, -+ SCTP_CHUNK_TYPE_ASCONF_ACK = 128, -+ SCTP_CHUNK_TYPE_FORWARD_TSN = 192, -+ SCTP_CHUNK_TYPE_ASCONF = 193, -+}; -+ -+enum sctp_hdr_chunk_common_fields { -+ SCTP_CHUNK_COMMON_TYPE, -+ SCTP_CHUNK_COMMON_FLAGS, -+ SCTP_CHUNK_COMMON_LENGTH, -+ __SCTP_CHUNK_COMMON_MAX, -+}; -+ -+#define SCTP_CHUNK_START_INDEX __SCTP_CHUNK_COMMON_MAX -+ -+enum sctp_hdr_chunk_data_fields { -+ SCTP_CHUNK_DATA_TSN = SCTP_CHUNK_START_INDEX, -+ SCTP_CHUNK_DATA_STREAM, -+ SCTP_CHUNK_DATA_SSN, -+ SCTP_CHUNK_DATA_PPID, -+}; -+ -+enum sctp_hdr_chunk_init_fields { -+ SCTP_CHUNK_INIT_TAG = SCTP_CHUNK_START_INDEX, -+ SCTP_CHUNK_INIT_RWND, -+ SCTP_CHUNK_INIT_OSTREAMS, -+ SCTP_CHUNK_INIT_ISTREAMS, -+ SCTP_CHUNK_INIT_TSN, -+}; -+ -+enum sctp_hdr_chunk_sack_fields { -+ SCTP_CHUNK_SACK_CTSN_ACK = SCTP_CHUNK_START_INDEX, -+ SCTP_CHUNK_SACK_RWND, -+ SCTP_CHUNK_SACK_GACK_BLOCKS, -+ SCTP_CHUNK_SACK_DUP_TSNS, -+}; -+ -+enum sctp_hdr_chunk_shutdown_fields { -+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK = SCTP_CHUNK_START_INDEX, -+}; -+ -+enum sctp_hdr_chunk_ecne_cwr_fields { -+ SCTP_CHUNK_ECNE_CWR_MIN_TSN = SCTP_CHUNK_START_INDEX, -+}; -+ -+enum sctp_hdr_chunk_asconf_fields { -+ SCTP_CHUNK_ASCONF_SEQNO = SCTP_CHUNK_START_INDEX, -+}; -+ -+enum sctp_hdr_chunk_fwd_tsn_fields { -+ SCTP_CHUNK_FORWARD_TSN_NCTSN = SCTP_CHUNK_START_INDEX, -+}; -+ -+struct expr *sctp_chunk_expr_alloc(const struct location *loc, -+ unsigned int type, unsigned int field); -+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off, -+ unsigned int len, uint32_t flags); -+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name); -+ -+#endif /* NFTABLES_SCTP_CHUNK_H */ -diff --git a/src/Makefile.am b/src/Makefile.am -index 3041a933bc067..253cb995a3f07 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -74,6 +74,7 @@ libnftables_la_SOURCES = \ - tcpopt.c \ - socket.c \ - print.c \ -+ sctp_chunk.c \ - libnftables.c \ - libnftables.map - -diff --git a/src/evaluate.c b/src/evaluate.c -index 2a897f469434a..bba685af720ed 100644 ---- a/src/evaluate.c -+++ b/src/evaluate.c -@@ -583,6 +583,8 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) - dependency = &proto_tcp; - pb = PROTO_BASE_TRANSPORT_HDR; - break; -+ case NFT_EXTHDR_OP_SCTP: -+ return __expr_evaluate_exthdr(ctx, exprp); - case NFT_EXTHDR_OP_IPV4: - dependency = &proto_ip; - break; -diff --git a/src/exthdr.c b/src/exthdr.c -index b0243adad1da4..22a08b0c9c2bf 100644 ---- a/src/exthdr.c -+++ b/src/exthdr.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - static const struct exthdr_desc *exthdr_definitions[PROTO_DESC_MAX + 1] = { - [EXTHDR_DESC_HBH] = &exthdr_hbh, -@@ -75,6 +76,11 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx) - if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) - return; - nft_print(octx, " %s", expr->exthdr.tmpl->token); -+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_SCTP) { -+ nft_print(octx, "sctp chunk %s", expr->exthdr.desc->name); -+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) -+ return; -+ nft_print(octx, " %s", expr->exthdr.tmpl->token); - } else { - if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) - nft_print(octx, "exthdr %s", expr->exthdr.desc->name); -@@ -291,6 +297,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type, - return tcpopt_init_raw(expr, type, offset, len, flags); - if (op == NFT_EXTHDR_OP_IPV4) - return ipopt_init_raw(expr, type, offset, len, flags, true); -+ if (op == NFT_EXTHDR_OP_SCTP) -+ return sctp_chunk_init_raw(expr, type, offset, len, flags); - - expr->len = len; - expr->exthdr.flags = flags; -diff --git a/src/json.c b/src/json.c -index 6607d83f4e8f8..9f345cb486389 100644 ---- a/src/json.c -+++ b/src/json.c -@@ -704,6 +704,8 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx) - switch (expr->exthdr.op) { - case NFT_EXTHDR_OP_IPV4: - return json_pack("{s:o}", "ip option", root); -+ case NFT_EXTHDR_OP_SCTP: -+ return json_pack("{s:o}", "sctp chunk", root); - default: - return json_pack("{s:o}", "exthdr", root); - } -diff --git a/src/parser_bison.y b/src/parser_bison.y -index 383908fa3742f..44b9107e8a360 100644 ---- a/src/parser_bison.y -+++ b/src/parser_bison.y -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - - #include "parser_bison.h" - -@@ -417,6 +418,40 @@ int nft_lex(void *, void *, void *); - %token DCCP "dccp" - - %token SCTP "sctp" -+%token CHUNK "chunk" -+%token DATA "data" -+%token INIT "init" -+%token INIT_ACK "init-ack" -+%token HEARTBEAT "heartbeat" -+%token HEARTBEAT_ACK "heartbeat-ack" -+%token ABORT "abort" -+%token SHUTDOWN "shutdown" -+%token SHUTDOWN_ACK "shutdown-ack" -+%token ERROR "error" -+%token COOKIE_ECHO "cookie-echo" -+%token COOKIE_ACK "cookie-ack" -+%token ECNE "ecne" -+%token CWR "cwr" -+%token SHUTDOWN_COMPLETE "shutdown-complete" -+%token ASCONF_ACK "asconf-ack" -+%token FORWARD_TSN "forward-tsn" -+%token ASCONF "asconf" -+%token TSN "tsn" -+%token STREAM "stream" -+%token SSN "ssn" -+%token PPID "ppid" -+%token INIT_TAG "init-tag" -+%token A_RWND "a-rwnd" -+%token NUM_OSTREAMS "num-outbound-streams" -+%token NUM_ISTREAMS "num-inbound-streams" -+%token INIT_TSN "initial-tsn" -+%token CUM_TSN_ACK "cum-tsn-ack" -+%token NUM_GACK_BLOCKS "num-gap-ack-blocks" -+%token NUM_DUP_TSNS "num-dup-tsns" -+%token LOWEST_TSN "lowest-tsn" -+%token SEQNO "seqno" -+%token NEW_CUM_TSN "new-cum-tsn" -+ - %token VTAG "vtag" - - %token RT "rt" -@@ -763,9 +798,12 @@ int nft_lex(void *, void *, void *); - %type udp_hdr_expr udplite_hdr_expr - %destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr - %type udp_hdr_field udplite_hdr_field --%type dccp_hdr_expr sctp_hdr_expr --%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr -+%type dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc -+%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc - %type dccp_hdr_field sctp_hdr_field -+%type sctp_chunk_type sctp_chunk_common_field -+%type sctp_chunk_data_field sctp_chunk_init_field -+%type sctp_chunk_sack_field - %type th_hdr_expr - %destructor { expr_free($$); } th_hdr_expr - %type th_hdr_field -@@ -860,6 +898,7 @@ opt_newline : NEWLINE - close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; - close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }; - close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }; -+close_scope_sctp_chunk : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); }; - - common_block : INCLUDE QUOTED_STRING stmt_separator - { -@@ -5346,10 +5385,115 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; } - | TYPE { $$ = DCCPHDR_TYPE; } - ; - -+sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; } -+ | INIT { $$ = SCTP_CHUNK_TYPE_INIT; } -+ | INIT_ACK { $$ = SCTP_CHUNK_TYPE_INIT_ACK; } -+ | SACK { $$ = SCTP_CHUNK_TYPE_SACK; } -+ | HEARTBEAT { $$ = SCTP_CHUNK_TYPE_HEARTBEAT; } -+ | HEARTBEAT_ACK { $$ = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; } -+ | ABORT { $$ = SCTP_CHUNK_TYPE_ABORT; } -+ | SHUTDOWN { $$ = SCTP_CHUNK_TYPE_SHUTDOWN; } -+ | SHUTDOWN_ACK { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; } -+ | ERROR { $$ = SCTP_CHUNK_TYPE_ERROR; } -+ | COOKIE_ECHO { $$ = SCTP_CHUNK_TYPE_COOKIE_ECHO; } -+ | COOKIE_ACK { $$ = SCTP_CHUNK_TYPE_COOKIE_ACK; } -+ | ECNE { $$ = SCTP_CHUNK_TYPE_ECNE; } -+ | CWR { $$ = SCTP_CHUNK_TYPE_CWR; } -+ | SHUTDOWN_COMPLETE { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; } -+ | ASCONF_ACK { $$ = SCTP_CHUNK_TYPE_ASCONF_ACK; } -+ | FORWARD_TSN { $$ = SCTP_CHUNK_TYPE_FORWARD_TSN; } -+ | ASCONF { $$ = SCTP_CHUNK_TYPE_ASCONF; } -+ ; -+ -+sctp_chunk_common_field : TYPE { $$ = SCTP_CHUNK_COMMON_TYPE; } -+ | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; } -+ | LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; } -+ ; -+ -+sctp_chunk_data_field : TSN { $$ = SCTP_CHUNK_DATA_TSN; } -+ | STREAM { $$ = SCTP_CHUNK_DATA_STREAM; } -+ | SSN { $$ = SCTP_CHUNK_DATA_SSN; } -+ | PPID { $$ = SCTP_CHUNK_DATA_PPID; } -+ ; -+ -+sctp_chunk_init_field : INIT_TAG { $$ = SCTP_CHUNK_INIT_TAG; } -+ | A_RWND { $$ = SCTP_CHUNK_INIT_RWND; } -+ | NUM_OSTREAMS { $$ = SCTP_CHUNK_INIT_OSTREAMS; } -+ | NUM_ISTREAMS { $$ = SCTP_CHUNK_INIT_ISTREAMS; } -+ | INIT_TSN { $$ = SCTP_CHUNK_INIT_TSN; } -+ ; -+ -+sctp_chunk_sack_field : CUM_TSN_ACK { $$ = SCTP_CHUNK_SACK_CTSN_ACK; } -+ | A_RWND { $$ = SCTP_CHUNK_SACK_RWND; } -+ | NUM_GACK_BLOCKS { $$ = SCTP_CHUNK_SACK_GACK_BLOCKS; } -+ | NUM_DUP_TSNS { $$ = SCTP_CHUNK_SACK_DUP_TSNS; } -+ ; -+ -+sctp_chunk_alloc : sctp_chunk_type -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, $1, SCTP_CHUNK_COMMON_TYPE); -+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT; -+ } -+ | sctp_chunk_type sctp_chunk_common_field -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, $1, $2); -+ } -+ | DATA sctp_chunk_data_field -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_DATA, $2); -+ } -+ | INIT sctp_chunk_init_field -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT, $2); -+ } -+ | INIT_ACK sctp_chunk_init_field -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT_ACK, $2); -+ } -+ | SACK sctp_chunk_sack_field -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SACK, $2); -+ } -+ | SHUTDOWN CUM_TSN_ACK -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SHUTDOWN, -+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK); -+ } -+ | ECNE LOWEST_TSN -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ECNE, -+ SCTP_CHUNK_ECNE_CWR_MIN_TSN); -+ } -+ | CWR LOWEST_TSN -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_CWR, -+ SCTP_CHUNK_ECNE_CWR_MIN_TSN); -+ } -+ | ASCONF_ACK SEQNO -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF_ACK, -+ SCTP_CHUNK_ASCONF_SEQNO); -+ } -+ | FORWARD_TSN NEW_CUM_TSN -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_FORWARD_TSN, -+ SCTP_CHUNK_FORWARD_TSN_NCTSN); -+ } -+ | ASCONF SEQNO -+ { -+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF, -+ SCTP_CHUNK_ASCONF_SEQNO); -+ } -+ ; -+ - sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp - { - $$ = payload_expr_alloc(&@$, &proto_sctp, $2); - } -+ | SCTP CHUNK sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp -+ { -+ $$ = $3; -+ } - ; - - sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; } -diff --git a/src/parser_json.c b/src/parser_json.c -index 9bba77dad5f0d..0dce6ba57f634 100644 ---- a/src/parser_json.c -+++ b/src/parser_json.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -707,6 +708,53 @@ static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx, - return ipopt_expr_alloc(int_loc, descval, fieldval, 0); - } - -+static int json_parse_sctp_chunk_field(const struct exthdr_desc *desc, -+ const char *name, int *val) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < array_size(desc->templates); i++) { -+ if (desc->templates[i].token && -+ !strcmp(desc->templates[i].token, name)) { -+ if (val) -+ *val = i; -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx, -+ const char *type, json_t *root) -+{ -+ const struct exthdr_desc *desc; -+ const char *name, *field; -+ struct expr *expr; -+ int fieldval; -+ -+ if (json_unpack_err(ctx, root, "{s:s}", "name", &name)) -+ return NULL; -+ -+ desc = sctp_chunk_protocol_find(name); -+ if (!desc) { -+ json_error(ctx, "Unknown sctp chunk name '%s'.", name); -+ return NULL; -+ } -+ -+ if (json_unpack(root, "{s:s}", "field", &field)) { -+ expr = sctp_chunk_expr_alloc(int_loc, desc->type, -+ SCTP_CHUNK_COMMON_TYPE); -+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT; -+ -+ return expr; -+ } -+ if (json_parse_sctp_chunk_field(desc, field, &fieldval)) { -+ json_error(ctx, "Unknown sctp chunk field '%s'.", field); -+ return NULL; -+ } -+ return sctp_chunk_expr_alloc(int_loc, desc->type, fieldval); -+} -+ - static const struct exthdr_desc *exthdr_lookup_byname(const char *name) - { - const struct exthdr_desc *exthdr_tbl[] = { -@@ -1412,6 +1460,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root) - { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, - { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, - { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, -+ { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, - { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, - { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, - { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, -diff --git a/src/scanner.l b/src/scanner.l -index c8e74e685f3d7..1bf07ec2d44c4 100644 ---- a/src/scanner.l -+++ b/src/scanner.l -@@ -199,6 +199,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - %s SCANSTATE_SCTP - %s SCANSTATE_EXPR_HASH - %s SCANSTATE_EXPR_NUMGEN -+%s SCANSTATE_EXPR_SCTP_CHUNK - - %% - -@@ -495,9 +496,46 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) - "sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; } - - { -+ "chunk" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; } - "vtag" { return VTAG; } - } - -+{ -+ "data" { return DATA; } -+ "init" { return INIT; } -+ "init-ack" { return INIT_ACK; } -+ "heartbeat" { return HEARTBEAT; } -+ "heartbeat-ack" { return HEARTBEAT_ACK; } -+ "abort" { return ABORT; } -+ "shutdown" { return SHUTDOWN; } -+ "shutdown-ack" { return SHUTDOWN_ACK; } -+ "error" { return ERROR; } -+ "cookie-echo" { return COOKIE_ECHO; } -+ "cookie-ack" { return COOKIE_ACK; } -+ "ecne" { return ECNE; } -+ "cwr" { return CWR; } -+ "shutdown-complete" { return SHUTDOWN_COMPLETE; } -+ "asconf-ack" { return ASCONF_ACK; } -+ "forward-tsn" { return FORWARD_TSN; } -+ "asconf" { return ASCONF; } -+ -+ "tsn" { return TSN; } -+ "stream" { return STREAM; } -+ "ssn" { return SSN; } -+ "ppid" { return PPID; } -+ "init-tag" { return INIT_TAG; } -+ "a-rwnd" { return A_RWND; } -+ "num-outbound-streams" { return NUM_OSTREAMS; } -+ "num-inbound-streams" { return NUM_ISTREAMS; } -+ "initial-tsn" { return INIT_TSN; } -+ "cum-tsn-ack" { return CUM_TSN_ACK; } -+ "num-gap-ack-blocks" { return NUM_GACK_BLOCKS; } -+ "num-dup-tsns" { return NUM_DUP_TSNS; } -+ "lowest-tsn" { return LOWEST_TSN; } -+ "seqno" { return SEQNO; } -+ "new-cum-tsn" { return NEW_CUM_TSN; } -+} -+ - "rt" { return RT; } - "rt0" { return RT0; } - "rt2" { return RT2; } -diff --git a/src/sctp_chunk.c b/src/sctp_chunk.c -new file mode 100644 -index 0000000000000..6e73e72f8308b ---- /dev/null -+++ b/src/sctp_chunk.c -@@ -0,0 +1,261 @@ -+/* -+ * Copyright Red Hat -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 (or any -+ * later) as published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+ -+#define PHT(__token, __offset, __len) \ -+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \ -+ __offset, __len) -+ -+static const struct exthdr_desc sctp_chunk_data = { -+ .name = "data", -+ .type = SCTP_CHUNK_TYPE_DATA, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_DATA_TSN] = PHT("tsn", 32, 32), -+ [SCTP_CHUNK_DATA_STREAM] = PHT("stream", 64, 16), -+ [SCTP_CHUNK_DATA_SSN] = PHT("ssn", 80, 16), -+ [SCTP_CHUNK_DATA_PPID] = PHT("ppid", 96, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_init = { -+ .name = "init", -+ .type = SCTP_CHUNK_TYPE_INIT, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32), -+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32), -+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16), -+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16), -+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_init_ack = { -+ .name = "init-ack", -+ .type = SCTP_CHUNK_TYPE_INIT_ACK, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32), -+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32), -+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16), -+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16), -+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_sack = { -+ .name = "sack", -+ .type = SCTP_CHUNK_TYPE_SACK, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_SACK_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32), -+ [SCTP_CHUNK_SACK_RWND] = PHT("a-rwnd", 64, 32), -+ [SCTP_CHUNK_SACK_GACK_BLOCKS] = PHT("num-gap-ack-blocks", 96, 16), -+ [SCTP_CHUNK_SACK_DUP_TSNS] = PHT("num-dup-tsns", 112, 16), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_shutdown = { -+ .name = "shutdown", -+ .type = SCTP_CHUNK_TYPE_SHUTDOWN, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_SHUTDOWN_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_ecne = { -+ .name = "ecne", -+ .type = SCTP_CHUNK_TYPE_ECNE, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_cwr = { -+ .name = "cwr", -+ .type = SCTP_CHUNK_TYPE_CWR, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_asconf_ack = { -+ .name = "asconf-ack", -+ .type = SCTP_CHUNK_TYPE_ASCONF_ACK, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_forward_tsn = { -+ .name = "forward-tsn", -+ .type = SCTP_CHUNK_TYPE_FORWARD_TSN, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_FORWARD_TSN_NCTSN] = PHT("new-cum-tsn", 32, 32), -+ }, -+}; -+ -+static const struct exthdr_desc sctp_chunk_asconf = { -+ .name = "asconf", -+ .type = SCTP_CHUNK_TYPE_ASCONF, -+ .templates = { -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16), -+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32), -+ }, -+}; -+ -+#define SCTP_CHUNK_DESC_GENERATOR(descname, hname, desctype) \ -+static const struct exthdr_desc sctp_chunk_##descname = { \ -+ .name = #hname, \ -+ .type = SCTP_CHUNK_TYPE_##desctype, \ -+ .templates = { \ -+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), \ -+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), \ -+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),\ -+ }, \ -+}; -+ -+SCTP_CHUNK_DESC_GENERATOR(heartbeat, heartbeat, HEARTBEAT) -+SCTP_CHUNK_DESC_GENERATOR(heartbeat_ack, heartbeat-ack, HEARTBEAT_ACK) -+SCTP_CHUNK_DESC_GENERATOR(abort, abort, ABORT) -+SCTP_CHUNK_DESC_GENERATOR(shutdown_ack, shutdown-ack, SHUTDOWN_ACK) -+SCTP_CHUNK_DESC_GENERATOR(error, error, ERROR) -+SCTP_CHUNK_DESC_GENERATOR(cookie_echo, cookie-echo, COOKIE_ECHO) -+SCTP_CHUNK_DESC_GENERATOR(cookie_ack, cookie-ack, COOKIE_ACK) -+SCTP_CHUNK_DESC_GENERATOR(shutdown_complete, shutdown-complete, SHUTDOWN_COMPLETE) -+ -+#undef SCTP_CHUNK_DESC_GENERATOR -+ -+static const struct exthdr_desc *sctp_chunk_protocols[] = { -+ [SCTP_CHUNK_TYPE_DATA] = &sctp_chunk_data, -+ [SCTP_CHUNK_TYPE_INIT] = &sctp_chunk_init, -+ [SCTP_CHUNK_TYPE_INIT_ACK] = &sctp_chunk_init_ack, -+ [SCTP_CHUNK_TYPE_SACK] = &sctp_chunk_sack, -+ [SCTP_CHUNK_TYPE_HEARTBEAT] = &sctp_chunk_heartbeat, -+ [SCTP_CHUNK_TYPE_HEARTBEAT_ACK] = &sctp_chunk_heartbeat_ack, -+ [SCTP_CHUNK_TYPE_ABORT] = &sctp_chunk_abort, -+ [SCTP_CHUNK_TYPE_SHUTDOWN] = &sctp_chunk_shutdown, -+ [SCTP_CHUNK_TYPE_SHUTDOWN_ACK] = &sctp_chunk_shutdown_ack, -+ [SCTP_CHUNK_TYPE_ERROR] = &sctp_chunk_error, -+ [SCTP_CHUNK_TYPE_COOKIE_ECHO] = &sctp_chunk_cookie_echo, -+ [SCTP_CHUNK_TYPE_COOKIE_ACK] = &sctp_chunk_cookie_ack, -+ [SCTP_CHUNK_TYPE_ECNE] = &sctp_chunk_ecne, -+ [SCTP_CHUNK_TYPE_CWR] = &sctp_chunk_cwr, -+ [SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE] = &sctp_chunk_shutdown_complete, -+ [SCTP_CHUNK_TYPE_ASCONF_ACK] = &sctp_chunk_asconf_ack, -+ [SCTP_CHUNK_TYPE_FORWARD_TSN] = &sctp_chunk_forward_tsn, -+ [SCTP_CHUNK_TYPE_ASCONF] = &sctp_chunk_asconf, -+}; -+ -+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < array_size(sctp_chunk_protocols); i++) { -+ if (sctp_chunk_protocols[i] && -+ !strcmp(sctp_chunk_protocols[i]->name, name)) -+ return sctp_chunk_protocols[i]; -+ } -+ return NULL; -+} -+ -+struct expr *sctp_chunk_expr_alloc(const struct location *loc, -+ unsigned int type, unsigned int field) -+{ -+ const struct proto_hdr_template *tmpl; -+ const struct exthdr_desc *desc = NULL; -+ struct expr *expr; -+ -+ if (type < array_size(sctp_chunk_protocols)) -+ desc = sctp_chunk_protocols[type]; -+ -+ if (!desc) -+ return NULL; -+ -+ tmpl = &desc->templates[field]; -+ if (!tmpl) -+ return NULL; -+ -+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype, -+ BYTEORDER_BIG_ENDIAN, tmpl->len); -+ expr->exthdr.desc = desc; -+ expr->exthdr.tmpl = tmpl; -+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP; -+ expr->exthdr.raw_type = desc->type; -+ expr->exthdr.offset = tmpl->offset; -+ -+ return expr; -+} -+ -+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off, -+ unsigned int len, uint32_t flags) -+{ -+ const struct proto_hdr_template *tmpl; -+ unsigned int i; -+ -+ assert(expr->etype == EXPR_EXTHDR); -+ -+ expr->len = len; -+ expr->exthdr.flags = flags; -+ expr->exthdr.offset = off; -+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP; -+ -+ if (flags & NFT_EXTHDR_F_PRESENT) -+ datatype_set(expr, &boolean_type); -+ else -+ datatype_set(expr, &integer_type); -+ -+ if (type >= array_size(sctp_chunk_protocols)) -+ return; -+ -+ expr->exthdr.desc = sctp_chunk_protocols[type]; -+ expr->exthdr.flags = flags; -+ assert(expr->exthdr.desc != NULL); -+ -+ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) { -+ tmpl = &expr->exthdr.desc->templates[i]; -+ if (tmpl->offset != off || tmpl->len != len) -+ continue; -+ -+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0) -+ datatype_set(expr, tmpl->dtype); -+ -+ expr->exthdr.tmpl = tmpl; -+ break; -+ } -+} -diff --git a/tests/py/inet/sctp.t b/tests/py/inet/sctp.t -index 5188b57e65085..3d1c2fd6cd2f7 100644 ---- a/tests/py/inet/sctp.t -+++ b/tests/py/inet/sctp.t -@@ -41,3 +41,40 @@ sctp vtag {33, 55, 67, 88};ok - sctp vtag != {33, 55, 67, 88};ok - sctp vtag { 33-55};ok - sctp vtag != { 33-55};ok -+ -+# assert all chunk types are recognized -+sctp chunk data exists;ok -+sctp chunk init exists;ok -+sctp chunk init-ack exists;ok -+sctp chunk sack exists;ok -+sctp chunk heartbeat exists;ok -+sctp chunk heartbeat-ack exists;ok -+sctp chunk abort exists;ok -+sctp chunk shutdown exists;ok -+sctp chunk shutdown-ack exists;ok -+sctp chunk error exists;ok -+sctp chunk cookie-echo exists;ok -+sctp chunk cookie-ack exists;ok -+sctp chunk ecne exists;ok -+sctp chunk cwr exists;ok -+sctp chunk shutdown-complete exists;ok -+sctp chunk asconf-ack exists;ok -+sctp chunk forward-tsn exists;ok -+sctp chunk asconf exists;ok -+ -+# test common header fields in random chunk types -+sctp chunk data type 0;ok -+sctp chunk init flags 23;ok -+sctp chunk init-ack length 42;ok -+ -+# test one custom field in every applicable chunk type -+sctp chunk data stream 1337;ok -+sctp chunk init initial-tsn 5;ok -+sctp chunk init-ack num-outbound-streams 3;ok -+sctp chunk sack a-rwnd 1;ok -+sctp chunk shutdown cum-tsn-ack 65535;ok -+sctp chunk ecne lowest-tsn 5;ok -+sctp chunk cwr lowest-tsn 8;ok -+sctp chunk asconf-ack seqno 12345;ok -+sctp chunk forward-tsn new-cum-tsn 31337;ok -+sctp chunk asconf seqno 12345;ok -diff --git a/tests/py/inet/sctp.t.json b/tests/py/inet/sctp.t.json -index 2684b0349a71b..8135686230129 100644 ---- a/tests/py/inet/sctp.t.json -+++ b/tests/py/inet/sctp.t.json -@@ -608,3 +608,481 @@ - } - ] - -+# sctp chunk data exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "data" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk init exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "init" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk init-ack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "init-ack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk sack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "sack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk heartbeat exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "heartbeat" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk heartbeat-ack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "heartbeat-ack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk abort exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "abort" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk shutdown exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "shutdown" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk shutdown-ack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "shutdown-ack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk error exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "error" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk cookie-echo exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "cookie-echo" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk cookie-ack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "cookie-ack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk ecne exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "ecne" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk cwr exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "cwr" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk shutdown-complete exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "shutdown-complete" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk asconf-ack exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "asconf-ack" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk forward-tsn exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "forward-tsn" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk asconf exists -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "name": "asconf" -+ } -+ }, -+ "op": "==", -+ "right": true -+ } -+ } -+] -+ -+# sctp chunk data type 0 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "type", -+ "name": "data" -+ } -+ }, -+ "op": "==", -+ "right": 0 -+ } -+ } -+] -+ -+# sctp chunk init flags 23 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "flags", -+ "name": "init" -+ } -+ }, -+ "op": "==", -+ "right": 23 -+ } -+ } -+] -+ -+# sctp chunk init-ack length 42 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "length", -+ "name": "init-ack" -+ } -+ }, -+ "op": "==", -+ "right": 42 -+ } -+ } -+] -+ -+# sctp chunk data stream 1337 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "stream", -+ "name": "data" -+ } -+ }, -+ "op": "==", -+ "right": 1337 -+ } -+ } -+] -+ -+# sctp chunk init initial-tsn 5 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "initial-tsn", -+ "name": "init" -+ } -+ }, -+ "op": "==", -+ "right": 5 -+ } -+ } -+] -+ -+# sctp chunk init-ack num-outbound-streams 3 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "num-outbound-streams", -+ "name": "init-ack" -+ } -+ }, -+ "op": "==", -+ "right": 3 -+ } -+ } -+] -+ -+# sctp chunk sack a-rwnd 1 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "a-rwnd", -+ "name": "sack" -+ } -+ }, -+ "op": "==", -+ "right": 1 -+ } -+ } -+] -+ -+# sctp chunk shutdown cum-tsn-ack 65535 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "cum-tsn-ack", -+ "name": "shutdown" -+ } -+ }, -+ "op": "==", -+ "right": 65535 -+ } -+ } -+] -+ -+# sctp chunk ecne lowest-tsn 5 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "lowest-tsn", -+ "name": "ecne" -+ } -+ }, -+ "op": "==", -+ "right": 5 -+ } -+ } -+] -+ -+# sctp chunk cwr lowest-tsn 8 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "lowest-tsn", -+ "name": "cwr" -+ } -+ }, -+ "op": "==", -+ "right": 8 -+ } -+ } -+] -+ -+# sctp chunk asconf-ack seqno 12345 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "seqno", -+ "name": "asconf-ack" -+ } -+ }, -+ "op": "==", -+ "right": 12345 -+ } -+ } -+] -+ -+# sctp chunk forward-tsn new-cum-tsn 31337 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "new-cum-tsn", -+ "name": "forward-tsn" -+ } -+ }, -+ "op": "==", -+ "right": 31337 -+ } -+ } -+] -+ -+# sctp chunk asconf seqno 12345 -+[ -+ { -+ "match": { -+ "left": { -+ "sctp chunk": { -+ "field": "seqno", -+ "name": "asconf" -+ } -+ }, -+ "op": "==", -+ "right": 12345 -+ } -+ } -+] -+ -diff --git a/tests/py/inet/sctp.t.payload b/tests/py/inet/sctp.t.payload -index ecfcc7252a066..9c4854cfe71c3 100644 ---- a/tests/py/inet/sctp.t.payload -+++ b/tests/py/inet/sctp.t.payload -@@ -274,3 +274,158 @@ inet test-inet input - [ payload load 4b @ transport header + 4 => reg 1 ] - [ lookup reg 1 set __set%d 0x1 ] - -+# sctp chunk data exists -+ip -+ [ exthdr load 1b @ 0 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk init exists -+ip -+ [ exthdr load 1b @ 1 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk init-ack exists -+ip -+ [ exthdr load 1b @ 2 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk sack exists -+ip -+ [ exthdr load 1b @ 3 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk heartbeat exists -+ip -+ [ exthdr load 1b @ 4 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk heartbeat-ack exists -+ip -+ [ exthdr load 1b @ 5 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk abort exists -+ip -+ [ exthdr load 1b @ 6 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk shutdown exists -+ip -+ [ exthdr load 1b @ 7 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk shutdown-ack exists -+ip -+ [ exthdr load 1b @ 8 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk error exists -+ip -+ [ exthdr load 1b @ 9 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk cookie-echo exists -+ip -+ [ exthdr load 1b @ 10 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk cookie-ack exists -+ip -+ [ exthdr load 1b @ 11 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk ecne exists -+ip -+ [ exthdr load 1b @ 12 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk cwr exists -+ip -+ [ exthdr load 1b @ 13 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk shutdown-complete exists -+ip -+ [ exthdr load 1b @ 14 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk asconf-ack exists -+ip -+ [ exthdr load 1b @ 128 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk forward-tsn exists -+ip -+ [ exthdr load 1b @ 192 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk asconf exists -+ip -+ [ exthdr load 1b @ 193 + 0 present => reg 1 ] -+ [ cmp eq reg 1 0x00000001 ] -+ -+# sctp chunk data type 0 -+ip -+ [ exthdr load 1b @ 0 + 0 => reg 1 ] -+ [ cmp eq reg 1 0x00000000 ] -+ -+# sctp chunk init flags 23 -+ip -+ [ exthdr load 1b @ 1 + 1 => reg 1 ] -+ [ cmp eq reg 1 0x00000017 ] -+ -+# sctp chunk init-ack length 42 -+ip -+ [ exthdr load 2b @ 2 + 2 => reg 1 ] -+ [ cmp eq reg 1 0x00002a00 ] -+ -+# sctp chunk data stream 1337 -+ip -+ [ exthdr load 2b @ 0 + 8 => reg 1 ] -+ [ cmp eq reg 1 0x00003905 ] -+ -+# sctp chunk init initial-tsn 5 -+ip -+ [ exthdr load 4b @ 1 + 16 => reg 1 ] -+ [ cmp eq reg 1 0x05000000 ] -+ -+# sctp chunk init-ack num-outbound-streams 3 -+ip -+ [ exthdr load 2b @ 2 + 12 => reg 1 ] -+ [ cmp eq reg 1 0x00000300 ] -+ -+# sctp chunk sack a-rwnd 1 -+ip -+ [ exthdr load 4b @ 3 + 8 => reg 1 ] -+ [ cmp eq reg 1 0x01000000 ] -+ -+# sctp chunk shutdown cum-tsn-ack 65535 -+ip -+ [ exthdr load 4b @ 7 + 4 => reg 1 ] -+ [ cmp eq reg 1 0xffff0000 ] -+ -+# sctp chunk ecne lowest-tsn 5 -+ip -+ [ exthdr load 4b @ 12 + 4 => reg 1 ] -+ [ cmp eq reg 1 0x05000000 ] -+ -+# sctp chunk cwr lowest-tsn 8 -+ip -+ [ exthdr load 4b @ 13 + 4 => reg 1 ] -+ [ cmp eq reg 1 0x08000000 ] -+ -+# sctp chunk asconf-ack seqno 12345 -+ip -+ [ exthdr load 4b @ 128 + 4 => reg 1 ] -+ [ cmp eq reg 1 0x39300000 ] -+ -+# sctp chunk forward-tsn new-cum-tsn 31337 -+ip -+ [ exthdr load 4b @ 192 + 4 => reg 1 ] -+ [ cmp eq reg 1 0x697a0000 ] -+ -+# sctp chunk asconf seqno 12345 -+ip -+ [ exthdr load 4b @ 193 + 4 => reg 1 ] -+ [ cmp eq reg 1 0x39300000 ] -+ --- -2.33.0 - diff --git a/SOURCES/0025-include-missing-sctp_chunk.h-in-Makefile.am.patch b/SOURCES/0025-include-missing-sctp_chunk.h-in-Makefile.am.patch deleted file mode 100644 index 7279044..0000000 --- a/SOURCES/0025-include-missing-sctp_chunk.h-in-Makefile.am.patch +++ /dev/null @@ -1,29 +0,0 @@ -From fe19063ce09d40ea94bf57c4af8b6c121aaf89e8 Mon Sep 17 00:00:00 2001 -From: Pablo Neira Ayuso -Date: Tue, 25 May 2021 14:04:36 +0200 -Subject: [PATCH] include: missing sctp_chunk.h in Makefile.am - -Fix make distcheck. - -Fixes: 0e3871cfd9a1 ("exthdr: Implement SCTP Chunk matching") -Signed-off-by: Pablo Neira Ayuso -(cherry picked from commit 117ceb4f527119a6d44bf5e23f2ff7a8d116658a) ---- - include/Makefile.am | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/Makefile.am b/include/Makefile.am -index 42f24f35ce7a5..4cd907380ebaa 100644 ---- a/include/Makefile.am -+++ b/include/Makefile.am -@@ -31,6 +31,7 @@ noinst_HEADERS = cli.h \ - osf.h \ - parser.h \ - proto.h \ -+ sctp_chunk.h \ - socket.h \ - rule.h \ - rt.h \ --- -2.33.0 - diff --git a/SOURCES/0026-evaluate-fix-inet-nat-with-no-layer-3-info.patch b/SOURCES/0026-evaluate-fix-inet-nat-with-no-layer-3-info.patch deleted file mode 100644 index 271c271..0000000 --- a/SOURCES/0026-evaluate-fix-inet-nat-with-no-layer-3-info.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0c371aeab906b6e65c4c86174cbe2fbca02891d1 Mon Sep 17 00:00:00 2001 -From: Pablo Neira Ayuso -Date: Tue, 20 Jul 2021 18:59:44 +0200 -Subject: [PATCH] evaluate: fix inet nat with no layer 3 info - -nft currently reports: - - Error: Could not process rule: Protocol error - add rule inet x y meta l4proto tcp dnat to :80 - ^^^^ - -default to NFPROTO_INET family, otherwise kernel bails out EPROTO when -trying to load the conntrack helper. - -Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1428 -Signed-off-by: Pablo Neira Ayuso -(cherry picked from commit 9a36033ce50638a403d1421935cdd1287ee5de6b) ---- - src/evaluate.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/src/evaluate.c b/src/evaluate.c -index bba685af720ed..73d6fd0e89bc2 100644 ---- a/src/evaluate.c -+++ b/src/evaluate.c -@@ -2896,9 +2896,10 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt) - stmt->nat.family = ctx->pctx.family; - return 0; - case NFPROTO_INET: -- if (!stmt->nat.addr) -+ if (!stmt->nat.addr) { -+ stmt->nat.family = NFPROTO_INET; - return 0; -- -+ } - if (stmt->nat.family != NFPROTO_UNSPEC) - return 0; - --- -2.34.1 - diff --git a/SOURCES/0027-tests-py-add-dnat-to-port-without-defining-destinati.patch b/SOURCES/0027-tests-py-add-dnat-to-port-without-defining-destinati.patch deleted file mode 100644 index 5659ece..0000000 --- a/SOURCES/0027-tests-py-add-dnat-to-port-without-defining-destinati.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 00d3745306aa87eeb2466dbb5e6958225de3354f Mon Sep 17 00:00:00 2001 -From: Pablo Neira Ayuso -Date: Thu, 22 Jul 2021 17:43:56 +0200 -Subject: [PATCH] tests: py: add dnat to port without defining destination - address - -Add a test to cover dnat to port without destination address. - -Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1428 -Signed-off-by: Pablo Neira Ayuso -(cherry picked from commit 0f27e258b37a592233d6ad5381cd1fae65e57514) ---- - tests/py/inet/dnat.t | 1 + - tests/py/inet/dnat.t.json | 20 ++++++++++++++++++++ - tests/py/inet/dnat.t.payload | 7 +++++++ - 3 files changed, 28 insertions(+) - -diff --git a/tests/py/inet/dnat.t b/tests/py/inet/dnat.t -index b460af3925570..e4e169f2bc3ec 100644 ---- a/tests/py/inet/dnat.t -+++ b/tests/py/inet/dnat.t -@@ -6,6 +6,7 @@ iifname "foo" tcp dport 80 redirect to :8080;ok - - iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2;ok - iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443;ok -+meta l4proto tcp dnat to :80;ok;meta l4proto 6 dnat to :80 - - dnat ip to ct mark map { 0x00000014 : 1.2.3.4};ok - dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok -diff --git a/tests/py/inet/dnat.t.json b/tests/py/inet/dnat.t.json -index 1b8aba6297d36..c341a0455fea1 100644 ---- a/tests/py/inet/dnat.t.json -+++ b/tests/py/inet/dnat.t.json -@@ -219,3 +219,23 @@ - } - ] - -+# meta l4proto tcp dnat to :80 -+[ -+ { -+ "match": { -+ "left": { -+ "meta": { -+ "key": "l4proto" -+ } -+ }, -+ "op": "==", -+ "right": 6 -+ } -+ }, -+ { -+ "dnat": { -+ "port": 80 -+ } -+ } -+] -+ -diff --git a/tests/py/inet/dnat.t.payload b/tests/py/inet/dnat.t.payload -index a741b9cbdb8d7..be5baf8fd4b47 100644 ---- a/tests/py/inet/dnat.t.payload -+++ b/tests/py/inet/dnat.t.payload -@@ -77,3 +77,10 @@ inet - [ immediate reg 2 0x00005000 ] - [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ] - -+# meta l4proto tcp dnat to :80 -+inet -+ [ meta load l4proto => reg 1 ] -+ [ cmp eq reg 1 0x00000006 ] -+ [ immediate reg 1 0x00005000 ] -+ [ nat dnat inet proto_min reg 1 flags 0x2 ] -+ --- -2.34.1 - diff --git a/SOURCES/0028-evaluate-pick-data-element-byte-order-not-dtype-one.patch b/SOURCES/0028-evaluate-pick-data-element-byte-order-not-dtype-one.patch deleted file mode 100644 index c3ce4f0..0000000 --- a/SOURCES/0028-evaluate-pick-data-element-byte-order-not-dtype-one.patch +++ /dev/null @@ -1,36 +0,0 @@ -From d5525024223f324c71edb9135f1938745d45acee Mon Sep 17 00:00:00 2001 -From: Florian Westphal -Date: Wed, 3 Feb 2021 17:57:06 +0100 -Subject: [PATCH] evaluate: pick data element byte order, not dtype one - -Some expressions have integer base type, not a specific one, e.g. 'ct zone'. -In that case nft used the wrong byte order. - -Without this, nft adds -elements = { "eth0" : 256, "eth1" : 512, "veth4" : 256 } -instead of 1, 2, 3. - -This is not a 'display bug', the added elements have wrong byte order. - -Signed-off-by: Florian Westphal -(cherry picked from commit 84b1d078e86dea25c93e15c3e5a3160bbf77e4e7) ---- - src/evaluate.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/evaluate.c b/src/evaluate.c -index 73d6fd0e89bc2..0543190fe777a 100644 ---- a/src/evaluate.c -+++ b/src/evaluate.c -@@ -1583,7 +1583,7 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr) - else - datalen = set->data->len; - -- expr_set_context(&ctx->ectx, set->data->dtype, datalen); -+ __expr_set_context(&ctx->ectx, set->data->dtype, set->data->byteorder, datalen, 0); - } else { - assert((set->flags & NFT_SET_MAP) == 0); - } --- -2.34.1 - diff --git a/SPECS/nftables.spec b/SPECS/nftables.spec index 75b771a..7d2de70 100644 --- a/SPECS/nftables.spec +++ b/SPECS/nftables.spec @@ -1,6 +1,9 @@ +%define rpmversion 1.0.4 +%define specrelease 2 + Name: nftables -Version: 0.9.8 -Release: 12%{?dist} +Version: %{rpmversion} +Release: %{specrelease}%{?dist}%{?buildid} # Upstream released a 0.100 version, then 0.4. Need Epoch to get back on track. Epoch: 1 Summary: Netfilter Tables userspace utillites @@ -14,49 +17,26 @@ Source3: main.nft Source4: router.nft Source5: nat.nft -Patch01: 0001-payload-check-icmp-dependency-before-removing-previo.patch -Patch02: 0002-tests-add-icmp-6-test-where-dependency-should-be-lef.patch -Patch03: 0003-main-fix-nft-help-output-fallout-from-719e4427.patch -Patch04: 0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch -Patch05: 0005-parser_json-Fix-for-memleak-in-tcp-option-error-path.patch -Patch06: 0006-evaluate-Mark-fall-through-case-in-str2hooknum.patch -Patch07: 0007-json-Drop-pointless-assignment-in-exthdr_expr_json.patch -Patch08: 0008-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch -Patch09: 0009-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch -Patch10: 0010-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch -Patch11: 0011-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch -Patch12: 0012-netlink_delinearize-Fix-suspicious-calloc-call.patch -Patch13: 0013-rule-Fix-for-potential-off-by-one-in-cmd_add_loc.patch -Patch14: 0014-src-add-xzalloc_array-and-use-it-to-allocate-the-exp.patch -Patch15: 0015-json-init-parser-state-for-every-new-buffer-file.patch -Patch16: 0016-segtree-Fix-segfault-when-restoring-a-huge-interval-.patch -Patch17: 0017-tests-cover-baecd1cf2685-segtree-Fix-segfault-when-r.patch -Patch18: 0018-doc-nft.8-Extend-monitor-description-by-trace.patch -Patch19: 0019-tests-shell-NFT-needs-to-be-invoked-unquoted.patch -Patch20: 0020-tests-shell-better-parameters-for-the-interval-stack.patch -Patch21: 0021-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch -Patch22: 0022-scanner-introduce-start-condition-stack.patch -Patch23: 0023-scanner-sctp-Move-to-own-scope.patch -Patch24: 0024-exthdr-Implement-SCTP-Chunk-matching.patch -Patch25: 0025-include-missing-sctp_chunk.h-in-Makefile.am.patch -Patch26: 0026-evaluate-fix-inet-nat-with-no-layer-3-info.patch -Patch27: 0027-tests-py-add-dnat-to-port-without-defining-destinati.patch -Patch28: 0028-evaluate-pick-data-element-byte-order-not-dtype-one.patch +Patch1: 0001-tests-shell-runtime-set-element-automerge.patch +Patch2: 0002-rule-collapse-set-element-commands.patch +Patch3: 0003-intervals-do-not-report-exact-overlaps-for-new-eleme.patch +Patch4: 0004-intervals-do-not-empty-cache-for-maps.patch +Patch5: 0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: libtool BuildRequires: make -BuildRequires: gcc +BuildRequires: gcc BuildRequires: flex BuildRequires: bison -BuildRequires: libmnl-devel +BuildRequires: pkgconfig(libmnl) >= 1.0.4 BuildRequires: gmp-devel BuildRequires: readline-devel -BuildRequires: libnftnl-devel +BuildRequires: pkgconfig(libnftnl) >= 1.2.2 BuildRequires: systemd BuildRequires: asciidoc -BuildRequires: iptables-devel +BuildRequires: pkgconfig(xtables) >= 1.6.1 BuildRequires: jansson-devel BuildRequires: python3-devel @@ -86,7 +66,7 @@ The nftables python module provides an interface to libnftables via ctypes. autoreconf -fi rm -Rf autom4te*.cache config.h.in~ %configure --disable-silent-rules --with-xtables --with-json \ - --enable-python --with-python-bin=%{__python3} + --enable-python --with-python-bin=%{__python3} --with-cli=readline %make_build %install @@ -104,7 +84,7 @@ cp -a %{SOURCE1} $RPM_BUILD_ROOT/%{_unitdir}/ mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig cp -a %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ -rm $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/*.nft +rm $RPM_BUILD_ROOT/%{_datadir}/nftables/*.nft cp %{SOURCE3} %{SOURCE4} %{SOURCE5} \ $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/ @@ -151,6 +131,21 @@ sed -i -e 's/\(sofile=\)".*"/\1"'$sofile'"/' \ %{python3_sitelib}/nftables/ %changelog +* Fri Jun 24 2022 Phil Sutter [1.0.4-2.el9] +- intervals: Do not sort cached set elements over and over again (Phil Sutter) [1917398] +- intervals: do not empty cache for maps (Phil Sutter) [1917398] +- intervals: do not report exact overlaps for new elements (Phil Sutter) [1917398] +- rule: collapse set element commands (Phil Sutter) [1917398] +- tests: shell: runtime set element automerge (Phil Sutter) [1917398] + +* Thu Jun 09 2022 Phil Sutter - 1:1.0.4-1 +- Review package dependencies +- new version 1.0.4 + +* Tue Mar 01 2022 Phil Sutter - 1:0.9.8-13 +- tests: extend dtype test case to cover expression with integer type +- evaluate: set evaluation context for set elements + * Fri Jan 14 2022 Phil Sutter - 1:0.9.8-12 - evaluate: pick data element byte order, not dtype one