]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: config: add command-line -dC to dump the configuration file
authorErwan Le Goas <elegoas@haproxy.com>
Wed, 14 Sep 2022 15:51:55 +0000 (17:51 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 17 Sep 2022 09:27:09 +0000 (11:27 +0200)
This commit adds a new command line option -dC to dump the configuration
file. An optional key may be appended to -dC in order to produce an
anonymized dump using this key. The anonymizing process uses the same
algorithm as the CLI so that the same key will produce the same hashes
for the same identifiers. This way an admin may share an anonymized
extract of a configuration to match against live dumps. Note that key 0
will not anonymize the output. However, in any case, the configuration
is dumped after tokenizing, thus comments are lost.

doc/configuration.txt
doc/management.txt
include/haproxy/global-t.h
src/cfgparse.c
src/haproxy.c

index bc4c622da47bcaefb4d902d747f9a1c6b3b4f6bd..6af5e4e97c541d450315bb8b7e8a8a26a06814ae 100644 (file)
@@ -3226,7 +3226,8 @@ anonkey <key>
   This sets the global anonymizing key to <key>, which must be a 32-bit number
   between 0 and 4294967295. This is the key that will be used by default by CLI
   commands when anonymized mode is enabled. This key may also be set at runtime
-  from the CLI command "set global-key".
+  from the CLI command "set global-key". See also command line argument "-dC"
+  in the management manual.
 
 quiet
   Do not display any message during startup. It is equivalent to the command-
index 9e908a6168487973425cec733ef5e5cbd9a1dbe5..30209df9062a000862af533441eb6304ff07a689 100644 (file)
@@ -204,6 +204,15 @@ list of options is :
     in foreground and to show incoming and outgoing events. It must never be
     used in an init script.
 
+  -dC[key] : dump the configuration file. It is performed after the lines are
+    tokenized, so comments are stripped and indenting is forced. If a non-zero
+    key is specified, lines are truncated before sensitive/confidential fields,
+    and identifiers and addresses are emitted hashed with this key using the
+    same algorithmm as the one used by the anonymized mode on the CLI. This
+    means that the output may safely be shared with a developer who needs it
+    to figure what's happening in a dump that was anonymized using the same
+    key. Please also see the CLI's "set anon" command.
+
   -dD : enable diagnostic mode. This mode will output extra warnings about
     suspicious configuration statements. This will never prevent startup even in
     "zero-warning" mode nor change the exit status code.
index 99b6acc74990b30e54a0a191ae4dc4eb3e9b2016..f10146e4900cbef00d54c5a1d661c9cbc3c4505a 100644 (file)
@@ -42,6 +42,7 @@
 #define        MODE_STOPPING   0x1000  /* the process is in the deinit phase, the event loop is not running anymore. */
 #define        MODE_DUMP_LIBS  0x2000  /* dump loaded libraries at the end of init phase */
 #define        MODE_DUMP_KWD   0x4000  /* dump registered keywords (see kwd_dump for the list) */
+#define        MODE_DUMP_CFG   0x8000 /* dump the configure file */
 
 /* list of last checks to perform, depending on config options */
 #define LSTCHK_CAP_BIND        0x00000001      /* check that we can bind to any port */
index 171982c0bb0c14a0e404d79c2f4f22c04ab312e3..352953fb76b5bfcfcaa5e9fb001dc1feabcdd375 100644 (file)
@@ -1893,6 +1893,219 @@ next_line:
                        break;
                }
 
