]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http-fetch: add {fs,bs}.hdng.{found,fixed} to report hardening results
authorWilly Tarreau <w@1wt.eu>
Tue, 10 Nov 2026 10:41:32 +0000 (11:41 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 12 Nov 2026 17:12:23 +0000 (18:12 +0100)
These new sample fetches return, for the frontend or backend mux stream,
the mask of HTTP hardening conditions that were met (found) and of the
rules that were enforced (fixed). They rely on the new mux stream controls
MUX_SCTL_GET_HDNG_FOUND and MUX_SCTL_GET_HDNG_FIXED, and fail when the mux
doesn't support them. The main purpose is to log them, e.g.:

    log-format "... cli_hdng=%[fs.hdng.found,htonl,hex] ..."

Note that a request rejected before the stream is created cannot be
reported this way since it is handled and logged by the mux alone.

The doc also mentions that the bit numbers are subject to change.

doc/configuration.txt
src/http_fetch.c

index 65a8afd5c5cd9ce5870a209cdb8bac246880bd58..8cf9bae07538ce611b612318938d827b3375a929 100644 (file)
@@ -27164,10 +27164,14 @@ Summary of sample fetch methods in this section and their respective types:
 51d.all(<prop>[,<prop>*])                          string
 bs.aborted                                         boolean
 bs.debug_str([<bitmap>])                           string
+bs.hdng.fixed                                      integer
+bs.hdng.found                                      integer
 bs.id                                              integer
 bs.rst_code                                        integer
 fs.aborted                                         boolean
 fs.debug_str([<bitmap>])                           string
+fs.hdng.fixed                                      integer
+fs.hdng.found                                      integer
 fs.id                                              integer
 fs.rst_code                                        integer
 ssl_bc                                             boolean
@@ -27318,7 +27322,33 @@ bs.debug_str([<bitmap>]) : string
   typical use case is to concatenate these information at the very end of a
   log-format, along with fs.debug_str(). Example:
 
-     log-format "$HAPROXY_HTTP_LOG_FMT fs=<%[fs.debug_str]> bs=<%[bs.debug_str]>"
+     log-format "$HAPROXY_HTTP_LOG_FMT \
+                 fs=<%[fs.debug_str]> bs=<%[bs.debug_str]>"
+
+bs.hdng.fixed : integer
+  Returns the mask of the HTTP hardening rules that were enforced on the
+  traffic received from the server for the current stream, i.e. the elements
+  that were rejected or deleted (see section 12.10). Each rule is designated
+  by one bit, whose position starting at 1 is reported by "haproxy -dKcfg" and
+  "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:
+
+     log-format "$HAPROXY_HTTP_LOG_FMT srv_hdng=%[bs.hdng.found,htonl,hex]"
+
+  See also "bs.hdng.found", "fs.hdng.fixed".
+
+bs.hdng.found : integer
+  Returns the mask of the HTTP hardening conditions that were met on the
+  traffic received from the server for the current stream, regardless of
+  whether the corresponding rules were enabled or not (see section 12.10).
+  This allows to figure what would be blocked or modified before enabling a
+  rule. The bits are the same as for "bs.hdng.fixed". 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). See also "bs.hdng.fixed", "fs.hdng.found".
 
 bs.id : integer
   Returns the multiplexer's stream ID on the server side. It is the
@@ -27356,6 +27386,26 @@ fs.debug_str([<bitmap>]) : string
 
      log-format "$HAPROXY_HTTP_LOG_FMT fs=<%[fs.debug_str]> bs=<%[bs.debug_str]>"
 
