From: Christopher Faulet Date: Wed, 23 Sep 2026 04:34:25 +0000 (+0000) Subject: BUG/MEDIUM: tcp-rules: ignore "capture len" rules evaluated from a backend X-Git-Tag: v3.5-dev8~127 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=2b8598b46df10e99196061f2866ec97ac56aa75b;p=haproxy.git BUG/MEDIUM: tcp-rules: ignore "capture len" rules evaluated from a backend This is the same issue as the one fixed for "http-request capture" by the previous commit. A "tcp-request content capture len " 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. --- diff --git a/reg-tests/http-rules/capture_len_listen_as_backend.vtc b/reg-tests/http-rules/capture_len_listen_as_backend.vtc index 3849daeb3..e8dc81e5c 100644 --- a/reg-tests/http-rules/capture_len_listen_as_backend.vtc +++ b/reg-tests/http-rules/capture_len_listen_as_backend.vtc @@ -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 == "" +} -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 diff --git a/src/tcp_rules.c b/src/tcp_rules.c index 3c2772f2e..620763ece 100644 --- a/src/tcp_rules.c +++ b/src/tcp_rules.c @@ -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;