+               /* dump cfg */
+               if (global.mode & MODE_DUMP_CFG) {
+                       if (args[0] != NULL) {
+                               struct cfg_section *sect;
+                               int is_sect = 0;
+                               int i = 0;
+                               uint32_t g_key = HA_ATOMIC_LOAD(&global.anon_key);
+
+                               qfprintf(stdout, "%d\t", linenum);
+
+                               /* if a word is in sections list, is_sect = 1 */
+                               list_for_each_entry(sect, &sections, list) {
+                                       if (strcmp(args[0], sect->section_name) == 0) {
+                                               is_sect = 1;
+                                               break;
+                                       }
+                               }
+
+                               if (g_key == 0) {
+                                       /* no anonymizing needed, dump the config as-is (but without comments).
+                                        * Note: tabs were lost during tokenizing, so we reinsert for non-section
+                                        * keywords.
+                                        */
+                                       if (!is_sect)
+                                               qfprintf(stdout, "\t");
+
+                                       for (i = 0; i < arg; i++) {
+                                               qfprintf(stdout, "%s ", args[i]);
+                                       }
+                                       qfprintf(stdout, "\n");
+                                       continue;
+                               }
+
+                               /* We're anonymizing */
+
+                               if (is_sect) {
+                                       /* new sections are optionally followed by an identifier */
+                                       if (arg >= 2) {
+                                               qfprintf(stdout, "%s %s\n", args[0], HA_ANON_ID(g_key, args[1]));
+                                       }
+                                       else {
+                                               qfprintf(stdout, "%s\n", args[0]);
+                                       }
+                                       continue;
+                               }
+
+                               /* non-section keywords start indented */
+                               qfprintf(stdout, "\t");
+
+                               /* some keywords deserve special treatment */
+                               if (!*args[0]) {
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "anonkey") == 0) {
+                                       qfprintf(stdout, "%s [...]\n", args[0]);
+                               }
+
+                               else if (strcmp(args[0], "maxconn") == 0) {
+                                       qfprintf(stdout, "%s %s\n", args[0], args[1]);
+                               }
+
+                               else if (strcmp(args[0], "stats") == 0 &&
+                                        (strcmp(args[1], "timeout") == 0 || strcmp(args[1], "maxconn") == 0)) {
+                                       qfprintf(stdout, "%s %s %s\n", args[0], args[1], args[2]);
+                               }
+
+                               else if (strcmp(args[0], "stats") == 0 && strcmp(args[1], "socket") == 0) {
+                                       qfprintf(stdout, "%s %s ", args[0], args[1]);
+
+                                       if (arg > 1) {
+                                               qfprintf(stdout, "%s ", args[2]);
+
+                                               if (arg > 2) {
+                                                       qfprintf(stdout, "[...]\n");
+                                               }
+                                               else {
+                                                       qfprintf(stdout, "\n");
+                                               }
+                                       }
+                                       else {
+                                               qfprintf(stdout, "\n");
+                                       }
+                               }
+
+                               else if (strcmp(args[0], "timeout") == 0) {
+                                       qfprintf(stdout, "%s %s %s\n", args[0], args[1], args[2]);
+                               }
+
+                               else if (strcmp(args[0], "mode") == 0) {
+                                       qfprintf(stdout, "%s %s\n", args[0], args[1]);
+                               }
+
+                               /* It concerns user in global secion and in userlist */
+                               else if (strcmp(args[0], "user") == 0) {
+                                       qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
+
+                                       if (arg > 2) {
+                                               qfprintf(stdout, "[...]\n");
+                                       }
+                                       else {
+                                               qfprintf(stdout, "\n");
+                                       }
+                               }
+
+                               else if (strcmp(args[0], "bind") == 0) {
+                                       qfprintf(stdout, "%s ", args[0]);
+                                       qfprintf(stdout, "%s ", hash_ipanon(g_key, args[1]));
+                                       if (arg > 2) {
+                                               qfprintf(stdout, "[...]\n");
+                                       }
+                                       else {
+                                               qfprintf(stdout, "\n");
+                                       }
+                               }
+
+                               else if (strcmp(args[0], "server") == 0) {
+                                       qfprintf(stdout, "%s ", args[0]);
+
+                                       if (strcmp(args[1], "localhost") == 0) {
+                                               qfprintf(stdout, "%s ", args[1]);
+                                       }
+                                       else {
+                                               qfprintf(stdout, "%s ", HA_ANON_ID(g_key, args[1]));
+                                       }
+                                       if (arg > 2) {
+                                               qfprintf(stdout, "%s ", hash_ipanon(g_key, args[2]));
+                                       }
+                                       if (arg > 3) {
+                                               qfprintf(stdout, "[...]\n");
+                                       }
+                                       else {
+                                               qfprintf(stdout, "\n");
+                                       }
+                               }
+
+                               else if (strcmp(args[0], "redirect") == 0) {
+                                       qfprintf(stdout, "%s %s ", args[0], args[1]);
+
+                                       if (strcmp(args[1], "prefix") == 0 || strcmp(args[1], "location") == 0) {
+                                               qfprintf(stdout, "%s ", HA_ANON_PATH(g_key, args[2]));
+                                       }
+                                       else {
+                                               qfprintf(stdout, "%s ", args[2]);
+                                       }
+                                       if (arg > 3) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "acl") == 0) {
+                                       qfprintf(stdout, "%s %s %s ", args[0], HA_ANON_ID(g_key, args[1]), args[2]);
+
+                                       if (arg > 3) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "log") == 0) {
+                                       qfprintf(stdout, "log ");
+
+                                       if (strcmp(args[1], "global") == 0) {
+                                               qfprintf(stdout, "%s ", args[1]);
+                                       }
+                                       else {
+                                               qfprintf(stdout, "%s ", hash_ipanon(g_key, args[1]));
+                                       }
+                                       if (arg > 2) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "peer") == 0) {
+                                       qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
+                                       qfprintf(stdout, "%s ", hash_ipanon(g_key, args[2]));
+
+                                       if (arg > 3) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "use_backend") == 0) {
+                                       qfprintf(stdout, "%s %s ", args[0], HA_ANON_ID(g_key, args[1]));
+
+                                       if (arg > 2) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+
+                               else if (strcmp(args[0], "default_backend") == 0) {
+                                       qfprintf(stdout, "%s %s\n", args[0], HA_ANON_ID(g_key, args[1]));
+                               }
+
+                               else {
+                                       /* display up to 3 words and mask the rest which might be confidential */
+                                       for (i = 0; i < MIN(arg, 3); i++) {
+                                               qfprintf(stdout, "%s ", args[i]);
+                                       }
+                                       if (arg > 3) {
+                                               qfprintf(stdout, "[...]");
+                                       }
+                                       qfprintf(stdout, "\n");
+                               }
+                       }
+                       continue;
+               }
+               /* end of config dump */
+
                /* empty line */
                if (!**args)
                        continue;
