]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Support listening on systemd sockets by name 3265/head
authorPeter Wu <peter@lekensteyn.nl>
Sat, 15 Feb 2020 19:05:37 +0000 (19:05 +0000)
committerPeter Wu <peter@lekensteyn.nl>
Sat, 15 Feb 2020 20:05:09 +0000 (20:05 +0000)
* 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
src/rspamd.c

index be1d948a7282970cd777803ea56208986986124b..b7475922913b119793946a0a82808293dbbff10c 100644 (file)
@@ -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);
                }
index 3a889ec693787d033391e4624249b01e14785b7a..511408f23c10a87ab0f905918c78af803e2920b5 100644 (file)
@@ -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) {