chiark / gitweb /
microhttp-util: rework gnutls logging
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 29 Mar 2014 15:58:11 +0000 (11:58 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 16 Jul 2014 02:23:47 +0000 (22:23 -0400)
src/journal/journal-gatewayd.c
src/journal/journal-remote.c
src/journal/microhttpd-util.c
src/journal/microhttpd-util.h

index c682666a22c72a7542fe4a37e9230576c816d62a..db07700111410be2f46bf55ee615d392ab262406 100644 (file)
@@ -989,7 +989,7 @@ int main(int argc, char *argv[]) {
 
 #ifdef HAVE_GNUTLS
         gnutls_global_set_log_function(log_func_gnutls);
-        gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
+        log_reset_gnutls_level();
 #endif
 
         n = sd_listen_fds(1);
index a31dc2c9801137ff44457aa1505319323e9bf579..9db4692a28b3d8585a761eb6d1df3021eb9f8691 100644 (file)
@@ -63,6 +63,7 @@ static char** arg_files = NULL;
 static int arg_compress = true;
 static int arg_seal = false;
 static int http_socket = -1, https_socket = -1;
+static char** arg_gnutls_log = NULL;
 
 static char *key_pem = NULL;
 static char *cert_pem = NULL;
@@ -969,6 +970,11 @@ static int help(void) {
                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
                "  --[no-]compress      Use XZ-compression in the output journal (default: yes)\n"
                "  --[no-]seal          Use Event sealing in the output journal (default: no)\n"
+               "  --key=FILENAME       Specify key in PEM format\n"
+               "  --cert=FILENAME      Specify certificate in PEM format\n"
+               "  --trust=FILENAME     Specify CA certificate in PEM format\n"
+               "  --gnutls-log=CATEGORY...\n"
+               "                       Specify a list of gnutls logging categories\n"
                "  -h --help            Show this help and exit\n"
                "  --version            Print version string and exit\n"
                "\n"
@@ -993,6 +999,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_KEY,
                 ARG_CERT,
                 ARG_TRUST,
+                ARG_GNUTLS_LOG,
         };
 
         static const struct option options[] = {
@@ -1011,6 +1018,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "key",          required_argument, NULL, ARG_KEY          },
                 { "cert",         required_argument, NULL, ARG_CERT         },
                 { "trust",        required_argument, NULL, ARG_TRUST        },
+                { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
                 {}
         };
 
@@ -1136,6 +1144,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 #else
                         log_error("Option --trust is not available.");
+                        return -EINVAL;
 #endif
 
                 case 'o':
@@ -1160,6 +1169,28 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_seal = false;
                         break;
 
+                case ARG_GNUTLS_LOG: {
+#ifdef HAVE_GNUTLS
+                        char *word, *state;
+                        size_t size;
+
+                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+                                char *cat;
+
+                                cat = strndup(word, size);
+                                if (!cat)
+                                        return log_oom();
+
+                                if (strv_consume(&arg_gnutls_log, cat) < 0)
+                                        return log_oom();
+                        }
+                        break;
+#else
+                        log_error("Option --gnutls-log is not available.");
+                        return -EINVAL;
+#endif
+                }
+
                 case '?':
                         return -EINVAL;
 
@@ -1179,13 +1210,26 @@ static int parse_argv(int argc, char *argv[]) {
         return 1 /* work to do */;
 }
 
-static int setup_gnutls_logger(void) {
+static int setup_gnutls_logger(char **categories) {
         if (!arg_listen_http && !arg_listen_https)
                 return 0;
 
 #ifdef HAVE_GNUTLS
-        gnutls_global_set_log_function(log_func_gnutls);
-        gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
+        {
+                char **cat;
+                int r;
+
+                gnutls_global_set_log_function(log_func_gnutls);
+
+                if (categories)
+                        STRV_FOREACH(cat, categories) {
+                                r = log_enable_gnutls_category(*cat);
+                                if (r < 0)
+                                        return r;
+                        }
+                else
+                        log_reset_gnutls_level();
+        }
 #endif
 
         return 0;
@@ -1203,7 +1247,7 @@ int main(int argc, char **argv) {
         if (r <= 0)
                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 
-        r = setup_gnutls_logger();
+        r = setup_gnutls_logger(arg_gnutls_log);
         if (r < 0)
                 return EXIT_FAILURE;
 
index 007cb5dfdc6903510be9201cd13d051bab18ad90..d0466867b7768377a6404bc7699071bf082a3c0f 100644 (file)
@@ -28,6 +28,7 @@
 #include "log.h"
 #include "macro.h"
 #include "util.h"
+#include "strv.h"
 
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
@@ -103,35 +104,64 @@ int mhd_respondf(struct MHD_Connection *connection,
 
 #ifdef HAVE_GNUTLS
 
-static int log_level_map[] = {
-        LOG_DEBUG,
-        LOG_WARNING, /* gnutls session audit */
-        LOG_DEBUG,   /* gnutls debug log */
-        LOG_WARNING, /* gnutls assert log */
-        LOG_INFO,    /* gnutls handshake log */
-        LOG_DEBUG,   /* gnutls record log */
-        LOG_DEBUG,   /* gnutls dtls log */
-        LOG_DEBUG,
-        LOG_DEBUG,
-        LOG_DEBUG,
-        LOG_DEBUG,   /* gnutls hard log */
-        LOG_DEBUG,   /* gnutls read log */
-        LOG_DEBUG,   /* gnutls write log */
-        LOG_DEBUG,   /* gnutls io log */
-        LOG_DEBUG,   /* gnutls buffers log */
+static struct {
+        const char *const names[4];
+        int level;
+        bool enabled;
+} gnutls_log_map[] = {
+        { {"0"},                  LOG_DEBUG },
+        { {"1", "audit"},         LOG_WARNING, true}, /* gnutls session audit */
+        { {"2", "assert"},        LOG_DEBUG },        /* gnutls assert log */
+        { {"3", "hsk", "ext"},    LOG_DEBUG },        /* gnutls handshake log */
+        { {"4", "rec"},           LOG_DEBUG },        /* gnutls record log */
+        { {"5", "dtls"},          LOG_DEBUG },        /* gnutls DTLS log */
+        { {"6", "buf"},           LOG_DEBUG },
+        { {"7", "write", "read"}, LOG_DEBUG },
+        { {"8"},                  LOG_DEBUG },
+        { {"9", "enc", "int"},    LOG_DEBUG },
 };
 
 void log_func_gnutls(int level, const char *message) {
-        int ourlevel;
-
         assert_se(message);
 
-        if (0 <= level && level < (int) ELEMENTSOF(log_level_map))
-                ourlevel = log_level_map[level];
-        else
-                ourlevel = LOG_DEBUG;
+        if (0 <= level && level < (int) ELEMENTSOF(gnutls_log_map)) {
+                if (gnutls_log_map[level].enabled)
+                        log_meta(gnutls_log_map[level].level, NULL, 0, NULL,
+                                 "gnutls %d/%s: %s", level, gnutls_log_map[level].names[1], message);
+        } else {
+                log_debug("Received GNUTLS message with unknown level %d.", level);
+                log_meta(LOG_DEBUG, NULL, 0, NULL, "gnutls: %s", message);
+        }
+}
+
+int log_enable_gnutls_category(const char *cat) {
+        unsigned i;
+
+        if (streq(cat, "all")) {
+                for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++)
+                        gnutls_log_map[i].enabled = true;
+                log_reset_gnutls_level();
+                return 0;
+        } else
+                for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++)
+                        if (strv_contains((char**)gnutls_log_map[i].names, cat)) {
+                                gnutls_log_map[i].enabled = true;
+                                log_reset_gnutls_level();
+                                return 0;
+                        }
+        log_error("No such log category: %s", cat);
+        return -EINVAL;
+}
+
+void log_reset_gnutls_level(void) {
+        int i;
 
-        log_meta(ourlevel, NULL, 0, NULL, "gnutls: %s", message);
+        for (i = ELEMENTSOF(gnutls_log_map) - 1; i >= 0; i--)
+                if (gnutls_log_map[i].enabled) {
+                        log_debug("Setting gnutls log level to %d", i);
+                        gnutls_global_set_log_level(i);
+                        break;
+                }
 }
 
 static int verify_cert_authorized(gnutls_session_t session) {
index df4d003eb95eaf943c34d54c741a2d48118fa872..4186da888e12fa083bf78343f0aaa19dcd484743 100644 (file)
@@ -45,10 +45,11 @@ int check_permissions(struct MHD_Connection *connection, int *code);
 
 #ifdef HAVE_GNUTLS
 void log_func_gnutls(int level, const char *message);
+int log_enable_gnutls_category(const char *cat);
+void log_reset_gnutls_level(void);
 
 /* This is additionally filtered by our internal log level, so it
  * should be set fairly high to capture all potentially interesting
  * events without overwhelming detail.
  */
-#define GNUTLS_LOG_LEVEL 6
 #endif