index 8d6f5876650746ccf060b36e33ff057aed379f81..ae2f5ebf30088319d3fd0ec89a2e2fb07b1cf393 100644 (file)
@@ -590,6 +590,7 @@ static void usage(char *name)
                "        -N sets the default, per-proxy maximum # of connections (%d)\n"
                "        -L set local peer name (default to hostname)\n"
                "        -p writes pids of all children to this file\n"
+               "        -dC[key] display the configure file, if there is a key, the file will be anonymise\n"
 #if defined(USE_EPOLL)
                "        -de disables epoll() usage even when available\n"
 #endif
@@ -1633,6 +1634,10 @@ static void init_args(int argc, char **argv)
                                global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
                        else if (*flag == 'V')
                                arg_mode |= MODE_VERBOSE;
+                       else if (*flag == 'd' && flag[1] == 'C') {
+                               arg_mode |= MODE_DUMP_CFG;
+                               HA_ATOMIC_STORE(&global.anon_key, atoll(flag + 2));
+                       }
                        else if (*flag == 'd' && flag[1] == 'b')
                                arg_mode |= MODE_FOREGROUND;
                        else if (*flag == 'd' && flag[1] == 'D')
@@ -1904,7 +1909,7 @@ static void init(int argc, char **argv)
 
        global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
                                    | MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
-                                   | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD));
+                                   | MODE_DIAG | MODE_CHECK_CONDITION | MODE_DUMP_LIBS | MODE_DUMP_KWD | MODE_DUMP_CFG));
 
        if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
                unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
@@ -2226,6 +2231,9 @@ static void init(int argc, char **argv)
                exit(2);
        }
 
+       if (global.mode & MODE_DUMP_CFG)
+               deinit_and_exit(0);
+
        if (global.mode & MODE_DIAG) {
                cfg_run_diagnostics();
        }