From 52627a18288ba460387444d8c2f0fa2477b1a286 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Sat, 15 Feb 2020 19:05:37 +0000 Subject: [PATCH] [Fix] Support listening on systemd sockets by name * Add support for looking up sockets by the systemd socket name, e.g. `systemd:rspamd-proxy.socket` or the name from `FileDescriptorName`. https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html * Replace EOVERFLOW error code to avoid confusing error messages. Fixes: #2035 --- src/libserver/cfg_utils.c | 10 +++++--- src/rspamd.c | 51 ++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c index be1d948a7..b74759229 100644 --- a/src/libserver/cfg_utils.c +++ b/src/libserver/cfg_utils.c @@ -98,7 +98,7 @@ rspamd_parse_bind_line (struct rspamd_config *cfg, const gchar *str) { struct rspamd_worker_bind_conf *cnf; - gchar *err; + const gchar *fdname; gboolean ret = TRUE; if (str == NULL) { @@ -112,11 +112,13 @@ rspamd_parse_bind_line (struct rspamd_config *cfg, if (g_ascii_strncasecmp (str, "systemd:", sizeof ("systemd:") - 1) == 0) { /* The actual socket will be passed by systemd environment */ + fdname = str + sizeof ("systemd:") - 1; cnf->is_systemd = TRUE; - cnf->cnt = strtoul (str + sizeof ("systemd:") - 1, &err, 10); - cnf->addrs = g_ptr_array_new (); + cnf->addrs = g_ptr_array_new_full (1, g_free); - if (err == NULL || *err == '\0') { + if (fdname[0]) { + g_ptr_array_add (cnf->addrs, g_strdup (fdname)); + cnf->cnt = cnf->addrs->len; cnf->name = g_strdup (str); LL_PREPEND (cf->bind_conf, cnf); } diff --git a/src/rspamd.c b/src/rspamd.c index 3a889ec69..511408f23 100644 --- a/src/rspamd.c +++ b/src/rspamd.c @@ -433,15 +433,15 @@ create_listen_socket (GPtrArray *addrs, guint cnt, } static GList * -systemd_get_socket (struct rspamd_main *rspamd_main, gint number) +systemd_get_socket (struct rspamd_main *rspamd_main, const gchar *fdname) { - int sock, num_passed, flags; + int number, sock, num_passed, flags; GList *result = NULL; const gchar *e; - gchar *err; + gchar **fdnames; + gchar *end; struct stat st; - /* XXX: can we trust the current choice ? */ - static const int sd_listen_fds_start = 3; + static const int sd_listen_fds_start = 3; /* SD_LISTEN_FDS_START */ struct rspamd_worker_listen_socket *ls; union { @@ -451,11 +451,39 @@ systemd_get_socket (struct rspamd_main *rspamd_main, gint number) socklen_t slen = sizeof (addr_storage); gint stype; + number = strtoul (fdname, &end, 10); + if (end != NULL && *end != '\0') { + /* Cannot parse as number, assume a name in LISTEN_FDNAMES. */ + e = getenv ("LISTEN_FDNAMES"); + if (!e) { + msg_err_main ("cannot get systemd variable 'LISTEN_FDNAMES'"); + errno = ENOENT; + return NULL; + } + + fdnames = g_strsplit (e, ":", -1); + for (number = 0; fdnames[number]; number++) { + if (!strcmp (fdnames[number], fdname)) { + break; + } + } + if (!fdnames[number]) { + number = -1; + } + g_strfreev (fdnames); + } + + if (number < 0) { + msg_warn_main ("cannot find systemd socket: %s", fdname); + errno = ENOENT; + return NULL; + } + e = getenv ("LISTEN_FDS"); if (e != NULL) { errno = 0; - num_passed = strtoul (e, &err, 10); - if ((err == NULL || *err == '\0') && num_passed > number) { + num_passed = strtoul (e, &end, 10); + if ((end == NULL || *end == '\0') && num_passed > number) { sock = number + sd_listen_fds_start; if (fstat (sock, &st) == -1) { msg_warn_main ("cannot stat systemd descriptor %d", sock); @@ -506,7 +534,7 @@ systemd_get_socket (struct rspamd_main *rspamd_main, gint number) else if (num_passed <= number) { msg_err_main ("systemd LISTEN_FDS does not contain the expected fd: %d", num_passed); - errno = EOVERFLOW; + errno = EINVAL; } } else { @@ -543,8 +571,8 @@ make_listen_key (struct rspamd_worker_bind_conf *cf) rspamd_cryptobox_fast_hash_init (&st, rspamd_hash_seed ()); if (cf->is_systemd) { - rspamd_cryptobox_fast_hash_update (&st, "systemd", sizeof ("systemd")); - rspamd_cryptobox_fast_hash_update (&st, &cf->cnt, sizeof (cf->cnt)); + /* Something like 'systemd:0' or 'systemd:controller'. */ + rspamd_cryptobox_fast_hash_update (&st, cf->name, strlen (cf->name)); } else { rspamd_cryptobox_fast_hash_update (&st, cf->name, strlen (cf->name)); @@ -643,7 +671,8 @@ spawn_workers (struct rspamd_main *rspamd_main, struct ev_loop *ev_base) cf->worker->listen_type); } else { - ls = systemd_get_socket (rspamd_main, bcf->cnt); + ls = systemd_get_socket (rspamd_main, + g_ptr_array_index (bcf->addrs, 0)); } if (ls == NULL) { -- 2.39.5