All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH nft] payload: Don't kill dependency for proto_th
@ 2025-02-25 10:03 Xiao Liang
  2025-02-25 20:35 ` Florian Westphal
  0 siblings, 1 reply; 3+ messages in thread
From: Xiao Liang @ 2025-02-25 10:03 UTC (permalink / raw)
  To: netfilter-devel

Since proto_th carries no information about the proto number, we need to
preserve the L4 protocol expression.

For example, if "meta l4proto 91 @th,0,16 0" is simplified to
"th sport 0", the information of protocol number is lost. This patch
changes it to "meta l4proto 91 th sport 0".

Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
---

Technically, if port is not defined for the L4 protocol, it's better to
keep "@th,0,16" as raw payload expressions rather than "th sport". But
it's not easy to figure out the context.

---
 src/payload.c                     |  1 +
 tests/py/any/rawpayload.t         |  1 +
 tests/py/any/rawpayload.t.json    | 31 +++++++++++++++++++++++++++++++
 tests/py/any/rawpayload.t.payload |  8 ++++++++
 4 files changed, 41 insertions(+)

diff --git a/src/payload.c b/src/payload.c
index f8b192b5..a039e242 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -920,6 +920,7 @@ void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
 			     unsigned int family)
 {
 	if (expr->payload.desc != &proto_unknown &&
+	    expr->payload.desc != &proto_th &&
 	    payload_dependency_exists(ctx, expr->payload.base) &&
 	    payload_may_dependency_kill(ctx, family, expr))
 		payload_dependency_release(ctx, expr->payload.base);
diff --git a/tests/py/any/rawpayload.t b/tests/py/any/rawpayload.t
index 745b4a61..4ef53f82 100644
--- a/tests/py/any/rawpayload.t
+++ b/tests/py/any/rawpayload.t
@@ -21,6 +21,7 @@ meta l4proto tcp @th,16,16 { 22, 23, 80};ok;tcp dport { 22, 23, 80}
 @ll,0,128 0xfedcba987654321001234567890abcde;ok
 
 meta l4proto 91 @th,400,16 0x0 accept;ok
+meta l4proto 91 @th,0,16 0x0 accept;ok;meta l4proto 91 th sport 0 accept
 
 @ih,32,32 0x14000000;ok
 @ih,58,6 set 0 @ih,86,6 set 0 @ih,170,22 set 0;ok;@ih,58,6 set 0x0 @ih,86,6 set 0x0 @ih,170,22 set 0x0
diff --git a/tests/py/any/rawpayload.t.json b/tests/py/any/rawpayload.t.json
index 4a06c598..2d3c7904 100644
--- a/tests/py/any/rawpayload.t.json
+++ b/tests/py/any/rawpayload.t.json
@@ -187,6 +187,37 @@
     }
 ]
 
+# meta l4proto 91 @th,0,16 0x0 accept
+[
+    {
+        "match": {
+            "left": {
+                "meta": {
+                    "key": "l4proto"
+                }
+            },
+            "op": "==",
+            "right": 91
+        }
+    },
+    {
+        "match": {
+            "left": {
+                "payload": {
+                    "field": "sport",
+                    "protocol": "th"
+                }
+            },
+            "op": "==",
+            "right": 0
+        }
+    },
+    {
+        "accept": null
+    }
+]
+
+
 # @ih,32,32 0x14000000
 [
     {
diff --git a/tests/py/any/rawpayload.t.payload b/tests/py/any/rawpayload.t.payload
index 8984eef6..c093d5d8 100644
--- a/tests/py/any/rawpayload.t.payload
+++ b/tests/py/any/rawpayload.t.payload
@@ -56,6 +56,14 @@ inet test-inet input
   [ cmp eq reg 1 0x00000000 ]
   [ immediate reg 0 accept ]
 
+# meta l4proto 91 @th,0,16 0x0 accept
+inet test-inet input
+  [ meta load l4proto => reg 1 ]
+  [ cmp eq reg 1 0x0000005b ]
+  [ payload load 2b @ transport header + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 ]
+  [ immediate reg 0 accept ]
+
 # @ih,32,32 0x14000000
 inet test-inet input
   [ payload load 4b @ inner header + 4 => reg 1 ]
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH nft] payload: Don't kill dependency for proto_th
  2025-02-25 10:03 [RFC PATCH nft] payload: Don't kill dependency for proto_th Xiao Liang
@ 2025-02-25 20:35 ` Florian Westphal
  2025-02-26  6:36   ` Xiao Liang
  0 siblings, 1 reply; 3+ messages in thread
From: Florian Westphal @ 2025-02-25 20:35 UTC (permalink / raw)
  To: Xiao Liang; +Cc: netfilter-devel

Xiao Liang <shaw.leon@gmail.com> wrote:
> Since proto_th carries no information about the proto number, we need to
> preserve the L4 protocol expression.
> 
> For example, if "meta l4proto 91 @th,0,16 0" is simplified to
> "th sport 0", the information of protocol number is lost. This patch
> changes it to "meta l4proto 91 th sport 0".
> 
> Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
> ---
> 
> Technically, if port is not defined for the L4 protocol, it's better to
> keep "@th,0,16" as raw payload expressions rather than "th sport". But
> it's not easy to figure out the context.

Yes, this is also because we don't store dependencies like
'meta l4proto { tcp, udp }', so we don't have access to this info when
we see the @th,0,16 load.

What do you make of this (it will display @th syntax for your test case)?

diff --git a/src/payload.c b/src/payload.c
--- a/src/payload.c
+++ b/src/payload.c
@@ -851,6 +851,58 @@ static bool payload_may_dependency_kill_ll(struct payload_dep_ctx *ctx, struct e
 	return true;
 }
 
+static bool l4proto_has_ports(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+	uint8_t v;
+
+	assert(expr->etype == EXPR_VALUE);
+
+	if (expr->len != 8)
+		return false;
+
+	v = mpz_get_uint8(expr->value);
+
+	switch (v) {
+	case IPPROTO_UDPLITE:
+	case IPPROTO_UDP:
+	case IPPROTO_TCP:
+	case IPPROTO_DCCP:
+	case IPPROTO_SCTP:
+		return true;
+	}
+
+	return false;
+}
+
+static bool payload_may_dependency_kill_th(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+	struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+	enum proto_bases b;
+
+	switch (dep->left->etype) {
+	case EXPR_PAYLOAD:
+		b = dep->left->payload.base;
+		break;
+	case EXPR_META:
+		b = dep->left->meta.base;
+		break;
+	default:
+		return false;
+	}
+
+	if (b != PROTO_BASE_NETWORK_HDR)
+		return false;
+
+	switch (dep->right->etype) {
+	case EXPR_VALUE:
+		return l4proto_has_ports(ctx, dep->right);
+	default:
+		break;
+	}
+
+	return false;
+}
+
 static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
 					unsigned int family, struct expr *expr)
 {
@@ -893,6 +945,15 @@ static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
 	if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
 		return true;
 
+	if (expr->payload.desc == &proto_th) {
+		if (payload_may_dependency_kill_th(ctx, expr))
+			return true;
+
+		/* prefer @th syntax, we don't have a 'source/destination port' protocol */
+		expr->payload.desc = &proto_unknown;
+		return false;
+	}
+
 	if (dep->left->etype != EXPR_PAYLOAD ||
 	    dep->left->payload.base != PROTO_BASE_TRANSPORT_HDR)
 		return true;


It would make sense to NOT set &proto_th from payload_init_raw(), but
that would place significant burden on netlink_delinearize to
pretty-print the typical use case for this, i.e.

'meta l4proto { tcp, udp } th dport 53 accept'


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH nft] payload: Don't kill dependency for proto_th
  2025-02-25 20:35 ` Florian Westphal
