]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http-conv: add hdng_rej_name to name the HTTP hardening reject rule
authorWilly Tarreau <w@1wt.eu>
Tue, 10 Nov 2026 10:54:56 +0000 (11:54 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 12 Nov 2026 17:12:23 +0000 (18:12 +0100)
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] ..."

doc/configuration.txt
src/http_conv.c

index 8cf9bae07538ce611b612318938d827b3375a929..94d469e569bdad5f4074ceba044c4c3d6257603e 100644 (file)
@@ -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".
 
index b97ce6d6eeb6ccd576234326dcefe6eeb08ce7db..0a394a1b3532b0e91395ba7a233b2928f823cc24 100644 (file)
@@ -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},