]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: tcp-rules: ignore "capture len" rules evaluated from a backend
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 23 Sep 2026 04:34:25 +0000 (04:34 +0000)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 23 Sep 2026 12:05:25 +0000 (14:05 +0200)
This is the same issue as the one fixed for "http-request capture" by the
previous commit. A "tcp-request content capture <expr> len <n>" rule is
accepted in a "listen" section, and creates a capture slot numbered in this
section. When the section is also used as the backend of another frontend,
the rule writes into the slot array of the stream, which is the one of the
frontend: NULL if the frontend has no capture, which crashes the process on
the first request, or a slot belonging to the frontend, allocated from one
pool and later released to another.

The rule is now ignored when the proxy evaluating it is not the stream's
frontend. The reg-test added by the previous commit is extended with the
same three cases for the tcp-request rule.

This must be backported to all supported versions.

reg-tests/http-rules/capture_len_listen_as_backend.vtc
src/tcp_rules.c

index 3849daeb3e855e0c65d439d8ff591cc4a130634b..e8dc81e5ca2ab56a86de75c2517854763864d504 100644 (file)
@@ -12,6 +12,8 @@ varnishtest "capture with a length in a listen section also used as a backend"
 #   - reached from a frontend which has no capture at all;
 #   - reached from a frontend which has its own capture, which must be
 #     left untouched.
+# They are run for an "http-request capture" and for a "tcp-request content
+# capture" rule.
 
 feature ignore_unknown_macro
 
@@ -35,6 +37,21 @@ haproxy h1 -conf {
         bind "fd@${lst}"
         http-request capture req.hdr(x-b) len 40
         http-request return status 200 hdr cap0 "%[capture.req.hdr(0)]"
+
+    frontend fe_tcp_nocap
+        bind "fd@${fe_tcp_nocap}"
+        use_backend lst_tcp
+
+    frontend fe_tcp_cap
+        bind "fd@${fe_tcp_cap}"
+        capture request header x-a len 1
+        use_backend lst_tcp
+
+    listen lst_tcp
+        bind "fd@${lst_tcp}"
+        tcp-request inspect-delay 1s
+        tcp-request content capture req.hdr(x-b) len 40
+        http-request return status 200 hdr cap0 "%[capture.req.hdr(0)]"
 } -start
 
 client c1 -connect ${h1_lst_sock} {
@@ -57,3 +74,24 @@ client c3 -connect ${h1_fe_cap_sock} {
     expect resp.status == 200
     expect resp.http.cap0 == "A"
 } -run
+
+client c4 -connect ${h1_lst_tcp_sock} {
+    txreq -hdr "x-b: hello"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.cap0 == "hello"
+} -run
+
+client c5 -connect ${h1_fe_tcp_nocap_sock} {
+    txreq -hdr "x-b: hello"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.cap0 == "<undef>"
+} -run
+
+client c6 -connect ${h1_fe_tcp_cap_sock} {
+    txreq -hdr "x-a: A" -hdr "x-b: hello"
+    rxresp
+    expect resp.status == 200
+    expect resp.http.cap0 == "A"
+} -run
index 3c2772f2e69c8a60bbf0451f293ea52613eaf8a9..620763ece6238df5e3f25907ec5c4f0bfd197692 100644 (file)
@@ -840,6 +840,14 @@ static enum act_return tcp_action_capture(struct act_rule *rule, struct proxy *p
        char **cap = s->req_cap;
        int len, opt;
 
+       /* The capture slot was declared in the proxy holding the rule, but the
+        * slots of the stream are those of its frontend. When the rule is
+        * evaluated from a listen section used as a backend, the slot does not
+        * exist, so the rule is ignored.
+        */
+       if (px != strm_fe(s))
+               goto end;
+
        opt = ((rule->from == ACT_F_TCP_REQ_CNT) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
        if (flags & ACT_FLAG_FINAL)
                opt |= SMP_OPT_FINAL;