@ 2025-02-26  6:36   ` Xiao Liang
  0 siblings, 0 replies; 3+ messages in thread
From: Xiao Liang @ 2025-02-26  6:36 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel

On Wed, Feb 26, 2025 at 4:38 AM Florian Westphal <fw@strlen.de> wrote:
>
> Xiao Liang <shaw.leon@gmail.com> wrote:
> > Since proto_th carries no information about the proto number, we need to
> > preserve the L4 protocol expression.
> >
> > For example, if "meta l4proto 91 @th,0,16 0" is simplified to
> > "th sport 0", the information of protocol number is lost. This patch
> > changes it to "meta l4proto 91 th sport 0".
> >
> > Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
> > ---
> >
> > Technically, if port is not defined for the L4 protocol, it's better to
> > keep "@th,0,16" as raw payload expressions rather than "th sport". But
> > it's not easy to figure out the context.
>
> Yes, this is also because we don't store dependencies like
> 'meta l4proto { tcp, udp }', so we don't have access to this info when
> we see the @th,0,16 load.
>
> What do you make of this (it will display @th syntax for your test case)?

Looks good. I think this can cover most of the use cases. We don't
usually mix protocols when matching L4 header fields other than ports.
Thanks!

>
> diff --git a/src/payload.c b/src/payload.c
> --- a/src/payload.c
> +++ b/src/payload.c
> @@ -851,6 +851,58 @@ static bool payload_may_dependency_kill_ll(struct payload_dep_ctx *ctx, struct e
>         return true;
>  }
>
> +static bool l4proto_has_ports(struct payload_dep_ctx *ctx, struct expr *expr)
> +{
> +       uint8_t v;
> +
> +       assert(expr->etype == EXPR_VALUE);
> +
> +       if (expr->len != 8)
> +               return false;
> +
> +       v = mpz_get_uint8(expr->value);
> +
> +       switch (v) {
> +       case IPPROTO_UDPLITE:
> +       case IPPROTO_UDP:
> +       case IPPROTO_TCP:
> +       case IPPROTO_DCCP:
> +       case IPPROTO_SCTP:
> +               return true;
> +       }
> +
> +       return false;
> +}
> +
> +static bool payload_may_dependency_kill_th(struct payload_dep_ctx *ctx, struct expr *expr)
> +{
> +       struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
> +       enum proto_bases b;
> +
> +       switch (dep->left->etype) {
> +       case EXPR_PAYLOAD:
> +               b = dep->left->payload.base;
> +               break;
> +       case EXPR_META:
> +               b = dep->left->meta.base;
> +               break;
> +       default:
> +               return false;
> +       }
> +
> +       if (b != PROTO_BASE_NETWORK_HDR)
> +               return false;
> +
> +       switch (dep->right->etype) {
> +       case EXPR_VALUE:
> +               return l4proto_has_ports(ctx, dep->right);
> +       default:
> +               break;
> +       }
> +
> +       return false;
> +}
> +
>  static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
>                                         unsigned int family, struct expr *expr)
>  {
> @@ -893,6 +945,15 @@ static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
>         if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
>                 return true;
>
> +       if (expr->payload.desc == &proto_th) {
> +               if (payload_may_dependency_kill_th(ctx, expr))
> +                       return true;
> +
> +               /* prefer @th syntax, we don't have a 'source/destination port' protocol */
> +               expr->payload.desc = &proto_unknown;
> +               return false;
> +       }
> +
>         if (dep->left->etype != EXPR_PAYLOAD ||
>             dep->left->payload.base != PROTO_BASE_TRANSPORT_HDR)
>                 return true;
>
>
> It would make sense to NOT set &proto_th from payload_init_raw(), but
> that would place significant burden on netlink_delinearize to
> pretty-print the typical use case for this, i.e.
>
> 'meta l4proto { tcp, udp } th dport 53 accept'
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-02-26  6:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-25 10:03 [RFC PATCH nft] payload: Don't kill dependency for proto_th Xiao Liang
2025-02-25 20:35 ` Florian Westphal
2025-02-26  6:36   ` Xiao Liang

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.