+fs.hdng.fixed : integer
+  Returns the mask of the HTTP hardening rules that were enforced on the
+  traffic received from the client for the current stream. This is the same as
+  "bs.hdng.fixed" but for the client side. Note that a request rejected before
+  the stream is created (e.g. on its headers, or on trailers received at the
+  same time) is handled and logged by the multiplexer alone, so that it can
+  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]"
+
+  See also "fs.hdng.found", "bs.hdng.fixed".
+
+fs.hdng.found : integer
+  Returns the mask of the HTTP hardening conditions that were met on the
+  traffic received from the client for the current stream, regardless of
+  whether the corresponding rules were enabled or not. This is the same as
+  "bs.hdng.found" but for the client side. See also "fs.hdng.fixed",
+  "bs.hdng.found".
+
 fs.id : integer
   Returns the multiplexer's stream ID on the client side. It is the
   multiplexer's responsibility to return the appropriate information. For
index 1bd17110ded82f283a136365954f02ec2c25612c..ff50504ae976d68f05f0cfeb78f29ac9bf6dc8c1 100644 (file)
@@ -2340,6 +2340,44 @@ int val_query(struct arg *args, char **err_msg)
        return 1;
 
 }
+/* Returns the HTTP hardening conditions met ("found") or rules enforced
+ * ("fixed") on the frontend ("fs.") or backend ("bs.") mux stream, as a mask
+ * of HTTP_HRD_* flags. The sample fetch fails if the mux doesn't support HTTP
+ * hardening.
+ */
+static int smp_fetch_hdng(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+       enum mux_sctl_type sctl;
+       struct connection *conn;
+       struct stconn *sc;
+       uint32_t mask = 0;
+
+       if (!smp->strm)
+               return 0;
+
+       /* kw is either "{f,b}s.hdng.found" or "{f,b}s.hdng.fixed" */
+       sctl = (kw[9] == 'o') ? MUX_SCTL_GET_HDNG_FOUND : MUX_SCTL_GET_HDNG_FIXED;
+       sc = (kw[0] == 'f' ? smp->strm->scf : smp->strm->scb);
+       conn = sc_conn(sc);
+
+       if (!conn)
+               return 0;
+
+       /* a missing mux is necessarily on the backend, and may arrive later */
+       if (!conn->mux) {
+               smp->flags |= SMP_F_MAY_CHANGE;
+               return 0;
+       }
+
+       if (!conn->mux->sctl || conn->mux->sctl(sc, sctl, &mask) == -1)
+               return 0;
+
+       smp->flags = SMP_F_VOL_TEST;
+       smp->data.type = SMP_T_SINT;
+       smp->data.u.sint = mask;
+       return 1;
+}
+
 /************************************************************************/
 /*      All supported sample fetch keywords must be declared here.      */
 /************************************************************************/
@@ -2351,6 +2389,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "base32+src",         smp_fetch_base32_src,         0,                NULL,   SMP_T_BIN,  SMP_USE_HRQHV | SMP_USE__MAY_ALIAS },
        { "baseq",              smp_fetch_base,               0,                NULL,   SMP_T_STR,  SMP_USE_HRQHV | SMP_USE__MAY_ALIAS },
 
+       { "bs.hdng.fixed",      smp_fetch_hdng,               0,                NULL,   SMP_T_SINT, SMP_USE_L5SRV },
+       { "bs.hdng.found",      smp_fetch_hdng,               0,                NULL,   SMP_T_SINT, SMP_USE_L5SRV },
+
        /* capture are allocated and are permanent in the stream */
        { "capture.req.hdr",    smp_fetch_capture_req_hdr,    ARG1(1,SINT),     val_cap_id, SMP_T_STR,  SMP_USE_HRQHP },
 
@@ -2371,6 +2412,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
        { "cook_cnt",           smp_fetch_cookie_cnt,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
        { "cook_val",           smp_fetch_cookie_val,         ARG1(0,STR),      NULL,    SMP_T_SINT, SMP_USE_HRQHV },
 
+       { "fs.hdng.fixed",      smp_fetch_hdng,               0,                NULL,    SMP_T_SINT, SMP_USE_L5CLI },
+       { "fs.hdng.found",      smp_fetch_hdng,               0,                NULL,    SMP_T_SINT, SMP_USE_L5CLI },
+
        /* hdr is valid in both directions (eg: for "stick ...") but hdr_* are
         * only here to match the ACL's name, are request-only and are used for
         * ACL compatibility only.