From 19549524d2f86a05d1fceb04e5f77390c697a06d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 17 2022 10:33:41 +0000 Subject: import nftables-0.9.8-12.el9 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f8f5b8b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/nftables-0.9.8.tar.bz2 diff --git a/.nftables.metadata b/.nftables.metadata new file mode 100644 index 0000000..55ded3f --- /dev/null +++ b/.nftables.metadata @@ -0,0 +1 @@ +c15ac5552959c8358975f6b3e15757841c6904c8 SOURCES/nftables-0.9.8.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 new file mode 100644 index 0000000..7c234c4 --- /dev/null +++ b/SOURCES/0001-payload-check-icmp-dependency-before-removing-previo.patch @@ -0,0 +1,122 @@ +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/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 new file mode 100644 index 0000000..f412459 --- /dev/null +++ b/SOURCES/0002-tests-add-icmp-6-test-where-dependency-should-be-lef.patch @@ -0,0 +1,165 @@ +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-main-fix-nft-help-output-fallout-from-719e4427.patch b/SOURCES/0003-main-fix-nft-help-output-fallout-from-719e4427.patch new file mode 100644 index 0000000..a9293bc --- /dev/null +++ b/SOURCES/0003-main-fix-nft-help-output-fallout-from-719e4427.patch @@ -0,0 +1,48 @@ +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-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch b/SOURCES/0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch new file mode 100644 index 0000000..6573573 --- /dev/null +++ b/SOURCES/0004-parser_bison-Fix-for-implicit-declaration-of-isalnum.patch @@ -0,0 +1,30 @@ +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-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 new file mode 100644 index 0000000..5a4a726 --- /dev/null +++ b/SOURCES/0005-parser_json-Fix-for-memleak-in-tcp-option-error-path.patch @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000..04180b5 --- /dev/null +++ b/SOURCES/0006-evaluate-Mark-fall-through-case-in-str2hooknum.patch @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000..2a97351 --- /dev/null +++ b/SOURCES/0007-json-Drop-pointless-assignment-in-exthdr_expr_json.patch @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000..253acbf --- /dev/null +++ b/SOURCES/0008-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000..d8539ab --- /dev/null +++ b/SOURCES/0009-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000..67fad59 --- /dev/null +++ b/SOURCES/0010-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000..9b4e889 --- /dev/null +++ b/SOURCES/0011-netlink-Avoid-memleak-in-error-path-of-netlink_delin.patch @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000..ac21f56 --- /dev/null +++ b/SOURCES/0012-netlink_delinearize-Fix-suspicious-calloc-call.patch @@ -0,0 +1,35 @@ +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 new file mode 100644 index 0000000..ae87cde --- /dev/null +++ b/SOURCES/0013-rule-Fix-for-potential-off-by-one-in-cmd_add_loc.patch @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000..0845e96 --- /dev/null +++ b/SOURCES/0014-src-add-xzalloc_array-and-use-it-to-allocate-the-exp.patch @@ -0,0 +1,71 @@ +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 new file mode 100644 index 0000000..16a0630 --- /dev/null +++ b/SOURCES/0015-json-init-parser-state-for-every-new-buffer-file.patch @@ -0,0 +1,38 @@ +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 new file mode 100644 index 0000000..5051a9e --- /dev/null +++ b/SOURCES/0016-segtree-Fix-segfault-when-restoring-a-huge-interval-.patch @@ -0,0 +1,61 @@ +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 new file mode 100644 index 0000000..a0d7945 --- /dev/null +++ b/SOURCES/0017-tests-cover-baecd1cf2685-segtree-Fix-segfault-when-r.patch @@ -0,0 +1,66 @@ +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 new file mode 100644 index 0000000..b58ed8a --- /dev/null +++ b/SOURCES/0018-doc-nft.8-Extend-monitor-description-by-trace.patch @@ -0,0 +1,63 @@ +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 new file mode 100644 index 0000000..5290318 --- /dev/null +++ b/SOURCES/0019-tests-shell-NFT-needs-to-be-invoked-unquoted.patch @@ -0,0 +1,53 @@ +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 new file mode 100644 index 0000000..39a6426 --- /dev/null +++ b/SOURCES/0020-tests-shell-better-parameters-for-the-interval-stack.patch @@ -0,0 +1,51 @@ +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 new file mode 100644 index 0000000..000a191 --- /dev/null +++ b/SOURCES/0021-json-Simplify-non-tcpopt-exthdr-printing-a-bit.patch @@ -0,0 +1,49 @@ +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 new file mode 100644 index 0000000..1bc0e4e --- /dev/null +++ b/SOURCES/0022-scanner-introduce-start-condition-stack.patch @@ -0,0 +1,167 @@ +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 new file mode 100644 index 0000000..3aa28a6 --- /dev/null +++ b/SOURCES/0023-scanner-sctp-Move-to-own-scope.patch @@ -0,0 +1,93 @@ +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 new file mode 100644 index 0000000..e2b5ba2 --- /dev/null +++ b/SOURCES/0024-exthdr-Implement-SCTP-Chunk-matching.patch @@ -0,0 +1,1622 @@ +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 new file mode 100644 index 0000000..7279044 --- /dev/null +++ b/SOURCES/0025-include-missing-sctp_chunk.h-in-Makefile.am.patch @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..271c271 --- /dev/null +++ b/SOURCES/0026-evaluate-fix-inet-nat-with-no-layer-3-info.patch @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000..5659ece --- /dev/null +++ b/SOURCES/0027-tests-py-add-dnat-to-port-without-defining-destinati.patch @@ -0,0 +1,75 @@ +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 new file mode 100644 index 0000000..c3ce4f0 --- /dev/null +++ b/SOURCES/0028-evaluate-pick-data-element-byte-order-not-dtype-one.patch @@ -0,0 +1,36 @@ +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/SOURCES/main.nft b/SOURCES/main.nft new file mode 100644 index 0000000..6460d10 --- /dev/null +++ b/SOURCES/main.nft @@ -0,0 +1,64 @@ +# Sample configuration for nftables service. +# Load this by calling 'nft -f /etc/nftables/main.nft'. + +# Note about base chain priorities: +# The priority values used in these sample configs are +# offset by 20 in order to avoid ambiguity when firewalld +# is also running which uses an offset of 10. This means +# that packets will traverse firewalld first and if not +# dropped/rejected there will hit the chains defined here. +# Chains created by iptables, ebtables and arptables tools +# do not use an offset, so those chains are traversed first +# in any case. + +# drop any existing nftables ruleset +flush ruleset + +# a common table for both IPv4 and IPv6 +table inet nftables_svc { + + # protocols to allow + set allowed_protocols { + type inet_proto + elements = { icmp, icmpv6 } + } + + # interfaces to accept any traffic on + set allowed_interfaces { + type ifname + elements = { "lo" } + } + + # services to allow + set allowed_tcp_dports { + type inet_service + elements = { ssh, 9090 } + } + + # this chain gathers all accept conditions + chain allow { + ct state established,related accept + + meta l4proto @allowed_protocols accept + iifname @allowed_interfaces accept + tcp dport @allowed_tcp_dports accept + } + + # base-chain for traffic to this host + chain INPUT { + type filter hook input priority filter + 20 + policy accept + + jump allow + reject with icmpx type port-unreachable + } +} + +# By default, any forwarding traffic is allowed. +# Uncomment the following line to filter it based +# on the same criteria as input traffic. +#include "/etc/nftables/router.nft" + +# Uncomment the following line to enable masquerading of +# forwarded traffic. May be used with or without router.nft. +#include "/etc/nftables/nat.nft" diff --git a/SOURCES/nat.nft b/SOURCES/nat.nft new file mode 100644 index 0000000..7079893 --- /dev/null +++ b/SOURCES/nat.nft @@ -0,0 +1,30 @@ +# Sample configuration snippet for nftables service. +# Meant to be included by main.nft, not for direct use. + +# dedicated table for IPv4 +table ip nftables_svc { + + # interfaces to masquerade traffic from + set masq_interfaces { + type ifname + elements = { "virbr0" } + } + + # networks to masquerade traffic from + # 'interval' flag is required to support subnets + set masq_ips { + type ipv4_addr + flags interval + elements = { 192.168.122.0/24 } + } + + # base-chain to manipulate conntrack in postrouting, + # will see packets for new or related traffic only + chain POSTROUTING { + type nat hook postrouting priority srcnat + 20 + policy accept + + iifname @masq_interfaces oifname != @masq_interfaces masquerade + ip saddr @masq_ips masquerade + } +} diff --git a/SOURCES/nftables.conf b/SOURCES/nftables.conf new file mode 100644 index 0000000..c3d9649 --- /dev/null +++ b/SOURCES/nftables.conf @@ -0,0 +1,8 @@ +# Uncomment the include statement here to load the default config sample +# in /etc/nftables for nftables service. + +#include "/etc/nftables/main.nft" + +# To customize, either edit the samples in /etc/nftables, append further +# commands to the end of this file or overwrite it after first service +# start by calling: 'nft list ruleset >/etc/sysconfig/nftables.conf'. diff --git a/SOURCES/nftables.service b/SOURCES/nftables.service new file mode 100644 index 0000000..1e8c194 --- /dev/null +++ b/SOURCES/nftables.service @@ -0,0 +1,17 @@ +[Unit] +Description=Netfilter Tables +Documentation=man:nft(8) +Wants=network-pre.target +Before=network-pre.target + +[Service] +Type=oneshot +ProtectSystem=full +ProtectHome=true +ExecStart=/sbin/nft -f /etc/sysconfig/nftables.conf +ExecReload=/sbin/nft 'flush ruleset; include "/etc/sysconfig/nftables.conf";' +ExecStop=/sbin/nft flush ruleset +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/router.nft b/SOURCES/router.nft new file mode 100644 index 0000000..6300a55 --- /dev/null +++ b/SOURCES/router.nft @@ -0,0 +1,16 @@ +# Sample configuration snippet for nftables service. +# Meant to be included by main.nft, not for direct use. + +# a common table for both IPv4 and IPv6 +table inet nftables_svc { + + # base-chain for traffic forwarded by this host + # re-uses 'allow' chain from main.nft + chain FORWARD { + type filter hook forward priority filter + 20 + policy accept + + jump allow + reject with icmpx type host-unreachable + } +} diff --git a/SPECS/nftables.spec b/SPECS/nftables.spec new file mode 100644 index 0000000..75b771a --- /dev/null +++ b/SPECS/nftables.spec @@ -0,0 +1,395 @@ +Name: nftables +Version: 0.9.8 +Release: 12%{?dist} +# Upstream released a 0.100 version, then 0.4. Need Epoch to get back on track. +Epoch: 1 +Summary: Netfilter Tables userspace utillites + +License: GPLv2 +URL: https://netfilter.org/projects/nftables/ +Source0: %{url}/files/%{name}-%{version}.tar.bz2 +Source1: nftables.service +Source2: nftables.conf +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 + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libtool +BuildRequires: make +BuildRequires: gcc +BuildRequires: flex +BuildRequires: bison +BuildRequires: libmnl-devel +BuildRequires: gmp-devel +BuildRequires: readline-devel +BuildRequires: libnftnl-devel +BuildRequires: systemd +BuildRequires: asciidoc +BuildRequires: iptables-devel +BuildRequires: jansson-devel +BuildRequires: python3-devel + +%description +Netfilter Tables userspace utilities. + +%package devel +Summary: Development library for nftables / libnftables +Requires: %{name} = %{epoch}:%{version}-%{release} +Requires: pkgconfig + +%description devel +Development tools and static libraries and header files for the libnftables library. + +%package -n python3-nftables +Summary: Python module providing an interface to libnftables +Requires: %{name} = %{epoch}:%{version}-%{release} +%{?python_provide:%python_provide python3-nftables} + +%description -n python3-nftables +The nftables python module provides an interface to libnftables via ctypes. + +%prep +%autosetup -p1 + +%build +autoreconf -fi +rm -Rf autom4te*.cache config.h.in~ +%configure --disable-silent-rules --with-xtables --with-json \ + --enable-python --with-python-bin=%{__python3} +%make_build + +%install +%make_install +find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' + +# Don't ship static lib (for now at least) +rm -f $RPM_BUILD_ROOT/%{_libdir}/libnftables.a + +chmod 644 $RPM_BUILD_ROOT/%{_mandir}/man8/nft* + +mkdir -p $RPM_BUILD_ROOT/%{_unitdir} +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 +cp %{SOURCE3} %{SOURCE4} %{SOURCE5} \ + $RPM_BUILD_ROOT/%{_sysconfdir}/nftables/ + +find $RPM_BUILD_ROOT/%{_sysconfdir} \ + \( -type d -exec chmod 0700 {} \; \) , \ + \( -type f -exec chmod 0600 {} \; \) + +# make nftables.py use the real library file name +# to avoid nftables-devel package dependency +sofile=$(readlink $RPM_BUILD_ROOT/%{_libdir}/libnftables.so) +sed -i -e 's/\(sofile=\)".*"/\1"'$sofile'"/' \ + $RPM_BUILD_ROOT/%{python3_sitelib}/nftables/nftables.py + +%post +%systemd_post nftables.service +%ldconfig_post + +%preun +%systemd_preun nftables.service + +%postun +%systemd_postun_with_restart nftables.service +%ldconfig_postun + +%files +%license COPYING +%config(noreplace) %{_sysconfdir}/nftables/ +%config(noreplace) %{_sysconfdir}/sysconfig/nftables.conf +%{_sbindir}/nft +%{_libdir}/libnftables.so.* +%{_mandir}/man5/libnftables-json.5* +%{_mandir}/man8/nft* +%{_unitdir}/nftables.service +%{_docdir}/nftables/examples/*.nft + +%files devel +%{_libdir}/libnftables.so +%{_libdir}/pkgconfig/libnftables.pc +%{_includedir}/nftables/libnftables.h +%{_mandir}/man3/libnftables.3* + +%files -n python3-nftables +%{python3_sitelib}/nftables-*.egg-info +%{python3_sitelib}/nftables/ + +%changelog +* Fri Jan 14 2022 Phil Sutter - 1:0.9.8-12 +- evaluate: pick data element byte order, not dtype one + +* Wed Dec 08 2021 Phil Sutter - 1:0.9.8-11 +- tests: py: add dnat to port without defining destination address +- evaluate: fix inet nat with no layer 3 info +- include: missing sctp_chunk.h in Makefile.am +- exthdr: Implement SCTP Chunk matching +- scanner: sctp: Move to own scope +- scanner: introduce start condition stack +- json: Simplify non-tcpopt exthdr printing a bit + +* Wed Dec 08 2021 Phil Sutter - 1:0.9.8-10 +- tests: shell: better parameters for the interval stack overflow test +- tests: shell: $NFT needs to be invoked unquoted + +* Thu Nov 11 2021 Phil Sutter - 1:0.9.8-9 +- doc: nft.8: Extend monitor description by trace + +* Fri Nov 05 2021 Phil Sutter - 1:0.9.8-8 +- tests: cover baecd1cf2685 ("segtree: Fix segfault when restoring a huge interval set") +- segtree: Fix segfault when restoring a huge interval set + +* Mon Aug 09 2021 Mohan Boddu - 1:0.9.8-7 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Fri Jun 18 2021 Phil Sutter - 1:0.9.8-6 +- json: init parser state for every new buffer/file + +* Tue Jun 15 2021 Phil Sutter - 1:0.9.8-5 +- src: add xzalloc_array() and use it to allocate the expression hashtable + +* Mon Jun 14 2021 Phil Sutter - 1:0.9.8-4 +- Install an improved sample config +- Fix permissions of osf-related configs +- rule: Fix for potential off-by-one in cmd_add_loc() +- netlink_delinearize: Fix suspicious calloc() call +- netlink: Avoid memleak in error path of netlink_delinearize_obj() +- netlink: Avoid memleak in error path of netlink_delinearize_table() +- netlink: Avoid memleak in error path of netlink_delinearize_chain() +- netlink: Avoid memleak in error path of netlink_delinearize_set() +- json: Drop pointless assignment in exthdr_expr_json() +- evaluate: Mark fall through case in str2hooknum() +- parser_json: Fix for memleak in tcp option error path +- parser_bison: Fix for implicit declaration of isalnum +- main: fix nft --help output fallout from 719e4427 +- tests: add icmp/6 test where dependency should be left alone +- payload: check icmp dependency before removing previous icmp expression + +* Fri Apr 16 2021 Mohan Boddu - 1:0.9.8-3 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Tue Jan 26 2021 Fedora Release Engineering - 1:0.9.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Sat Jan 16 2021 Kevin Fenzi - 0.9.8-1 +- Update to 0.9.8. Fixes rhbz#1916940 + +* Sat Oct 31 2020 Kevin Fenzi - 0.9.7-1 +- Update to 0.9.7. Fixes bug #1891769 + +* Thu Oct 29 2020 Stephen Gallagher - 1:0.9.6-2 +- Drop upstreamed patch + +* Sat Sep 05 2020 Neal Gompa - 1:0.9.6-1 +- Update to 0.9.6 (RH#1846663) + +* Tue Jul 28 2020 Fedora Release Engineering - 1:0.9.3-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 14 2020 Tom Stellard - 1:0.9.3-5 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Tue May 26 2020 Miro Hrončok - 1:0.9.3-4 +- Rebuilt for Python 3.9 + +* Fri May 15 2020 Richard Shaw - 1:0.9.3-3 +- Add patch for json performance with ipsets, fixes RHBZ#1834853. + +* Wed Jan 29 2020 Fedora Release Engineering - 1:0.9.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Wed Dec 04 2019 Phil Sutter - 1:0.9.3-1 +- Update to 0.9.3. Fixes bug #1778959 + +* Tue Oct 01 2019 Phil Sutter - 1:0.9.2-3 +- Drop unneeded docbook2X build dependency +- Add python3-nftables sub-package + +* Fri Aug 23 2019 Kevin Fenzi - 0.9.2-2 +- Move libnftables section 3 man page to devel package. + +* Fri Aug 23 2019 Kevin Fenzi - 0.9.2-1 +- Update to 0.9.2. Fixes bug #1743223 + +* Thu Jul 25 2019 Fedora Release Engineering - 1:0.9.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Fri Jun 28 2019 Kevin Fenzi - 0.9.1-2 +- Add some filters to nftables.conf + +* Tue Jun 25 2019 Kevin Fenzi - 0.9.1-1 +- Update to 0.9.1. Fixes bug #1723515 + +* Mon Jun 17 2019 Kevin Fenzi - 0.9.0-7 +- Rebuild for new libnftnl. + +* Sat Mar 16 2019 Kevin Fenzi - 1:0.9.0-6 +- Fix permissions. Bug #1685242 + +* Sun Feb 17 2019 Igor Gnatenko - 1:0.9.0-5 +- Rebuild for readline 8.0 + +* Fri Feb 01 2019 Fedora Release Engineering - 1:0.9.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Sun Nov 04 2018 Kevin Fenzi - 0.9.0-3 +- Fix config file to have correct include names. Fixes bug #1642103 + +* Fri Jul 13 2018 Fedora Release Engineering - 1:0.9.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Sat Jun 09 2018 Kevin Fenzi - 0.9.0-1 +- Update to 0.9.0. Fixes bug #1589404 + +* Fri May 11 2018 Kevin Fenzi - 0.8.5-1 +- Update to 0.8.5. Fixes bug #1576802 + +* Sun May 06 2018 Kevin Fenzi - 0.8.4-2 +- Fix devel package to require the Epoch too. +- Fix libraries split + +* Fri May 04 2018 Kevin Fenzi - 0.8.4-1 +- Update to 0.8.4. Fixes bug #1574096 + +* Sat Mar 03 2018 Kevin Fenzi - 0.8.3-1 +- Update to 0.8.3. Fixes bug #1551207 + +* Thu Feb 08 2018 Fedora Release Engineering - 1:0.8.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Feb 05 2018 Kevin Fenzi - 0.8.2-1 +- Update to 0.8.2. Fixes bug #1541582 + +* Tue Jan 16 2018 Kevin Fenzi - 0.8.1-1 +- Update to 0.8.1. Fixes bug #1534982 + +* Sun Oct 22 2017 Kevin Fenzi - 0.8-1 +- Update to 0.8. + +* Thu Aug 03 2017 Fedora Release Engineering - 1:0.7-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1:0.7-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering - 1:0.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Igor Gnatenko - 1:0.7-2 +- Rebuild for readline 7.x + +* Thu Dec 22 2016 Kevin Fenzi - 0.7-1 +- Update to 0.7 + +* Fri Jul 15 2016 Kevin Fenzi - 0.6-2 +- Rebuild for new glibc symbols + +* Thu Jun 02 2016 Kevin Fenzi - 0.6-1 +- Update to 0.6. + +* Sun Apr 10 2016 Kevin Fenzi - 0.5-4 +- Add example config files and move config to /etc/sysconfig. Fixes bug #1313936 + +* Fri Mar 25 2016 Kevin Fenzi - 0.5-3 +- Add systemd unit file. Fixes bug #1313936 + +* Thu Feb 04 2016 Fedora Release Engineering - 1:0.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Sep 17 2015 Kevin Fenzi 0.5-1 +- Update to 0.5 + +* Wed Jun 17 2015 Fedora Release Engineering - 1:0.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Sat Jan 10 2015 Kevin Fenzi 0.4-2 +- Add patch to fix nft -f dep gen. + +* Fri Dec 26 2014 Kevin Fenzi 0.4-1 +- Update to 0.4 +- Add Epoch to fix versioning. + +* Wed Sep 03 2014 Kevin Fenzi 0.100-4.20140903git +- Update to 20140903 snapshot + +* Sun Aug 17 2014 Fedora Release Engineering - 0.100-4.20140704git +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Jul 04 2014 Kevin Fenzi 0.100-3.20140704git +- Update to new snapshot + +* Sat Jun 07 2014 Fedora Release Engineering - 0.100-2.20140426git +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat Apr 26 2014 Kevin Fenzi 0.100-1.20140426git +- Update t0 20140426 + +* Sun Mar 30 2014 Kevin Fenzi 0.100-1.20140330git +- Update to 20140330 snapshot +- Sync versions to be post 0.100 release. + +* Wed Mar 26 2014 Kevin Fenzi 0-0.7.20140326git +- Update to 20140326 snapshot +- Fix permissions on man pages. + +* Mon Mar 24 2014 Kevin Fenzi 0-0.6.20140324git +- Update to 20140324 snapshot + +* Fri Mar 07 2014 Kevin Fenzi 0-0.5.20140307git +- Update to 20140307 + +* Sat Jan 25 2014 Kevin Fenzi 0-0.4.20140125git +- Update to 20140125 snapshot + +* Sat Jan 18 2014 Kevin Fenzi 0-0.3.20140118git +- Update to 20140118 snapshot +- Fixed License tag to be correct +- Fixed changelog +- nft scripts now use full path for nft +- Fixed man page building +- Dropped unneeded rm in install +- Patched build to not be silent. + +* Tue Dec 03 2013 Kevin Fenzi 0-0.2.20131202git +- Use upstream snapshots for source. +- Use 0 for version. + +* Sat Nov 30 2013 Kevin Fenzi 0-0.1 +- initial version for Fedora review