From: Willy Tarreau Date: Tue, 10 Nov 2026 10:54:56 +0000 (+0100) Subject: MINOR: http-conv: add hdng_rej_name to name the HTTP hardening reject rule X-Git-Tag: v3.5-dev12~2 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=906488861145950778e214caf8aefb7d31c8197e;p=haproxy.git MINOR: http-conv: add hdng_rej_name to name the HTTP hardening reject rule The hdng_rej_name converter takes a mask of HTTP_HRD_* flags such as returned by fs.hdng.fixed or bs.hdng.fixed, keeps only the "reject" rules, and returns the name of the lowest one, as found in http_hardening_kws[]. Since a reject stops the processing, at most one is normally present. Other rules are ignored, and the converter fails when no reject rule remains, so that nothing is logged when nothing was rejected: log-format "... cli_hdng=%[fs.hdng.found,htonl,hex],%[fs.hdng.fixed,hdng_rej_name] ..." --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 8cf9bae07..94d469e56 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -22252,6 +22252,7 @@ field(index,delimiters[,count]) string string fix_is_valid binary boolean fix_tag_value(tag) binary binary has_ctl([mask]) binary boolean +hdng_rej_name integer string hex binary string hex2i binary integer hmac(algorithm,key) binary binary @@ -22897,6 +22898,23 @@ has_ctl([mask]) # reject presence of any control char but tab in any HTTP header value http-request deny if { req.hdr(),has_ctl } +hdng_rej_name + Takes an integer made of HTTP hardening flags such as returned by the + "fs.hdng.fixed" or "bs.hdng.fixed" sample fetches, and returns the name of + the "reject" rule it contains, as shown in section 12.10 (e.g. + "reject-ctl-in-header-trailer"). Other rules (e.g. "delete" ones) are + ignored. Since a rejection stops the processing, at most one "reject" rule + is normally present. Should there be several, the one with the lowest bit + is reported. The converter fails if the input contains no "reject" rule, + which makes it possible to log nothing when nothing was rejected. Note that + it does not make much sense to use it with the ".found" variant of the sample + fetches because multiple bits will often be set. Example: + + log-format "$HAPROXY_HTTP_LOG_FMT cli_hdng=%[fs.hdng.found,htonl,hex],\ + %[fs.hdng.fixed,hdng_rej_name]" + + See also "fs.hdng.fixed", "bs.hdng.fixed". + hex Converts a binary input sample to a hex string containing two hex digits per input byte. It is used to log or transfer hex dumps of some binary input data @@ -27333,9 +27351,12 @@ bs.hdng.fixed : integer "show http-hardening". Note that bit numbers are subject to change between major versions and that new options may occasionally be introduced in minor versions. The sample fetch fails if the server side does not use an HTTP - multiplexer supporting HTTP hardening (H1, H2, H3). Example: + multiplexer supporting HTTP hardening (H1, H2, H3). Since rejects stop the + processing, at most one "reject" rule may appear, which may then be turned + into its name using the "hdng_rej_name" converter. Example: - log-format "$HAPROXY_HTTP_LOG_FMT srv_hdng=%[bs.hdng.found,htonl,hex]" + log-format "$HAPROXY_HTTP_LOG_FMT srv_hdng=%[bs.hdng.found,htonl,hex],\ + %[bs.hdng.fixed,hdng_rej_name]" See also "bs.hdng.found", "fs.hdng.fixed". @@ -27395,7 +27416,8 @@ fs.hdng.fixed : integer only be reported here when the rejection happens later (e.g. on trailers received after the headers). Example: - log-format "$HAPROXY_HTTP_LOG_FMT cli_hdng=%[fs.hdng.found,htonl,hex]" + log-format "$HAPROXY_HTTP_LOG_FMT cli_hdng=%[fs.hdng.found,htonl,hex],\ + %[fs.hdng.fixed,hdng_rej_name]" See also "fs.hdng.found", "bs.hdng.fixed". diff --git a/src/http_conv.c b/src/http_conv.c index b97ce6d6e..0a394a1b3 100644 --- a/src/http_conv.c +++ b/src/http_conv.c @@ -457,6 +457,33 @@ static int smp_conv_res_capture(const struct arg *args, struct sample *smp, void return 1; } +/* Turns an integer made of HTTP_HRD_* flags (e.g. from fs.hdng.fixed) into the + * name of the lowest "reject" rule it contains. Since a reject stops the + * processing, at most one such rule is normally present. Other flags are + * ignored. The converter fails if no reject rule is found. + */ +static int sample_conv_hdng_rej_name(const struct arg *args, struct sample *smp, void *private) +{ + const struct http_hardening_kw *kw; + uint32_t mask = smp->data.u.sint & HTTP_HRD_ALL_REJECT; + + if (!mask) + return 0; + + mask &= -mask; // keep the lowest bit only + for (kw = http_hardening_kws; kw->name; kw++) { + if (kw->mask == mask) { + smp->data.type = SMP_T_STR; + smp->flags |= SMP_F_CONST; + smp->data.u.str.area = (char *)kw->name; + smp->data.u.str.data = strlen(kw->name); + smp->data.u.str.size = 0; + return 1; + } + } + return 0; +} + /************************************************************************/ /* All supported converter keywords must be declared here. */ /************************************************************************/ @@ -465,6 +492,7 @@ static int smp_conv_res_capture(const struct arg *args, struct sample *smp, void static struct sample_conv_kw_list sample_conv_kws = {ILH, { { "http_date", sample_conv_http_date, ARG2(0,SINT,STR), smp_check_http_date_unit, SMP_T_SINT, SMP_T_STR}, { "date", sample_conv_http2epoch, 0, NULL, SMP_T_STR, SMP_T_SINT}, + { "hdng_rej_name", sample_conv_hdng_rej_name,0, NULL, SMP_T_SINT, SMP_T_STR}, { "language", sample_conv_q_preferred, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_T_STR}, { "capture-req", smp_conv_req_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR}, { "capture-res", smp_conv_res_capture, ARG1(1,SINT), NULL, SMP_T_STR, SMP_T_STR},