* [PATCH nft 0/4] add mptcp suboption mnemonics
@ 2025-02-27 14:52 Florian Westphal
2025-02-27 14:52 ` [PATCH nft 1/4] tcpopt: add symbol table for mptcp suboptions Florian Westphal
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Florian Westphal @ 2025-02-27 14:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Allow users to do
tcp option mptcp subtype mp-capable
instead of having to use the raw values described in rfc8684.
First patch adds this, rest of the patches resolve printing issues
when the mptcp option match is used in sets and concatenations.
Florian Westphal (4):
tcpopt: add symbol table for mptcp suboptions
expression: propagate key datatype for anonymous sets
netlink_delinearize: also consider exthdr type when trimming binops
expression: expr_build_udata_recurse should recurse
include/datatype.h | 5 +-
src/expression.c | 37 +++++++-
src/netlink_delinearize.c | 10 +-
src/tcpopt.c | 30 +++++-
tests/py/any/tcpopt.t | 7 +-
tests/py/any/tcpopt.t.json | 94 +++++++++++++++++--
tests/py/any/tcpopt.t.payload | 25 +++--
.../testcases/sets/dumps/typeof_sets_0.nft | 19 ++++
tests/shell/testcases/sets/typeof_sets_0 | 37 ++++++++
9 files changed, 245 insertions(+), 19 deletions(-)
--
2.45.3
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH nft 1/4] tcpopt: add symbol table for mptcp suboptions
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
@ 2025-02-27 14:52 ` Florian Westphal
2025-02-27 14:52 ` [PATCH nft 2/4] expression: propagate key datatype for anonymous sets Florian Westphal
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2025-02-27 14:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
nft can be used t match on specific multipath tcp subtypes:
tcp option mptcp subtype 0
However, depending on which subtype to match, users need to look up the
type/value to use in rfc8684. Add support for mnemonics and
"nft describe tcp option mptcp subtype" to get the subtype list.
Because the number of unique 'enum datatypes' is limited by ABI contraints
this adds a new mptcp suboption type as integer alias.
After this patch, nft supports all of the following:
add element t s { mp-capable }
add rule t c tcp option mptcp subtype mp-capable
add rule t c tcp option mptcp subtype { mp-capable, mp-fail }
For the 3rd case, listing will break because unlike for named sets, nft
lacks the type information needed to pretty-print the integer values,
i.e. nft will print the 3rd rule as 'subtype { 0, 6 }'.
This is resolved in a followup patch.
Other problematic constructs are:
set s1 {
typeof tcp option mptcp subtype . ip saddr
elements = { mp-fail . 1.2.3.4 }
}
Followed by:
tcp option mptcp subtype . ip saddr @s1
nft will print this as:
tcp option mptcp unknown & 240) >> 4 . ip saddr @s1
All of these issues are not related to this patch, however, they also occur
with other bit-sized extheader fields.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/datatype.h | 5 +++-
src/tcpopt.c | 30 ++++++++++++++++++-
tests/py/any/tcpopt.t | 4 +--
tests/py/any/tcpopt.t.json | 6 ++--
tests/py/any/tcpopt.t.payload | 2 +-
.../testcases/sets/dumps/typeof_sets_0.nft | 9 ++++++
tests/shell/testcases/sets/typeof_sets_0 | 18 +++++++++++
7 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/include/datatype.h b/include/datatype.h
index 8b950f9165a5..4fb47f158fc2 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -251,7 +251,6 @@ extern const struct datatype verdict_type;
extern const struct datatype nfproto_type;
extern const struct datatype bitmask_type;
extern const struct datatype integer_type;
-extern const struct datatype xinteger_type;
extern const struct datatype string_type;
extern const struct datatype lladdr_type;
extern const struct datatype ipaddr_type;
@@ -279,6 +278,10 @@ extern const struct datatype reject_icmp_code_type;
extern const struct datatype reject_icmpv6_code_type;
extern const struct datatype reject_icmpx_code_type;
+/* TYPE_INTEGER aliases: */
+extern const struct datatype xinteger_type;
+extern const struct datatype mptcpopt_subtype;
+
void inet_service_type_print(const struct expr *expr, struct output_ctx *octx);
extern const struct datatype *concat_type_alloc(uint32_t type);
diff --git a/src/tcpopt.c b/src/tcpopt.c
index f977e417536a..d8139337cc20 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -108,6 +108,31 @@ static const struct exthdr_desc tcpopt_md5sig = {
},
};
+static const struct symbol_table mptcp_subtype_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("mp-capable", 0),
+ SYMBOL("mp-join", 1),
+ SYMBOL("dss", 2),
+ SYMBOL("add-addr", 3),
+ SYMBOL("remove-addr", 4),
+ SYMBOL("mp-prio", 5),
+ SYMBOL("mp-fail", 6),
+ SYMBOL("mp-fastclose", 7),
+ SYMBOL("mp-tcprst", 8),
+ SYMBOL_LIST_END
+ },
+};
+
+/* alias of integer_type to parse mptcp subtypes */
+const struct datatype mptcpopt_subtype = {
+ .type = TYPE_INTEGER,
+ .name = "integer",
+ .desc = "mptcp option subtype",
+ .size = 4,
+ .basetype = &integer_type,
+ .sym_tbl = &mptcp_subtype_tbl,
+};
static const struct exthdr_desc tcpopt_mptcp = {
.name = "mptcp",
@@ -115,7 +140,10 @@ static const struct exthdr_desc tcpopt_mptcp = {
.templates = {
[TCPOPT_MPTCP_KIND] = PHT("kind", 0, 8),
[TCPOPT_MPTCP_LENGTH] = PHT("length", 8, 8),
- [TCPOPT_MPTCP_SUBTYPE] = PHT("subtype", 16, 4),
+ [TCPOPT_MPTCP_SUBTYPE] = PROTO_HDR_TEMPLATE("subtype",
+ &mptcpopt_subtype,
+ BYTEORDER_BIG_ENDIAN,
+ 16, 4),
},
};
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 177f01c45506..a2fcdb3afb25 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -51,8 +51,8 @@ tcp option md5sig exists;ok
tcp option fastopen exists;ok
tcp option mptcp exists;ok
-tcp option mptcp subtype 0;ok
-tcp option mptcp subtype 1;ok
+tcp option mptcp subtype mp-capable;ok
+tcp option mptcp subtype 1;ok;tcp option mptcp subtype mp-join
tcp option mptcp subtype { 0, 2};ok
reset tcp option mptcp;ok
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index 87074b9d216a..ea580473c8ad 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -533,7 +533,7 @@
}
]
-# tcp option mptcp subtype 0
+# tcp option mptcp subtype mp-capable
[
{
"match": {
@@ -544,7 +544,7 @@
}
},
"op": "==",
- "right": 0
+ "right": "mp-capable"
}
}
]
@@ -560,7 +560,7 @@
}
},
"op": "==",
- "right": 1
+ "right": "mp-join"
}
}
]
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index 99b8985f0f68..e3cf500b964b 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -168,7 +168,7 @@ inet
[ exthdr load tcpopt 1b @ 30 + 0 present => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option mptcp subtype 0
+# tcp option mptcp subtype mp-capable
inet
[ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
index 63fc5b145137..ed45d84a0eff 100644
--- a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -60,6 +60,11 @@ table inet t {
elements = { "eth0" . 10.1.1.2 . exists }
}
+ set s13 {
+ typeof tcp option mptcp subtype
+ elements = { mp-join, dss }
+ }
+
chain c1 {
osf name @s1 accept
}
@@ -103,4 +108,8 @@ table inet t {
chain c12 {
iifname . ip saddr . meta ipsec @s12 accept
}
+
+ chain c13 {
+ tcp option mptcp subtype @s13 accept
+ }
}
diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
index a105acffde48..5ba7fc76ce15 100755
--- a/tests/shell/testcases/sets/typeof_sets_0
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -119,6 +119,11 @@ INPUT="table inet t {$INPUT_OSF_SET
typeof meta iifname . ip saddr . meta ipsec
elements = { \"eth0\" . 10.1.1.2 . 1 }
}
+
+ set s13 {
+ typeof tcp option mptcp subtype
+ elements = { mp-join, dss }
+ }
$INPUT_OSF_CHAIN
chain c2 {
ether type vlan vlan id @s2 accept
@@ -148,6 +153,10 @@ $INPUT_VERSION_CHAIN
chain c12 {
meta iifname . ip saddr . meta ipsec @s12 accept
}
+
+ chain c13 {
+ tcp option mptcp subtype @s13 accept
+ }
}"
EXPECTED="table inet t {$INPUT_OSF_SET
@@ -196,6 +205,11 @@ $INPUT_VERSION_SET
typeof iifname . ip saddr . meta ipsec
elements = { \"eth0\" . 10.1.1.2 . exists }
}
+
+ set s13 {
+ typeof tcp option mptcp subtype
+ elements = { mp-join, dss }
+ }
$INPUT_OSF_CHAIN
chain c2 {
vlan id @s2 accept
@@ -224,6 +238,10 @@ $INPUT_SCTP_CHAIN$INPUT_VERSION_CHAIN
chain c12 {
iifname . ip saddr . meta ipsec @s12 accept
}
+
+ chain c13 {
+ tcp option mptcp subtype @s13 accept
+ }
}"
--
2.45.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nft 2/4] expression: propagate key datatype for anonymous sets
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
2025-02-27 14:52 ` [PATCH nft 1/4] tcpopt: add symbol table for mptcp suboptions Florian Westphal
@ 2025-02-27 14:52 ` Florian Westphal
2025-02-27 14:52 ` [PATCH nft 3/4] netlink_delinearize: also consider exthdr type when trimming binops Florian Westphal
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2025-02-27 14:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
set s {
typeof tcp option mptcp subtype
elements = { mp-join, dss }
}
is listed correctly. The set key provides the 'mptcpopt_subtype'
information and listing can print all elements with symbolic names.
In anon set case this doesn't work:
tcp option mptcp subtype { mp-join, dss }
is printed as "... subtype { 1, 2}" because the anon set only provides
plain integer type.
This change propagates the datatype to the individual members of the
anon set.
After this change, multiple existing data types such as TYPE_ICMP_TYPE
could theoretically be replaced by integer-type aliases.
However, those datatypes are already exposed to userspace via the
'set type' keyword. Thus removing them will break set definitions that
use them.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/expression.c | 35 +++++++++++++++++++++++++++++++++++
tests/py/any/tcpopt.t | 2 +-
tests/py/any/tcpopt.t.json | 11 ++++++++---
tests/py/any/tcpopt.t.payload | 10 +++++-----
4 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/src/expression.c b/src/expression.c
index 53d4c521ae18..d2fa46509262 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1485,6 +1485,32 @@ static void set_ref_expr_destroy(struct expr *expr)
set_free(expr->set);
}
+static void set_ref_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ const struct set *s = expr->set;
+
+ /* normal sets already have a precise datatype that is given in
+ * the set definition via type foo.
+ *
+ * Anon sets do not have this, and need to rely on type info
+ * generated at rule creation time.
+ *
+ * For most cases, the type info is correct.
+ * In some cases however, the kernel only stores TYPE_INTEGER.
+ *
+ * This happens with expressions that only use an integer alias
+ * type, e.g. the mptcpopt_subtype datatype.
+ *
+ * In this case nft will print the elements as numerical values
+ * because the base type lacks the ->sym_tbl information of the
+ * subtypes.
+ */
+ if (s->init && set_is_anonymous(s->flags))
+ expr_set_type(s->init, dtype, byteorder);
+}
+
static const struct expr_ops set_ref_expr_ops = {
.type = EXPR_SET_REF,
.name = "set reference",
@@ -1492,6 +1518,7 @@ static const struct expr_ops set_ref_expr_ops = {
.json = set_ref_expr_json,
.clone = set_ref_expr_clone,
.destroy = set_ref_expr_destroy,
+ .set_type = set_ref_expr_set_type,
};
struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
@@ -1556,6 +1583,13 @@ static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
__set_elem_expr_clone(new, expr);
}
+static void set_elem_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ expr_set_type(expr->key, dtype, byteorder);
+}
+
static const struct expr_ops set_elem_expr_ops = {
.type = EXPR_SET_ELEM,
.name = "set element",
@@ -1563,6 +1597,7 @@ static const struct expr_ops set_elem_expr_ops = {
.print = set_elem_expr_print,
.json = set_elem_expr_json,
.destroy = set_elem_expr_destroy,
+ .set_type = set_elem_expr_set_type,
};
struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index a2fcdb3afb25..79699e23a4b1 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -53,7 +53,7 @@ tcp option mptcp exists;ok
tcp option mptcp subtype mp-capable;ok
tcp option mptcp subtype 1;ok;tcp option mptcp subtype mp-join
-tcp option mptcp subtype { 0, 2};ok
+tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst };ok
reset tcp option mptcp;ok
reset tcp option 2;ok;reset tcp option maxseg
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index ea580473c8ad..a02e71b66c36 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -565,7 +565,7 @@
}
]
-# tcp option mptcp subtype { 0, 2}
+# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst }
[
{
"match": {
@@ -578,8 +578,13 @@
"op": "==",
"right": {
"set": [
- 0,
- 2
+ "mp-capable",
+ "mp-join",
+ "remove-addr",
+ "mp-prio",
+ "mp-fail",
+ "mp-fastclose",
+ "mp-tcprst"
]
}
}
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index e3cf500b964b..af8c4317e567 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -180,11 +180,11 @@ inet
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
-# tcp option mptcp subtype { 0, 2}
-__set%d test-inet 3 size 2
-__set%d test-inet 0
- element 00000000 : 0 [end] element 00000020 : 0 [end]
-inet
+# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst }
+__set%d test-ip4 3 size 7
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000010 : 0 [end] element 00000040 : 0 [end] element 00000050 : 0 [end] element 00000060 : 0 [end] element 00000070 : 0 [end] element 00000080 : 0 [end]
+ip test-ip4 input
[ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
--
2.45.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nft 3/4] netlink_delinearize: also consider exthdr type when trimming binops
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
2025-02-27 14:52 ` [PATCH nft 1/4] tcpopt: add symbol table for mptcp suboptions Florian Westphal
2025-02-27 14:52 ` [PATCH nft 2/4] expression: propagate key datatype for anonymous sets Florian Westphal
@ 2025-02-27 14:52 ` Florian Westphal
2025-02-27 14:52 ` [PATCH nft 4/4] expression: expr_build_udata_recurse should recurse Florian Westphal
2025-03-05 21:03 ` [PATCH nft 0/4] add mptcp suboption mnemonics Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2025-02-27 14:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
This allows trimming the binop for exthdrs, this will make nft render
(tcp option mptcp unknown & 240) >> 4 . ip saddr @s1
as
tcp option mptcp subtype . ip saddr @s1
Also extend the typeof set tests with a set concatenating a
sub-byte-sized exthdr expression with a payload one.
The additional call to expr_postprocess() is needed, without this,
typeof_sets_0.nft fails because
frag frag-off @s4 accept
is shown as
meta nfproto ipv6 frag frag-off @s4 accept
Previouly, EXPR_EXTHDR would cause payload_binop_postprocess()
to return false which will then make the caller invoke
expr_postprocess(), but after handling EXPR_EXTHDR this doesn't happen
anymore.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/netlink_delinearize.c | 10 +++++++++-
.../testcases/sets/dumps/typeof_sets_0.nft | 10 ++++++++++
tests/shell/testcases/sets/typeof_sets_0 | 19 +++++++++++++++++++
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index b629916ebff8..698bae85c8cc 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2655,8 +2655,16 @@ static bool payload_binop_postprocess(struct rule_pp_ctx *ctx,
if (expr->left->etype != EXPR_BINOP || expr->left->op != OP_AND)
return false;
- if (expr->left->left->etype != EXPR_PAYLOAD)
+ switch (expr->left->left->etype) {
+ case EXPR_EXTHDR:
+ break;
+ case EXPR_PAYLOAD:
+ break;
+ default:
return false;
+ }
+
+ expr_postprocess(ctx, &expr->left->left);
expr_set_type(expr->right, &integer_type,
BYTEORDER_HOST_ENDIAN);
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
index ed45d84a0eff..34aaab601cda 100644
--- a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -65,6 +65,12 @@ table inet t {
elements = { mp-join, dss }
}
+ set s14 {
+ typeof tcp option mptcp subtype . ip daddr
+ elements = { remove-addr . 10.1.1.1,
+ mp-join . 10.1.1.2 }
+ }
+
chain c1 {
osf name @s1 accept
}
@@ -112,4 +118,8 @@ table inet t {
chain c13 {
tcp option mptcp subtype @s13 accept
}
+
+ chain c14 {
+ tcp option mptcp subtype . ip saddr @s14 accept
+ }
}
diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
index 5ba7fc76ce15..ef2726db3b30 100755
--- a/tests/shell/testcases/sets/typeof_sets_0
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -124,6 +124,11 @@ INPUT="table inet t {$INPUT_OSF_SET
typeof tcp option mptcp subtype
elements = { mp-join, dss }
}
+
+ set s14 {
+ typeof tcp option mptcp subtype . ip daddr
+ elements = { remove-addr . 10.1.1.1, mp-join . 10.1.1.2 }
+ }
$INPUT_OSF_CHAIN
chain c2 {
ether type vlan vlan id @s2 accept
@@ -157,6 +162,10 @@ $INPUT_VERSION_CHAIN
chain c13 {
tcp option mptcp subtype @s13 accept
}
+
+ chain c14 {
+ tcp option mptcp subtype . ip saddr @s14 accept
+ }
}"
EXPECTED="table inet t {$INPUT_OSF_SET
@@ -210,6 +219,12 @@ $INPUT_VERSION_SET
typeof tcp option mptcp subtype
elements = { mp-join, dss }
}
+
+ set s14 {
+ typeof tcp option mptcp subtype . ip daddr
+ elements = { remove-addr . 10.1.1.1,
+ mp-join . 10.1.1.2 }
+ }
$INPUT_OSF_CHAIN
chain c2 {
vlan id @s2 accept
@@ -242,6 +257,10 @@ $INPUT_SCTP_CHAIN$INPUT_VERSION_CHAIN
chain c13 {
tcp option mptcp subtype @s13 accept
}
+
+ chain c14 {
+ tcp option mptcp subtype . ip saddr @s14 accept
+ }
}"
--
2.45.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH nft 4/4] expression: expr_build_udata_recurse should recurse
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
` (2 preceding siblings ...)
2025-02-27 14:52 ` [PATCH nft 3/4] netlink_delinearize: also consider exthdr type when trimming binops Florian Westphal
@ 2025-02-27 14:52 ` Florian Westphal
2025-03-05 21:03 ` [PATCH nft 0/4] add mptcp suboption mnemonics Pablo Neira Ayuso
4 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2025-02-27 14:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
If we see EXPR_BINOP, recurse: ->left can be another EXPR_BINOP.
This is irrelevant for 'typeof' named sets, but for anonymous sets, the
key is derived from the concat expression that builds the lookup key for
the anonymous set.
tcp option mptcp subtype . ip daddr { mp-join. 10.0.0.1, ..
needs two binops back-to-back:
[ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ bitwise reg 1 = ( reg 1 >> 0x00000004 ) ]
This bug prevents concat_expr_build_udata() from creating the userdata key
at load time.
When listing the rules, we get an assertion:
nft: src/mergesort.c:23: concat_expr_msort_value: Assertion `ilen > 0' failed.
because the set has a key with 0-length integers.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/expression.c | 2 +-
tests/py/any/tcpopt.t | 1 +
tests/py/any/tcpopt.t.json | 77 +++++++++++++++++++++++++++++++++++
tests/py/any/tcpopt.t.payload | 13 ++++++
4 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/src/expression.c b/src/expression.c
index d2fa46509262..8a90e09dd1c5 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1078,7 +1078,7 @@ static struct expr *expr_build_udata_recurse(struct expr *e)
{
switch (e->etype) {
case EXPR_BINOP:
- return e->left;
+ return expr_build_udata_recurse(e->left);
default:
break;
}
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 79699e23a4b1..3d46c0efc231 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -54,6 +54,7 @@ tcp option mptcp exists;ok
tcp option mptcp subtype mp-capable;ok
tcp option mptcp subtype 1;ok;tcp option mptcp subtype mp-join
tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst };ok
+tcp option mptcp subtype . tcp dport { mp-capable . 10, mp-join . 100, add-addr . 200, remove-addr . 300, mp-prio . 400, mp-fail . 500, mp-fastclose . 600, mp-tcprst . 700 };ok
reset tcp option mptcp;ok
reset tcp option 2;ok;reset tcp option maxseg
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index a02e71b66c36..e712a5e0ed56 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -591,6 +591,83 @@
}
]
+# tcp option mptcp subtype . tcp dport { mp-capable . 10, mp-join . 100, add-addr . 200, remove-addr . 300, mp-prio . 400, mp-fail . 500, mp-fastclose . 600, mp-tcprst . 700 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "mp-capable",
+ 10
+ ]
+ },
+ {
+ "concat": [
+ "remove-addr",
+ 300
+ ]
+ },
+ {
+ "concat": [
+ "mp-fastclose",
+ 600
+ ]
+ },
+ {
+ "concat": [
+ "mp-join",
+ 100
+ ]
+ },
+ {
+ "concat": [
+ "mp-prio",
+ 400
+ ]
+ },
+ {
+ "concat": [
+ "mp-tcprst",
+ 700
+ ]
+ },
+ {
+ "concat": [
+ "add-addr",
+ 200
+ ]
+ },
+ {
+ "concat": [
+ "mp-fail",
+ 500
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
# reset tcp option mptcp
[
{
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index af8c4317e567..437e073aae1c 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -189,6 +189,19 @@ ip test-ip4 input
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
+# tcp option mptcp subtype . tcp dport { mp-capable . 10, mp-join . 100, add-addr . 200, remove-addr . 300, mp-prio . 400, mp-fail . 500, mp-fastclose . 600, mp-tcprst . 700 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000000 00000a00 : 0 [end] element 00000001 00006400 : 0 [end] element 00000003 0000c800 : 0 [end] element 00000004 00002c01 : 0 [end] element 00000005 00009001 : 0 [end] element 00000006 0000f401 : 0 [end] element 00000007 00005802 : 0 [end] element 00000008 0000bc02 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000004 ) ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
# reset tcp option mptcp
ip test-ip4 input
[ exthdr reset tcpopt 30 ]
--
2.45.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH nft 0/4] add mptcp suboption mnemonics
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
` (3 preceding siblings ...)
2025-02-27 14:52 ` [PATCH nft 4/4] expression: expr_build_udata_recurse should recurse Florian Westphal
@ 2025-03-05 21:03 ` Pablo Neira Ayuso
2025-03-05 22:40 ` Pablo Neira Ayuso
4 siblings, 1 reply; 7+ messages in thread
From: Pablo Neira Ayuso @ 2025-03-05 21:03 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
On Thu, Feb 27, 2025 at 03:52:06PM +0100, Florian Westphal wrote:
> Allow users to do
> tcp option mptcp subtype mp-capable
>
> instead of having to use the raw values described in rfc8684.
>
> First patch adds this, rest of the patches resolve printing issues
> when the mptcp option match is used in sets and concatenations.
For this series.
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
Thanks.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH nft 0/4] add mptcp suboption mnemonics
2025-03-05 21:03 ` [PATCH nft 0/4] add mptcp suboption mnemonics Pablo Neira Ayuso
@ 2025-03-05 22:40 ` Pablo Neira Ayuso
0 siblings, 0 replies; 7+ messages in thread
From: Pablo Neira Ayuso @ 2025-03-05 22:40 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
[-- Attachment #1: Type: text/plain, Size: 520 bytes --]
On Wed, Mar 05, 2025 at 10:03:28PM +0100, Pablo Neira Ayuso wrote:
> On Thu, Feb 27, 2025 at 03:52:06PM +0100, Florian Westphal wrote:
> > Allow users to do
> > tcp option mptcp subtype mp-capable
> >
> > instead of having to use the raw values described in rfc8684.
> >
> > First patch adds this, rest of the patches resolve printing issues
> > when the mptcp option match is used in sets and concatenations.
>
> For this series.
>
> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
BTW, maybe add this too?
[-- Attachment #2: mptcp.patch --]
[-- Type: text/x-diff, Size: 1070 bytes --]
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 2a155aa87b6f..c363ba355138 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -735,7 +735,7 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC
The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
[verse]
*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
-*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp* | *mptcp*}
*ip option* { lsrr | ra | rr | ssrr }
*dccp option* 'dccp_option_type'
@@ -794,6 +794,9 @@ length, left, right
|timestamp|
TCP Timestamps |
length, tsval, tsecr
+|mptcp|
+MPTCP Option Subtype |
+subtype
|============================
TCP option matching also supports raw expression syntax to access arbitrary options:
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-03-05 22:41 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-27 14:52 [PATCH nft 0/4] add mptcp suboption mnemonics Florian Westphal
2025-02-27 14:52 ` [PATCH nft 1/4] tcpopt: add symbol table for mptcp suboptions Florian Westphal
2025-02-27 14:52 ` [PATCH nft 2/4] expression: propagate key datatype for anonymous sets Florian Westphal
2025-02-27 14:52 ` [PATCH nft 3/4] netlink_delinearize: also consider exthdr type when trimming binops Florian Westphal
2025-02-27 14:52 ` [PATCH nft 4/4] expression: expr_build_udata_recurse should recurse Florian Westphal
2025-03-05 21:03 ` [PATCH nft 0/4] add mptcp suboption mnemonics Pablo Neira Ayuso
2025-03-05 22:40 ` Pablo Neira Ayuso
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.