]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: http: add the "set http-hardening" CLI command
authorWilly Tarreau <w@1wt.eu>
Tue, 27 Oct 2026 16:43:44 +0000 (17:43 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Nov 2026 21:45:32 +0000 (22:45 +0100)
"set http-hardening <name> <option> {on|off}" enables or disables an option
of a profile at runtime, including the "all" keyword to change everything
at once, e.g. in an emergency. Options may also be specified by the bit
number that appears in -dKcfg or in "show http-hardening". The option is
looked up like in the section parser so that a suggestion is made on typos.
The profile is only read by the other threads, so it is updated while the
threads are isolated, which avoids any locking on the fast path. The
command is restricted to the admin level.

doc/management.txt
src/http.c

index b6ae2e1e8772a639ddbecf2c16fecf661a79af07..4520745a1c4425c51b06bdb15cb939018aa094f3 100644 (file)
@@ -2647,6 +2647,19 @@ set anon global-key <key>
   integer between 0 and 4294967295 (0 disables the global key). This command
   requires admin privilege.
 
+set http-hardening <name> { <option> | <number> } { on | off }
+  Enables or disables the hardening option <option> in the http-hardening
+  profile <name>, which may be "untrusted" and "trusted" even if not declared.
+  Alternately, the option may be designated by its <number> which corresponds
+  to the one reported by "show http-hardening". The special option "all"
+  changes all options at once, which may be used to quickly relax or restore
+  everything in an emergency. The change applies to all connections and servers
+  using this profile and is not persistent: it is lost on reload, so the
+  configuration must be updated as well. The profile being only updated while
+  all threads are isolated, this command may momentarily delay processing. This
+  command requires the admin level. See also "show http-hardening" and section
+  12.10 of the configuration manual.
+
 set map <map> [<key>|#<ref>] <value>
   Modify the value corresponding to each key <key> in a map <map>. <map> is the
   #<id> or <name> returned by "show map". If the <ref> is used in place of
index c3d2502bae1a4e306aa59b3a7668b134a35b0475..8cf380a358628d6da314282a95addfcef3c31fef 100644 (file)
@@ -2123,9 +2123,72 @@ static int cli_io_handler_show_http_hardening(struct appctx *appctx)
        return 1;
 }
 
+/* parses "set http-hardening <name> <option> {on|off}": changes an option of
+ * a profile. The profile is only read by the other threads, which are isolated
+ * during the update so that no lock is needed to read it.
+ */
+static int cli_parse_set_http_hardening(char **args, char *payload, struct appctx *appctx, void *trusted)
+{
+       struct http_hdng_prf *prf;
+       char *msg = NULL;
+       size_t idx = 0;
+       int match;
+       int v, on;
+
+       if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+               return 1;
+
+       if (!*args[2] || !*args[3] || !*args[4] || *args[5])
+               return cli_err(appctx, "Usage: set http-hardening <name> <option> {on|off}\n");
+
+       prf = http_hardening_lookup(args[2]);
+       if (!prf)
+               return cli_err(appctx, "Unknown http-hardening profile.\n");
+
+       v = atoi(args[3]);
+       match = 0;
+       if (v > 0 && v <= 8 * sizeof(http_hardening_kws[0].mask)) {
+               /* numeric entry found, corresponds to bit position starting at 1 */
+               for (idx = 0; idx < sizeof(http_hardening_kws) / sizeof(http_hardening_kws[0]); idx++) {
+                       if (1U << (v - 1) == http_hardening_kws[idx].mask) {
+                               /* found at [idx] */
+                               match = 2;
+                               break;
+                       }
+               }
+
+       }
+
+       if (match != 2)
+               match = find_word_index_in_array(http_hardening_kws, sizeof(http_hardening_kws[0]), -1,
+                                                offsetof(struct http_hardening_kw, name), args[3], &idx);
+       if (match != 2) {
+               if (match == 1) {
+                       memprintf(&msg, "Unknown http-hardening option. Maybe you meant '%s' ?\n",
+                                 http_hardening_kws[idx].name);
+                       return cli_dynerr(appctx, msg);
+               }
+               return cli_err(appctx, "Unknown http-hardening option.\n");
+       }
+
+       on = strcmp(args[4], "on") == 0;
+       if (!on && strcmp(args[4], "off") != 0)
+               return cli_err(appctx, "Expects 'on' or 'off'.\n");
+
+       thread_isolate();
+       if (on)
+               prf->mask |= http_hardening_kws[idx].mask;
+       else
+               prf->mask &= ~http_hardening_kws[idx].mask;
+       thread_release();
+       return 1;
+}
+
 static struct cli_kw_list http_hardening_cli_kws = {{ }, {
        { { "show", "http-hardening", NULL }, "show http-hardening [name]              : lists the profiles, or dumps one of them's rules",
          cli_parse_show_http_hardening, cli_io_handler_show_http_hardening },
+       { { "set", "http-hardening", NULL }, "set http-hardening <name> <opt> on|off : enable or disable an option of a profile",
+         cli_parse_set_http_hardening },
        {{},}
 }};