]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Rework parsing of IP addresses
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 24 Jan 2016 23:23:37 +0000 (23:23 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 24 Jan 2016 23:23:37 +0000 (23:23 +0000)
src/libserver/cfg_utils.c
src/libutil/addr.c
src/libutil/addr.h

index 32651dd20d2f4a09d019ba243a4d9c564f962748..475850f958fbeb3a8266bc47e89b945d0ebc1a87 100644 (file)
@@ -63,59 +63,23 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
        const gchar *str)
 {
        struct rspamd_worker_bind_conf *cnf;
-       gchar **tokens, *err;
+       gchar *err;
        gboolean ret = TRUE;
 
        if (str == NULL) {
                return FALSE;
        }
 
-       if (str[0] == '[') {
-               /* This is an ipv6 address */
-               gsize len, ntok;
-               const gchar *start, *ip_pos;
-
-               start = str + 1;
-
-               len = strcspn (start, "]");
-               if (start[len] != ']') {
-                       return FALSE;
-               }
-
-               ip_pos = start;
-               start += len + 1;
-               ntok = 1;
-
-               if (*start == ':') {
-                       ntok = 2;
-                       start ++;
-               }
-
-               tokens = g_malloc_n (ntok + 1, sizeof (gchar *));
-               tokens[ntok] = NULL;
-               tokens[0] = g_malloc (len + 1);
-               rspamd_strlcpy (tokens[0], ip_pos, len + 1);
-
-               if (ntok > 1) {
-                       tokens[1] = g_strdup (start);
-               }
-       }
-       else {
-               tokens = g_strsplit_set (str, ":", 0);
-       }
-       if (!tokens || !tokens[0]) {
-               return FALSE;
-       }
-
        cnf =
                rspamd_mempool_alloc0 (cfg->cfg_pool,
                        sizeof (struct rspamd_worker_bind_conf));
 
        cnf->cnt = 1024;
-       if (strcmp (tokens[0], "systemd") == 0) {
+
+       if (strcmp (str, "systemd") == 0) {
                /* The actual socket will be passed by systemd environment */
                cnf->is_systemd = TRUE;
-               cnf->cnt = strtoul (tokens[1], &err, 10);
+               cnf->cnt = strtoul (str, &err, 10);
                cnf->addrs = NULL;
 
                if (err == NULL || *err == '\0') {
@@ -128,7 +92,7 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
                }
        }
        else {
-               if (!rspamd_parse_host_port_priority_strv (tokens, &cnf->addrs,
+               if (!rspamd_parse_host_port_priority (str, &cnf->addrs,
                                NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
                        msg_err_config ("cannot parse bind line: %s", str);
                        ret = FALSE;
@@ -139,8 +103,6 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
                }
        }
 
-       g_strfreev (tokens);
-
        return ret;
 }
 
index 3eeef8e44cfdf7fb6d75006f525f997a524ddaf5..f5d1415d9f2b203b62662256dd9fb58ea92ebb18 100644 (file)
@@ -879,34 +879,68 @@ rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
        return r;
 }
 
-gboolean
-rspamd_parse_host_port_priority_strv (gchar **tokens,
-       GPtrArray **addrs,
-       guint *priority,
-       gchar **name,
-       guint default_port,
-       rspamd_mempool_t *pool)
+static gboolean
+rspamd_check_port_priority (const char *line, guint default_port,
+               guint *priority, gchar *out,
+               gsize outlen, rspamd_mempool_t *pool)
+{
+       guint real_port = default_port, real_priority = 0;
+       gchar *err_str, *err_str_prio;
+
+       if (line && line[0] == ':') {
+               errno = 0;
+               real_port = strtoul (line + 1, &err_str, 10);
+
+               if (err_str && *err_str == ':') {
+                       /* We have priority */
+                       real_priority = strtoul (err_str + 1, &err_str_prio, 10);
+
+                       if (err_str_prio && *err_str_prio != '\0') {
+                               msg_err_pool (
+                                               "cannot parse priority: %s, at symbol %c, error: %s",
+                                               line,
+                                               *err_str_prio,
+                                               strerror (errno));
+
+                               return FALSE;
+                       }
+               }
+               else if (err_str && *err_str != '\0') {
+                       msg_err_pool (
+                                       "cannot parse port: %s, at symbol %c, error: %s",
+                                       line,
+                                       *err_str,
+                                       strerror (errno));
+
+                       return FALSE;
+               }
+       }
+
+       if (priority) {
+               *priority = real_priority;
+       }
+
+       rspamd_snprintf (out, outlen, "%ud", real_port);
+
+       return TRUE;
+}
+
+static gboolean
+rspamd_resolve_addrs (const char *begin, size_t len, GPtrArray **addrs,
+               const gchar *portbuf, gint flags,
+               rspamd_mempool_t *pool)
 {
-       gchar *err_str, portbuf[8];
-       const gchar *cur_tok, *cur_port;
        struct addrinfo hints, *res, *cur;
-       rspamd_inet_addr_t *cur_addr;
-       guint addr_cnt;
-       guint port_parsed, priority_parsed, saved_errno = errno;
-       gint r;
+       rspamd_inet_addr_t *cur_addr = NULL;
+       gint r, addr_cnt;
+       gchar *addr_cpy;
 
        rspamd_ip_check_ipv6 ();
-       /* Now try to parse host and write address to ina */
        memset (&hints, 0, sizeof (hints));
        hints.ai_socktype = SOCK_STREAM; /* Type of the socket */
-       hints.ai_flags = AI_NUMERICSERV;
-
-       cur_tok = tokens[0];
-
-       if (strcmp (cur_tok, "*") == 0) {
-               hints.ai_flags |= AI_PASSIVE;
-               cur_tok = NULL;
-       }
+       hints.ai_flags = AI_NUMERICSERV|flags;
+       addr_cpy = g_malloc (len + 1);
+       rspamd_strlcpy (addr_cpy, begin, len + 1);
 
        if (ipv6_status == RSPAMD_IPV6_SUPPORTED) {
                hints.ai_family = AF_UNSPEC;
@@ -915,166 +949,152 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
                hints.ai_family = AF_INET;
        }
 
-       if (tokens[1] != NULL) {
-               /* Port part */
-               rspamd_strlcpy (portbuf, tokens[1], sizeof (portbuf));
-               cur_port = portbuf;
-               errno = 0;
-               port_parsed = strtoul (tokens[1], &err_str, 10);
-               if (*err_str != '\0' || errno != 0) {
-                       msg_warn ("cannot parse port: %s, at symbol %c, error: %s",
-                                       tokens[1],
-                                       *err_str,
-                                       strerror (errno));
-                       hints.ai_flags ^= AI_NUMERICSERV;
-               }
-               else if (port_parsed > G_MAXUINT16) {
-                       errno = ERANGE;
-                       msg_warn ("cannot parse port: %s, error: %s",
-                                       tokens[1],
-                                       strerror (errno));
-                       hints.ai_flags ^= AI_NUMERICSERV;
+       if ((r = getaddrinfo (addr_cpy, portbuf, &hints, &res)) == 0) {
+               /* Now copy up to max_addrs of addresses */
+               addr_cnt = 0;
+               cur = res;
+               while (cur) {
+                       cur = cur->ai_next;
+                       addr_cnt ++;
                }
-               if (priority != NULL) {
-                       const gchar *tok;
-
-                       tok = tokens[2];
-                       if (tok != NULL) {
-                               /* Priority part */
-                               errno = 0;
-                               priority_parsed = strtoul (tok, &err_str, 10);
-                               if (*err_str != '\0' || errno != 0) {
-                                       msg_warn (
-                                               "cannot parse priority: %s, at symbol %c, error: %s",
-                                               tok,
-                                               *err_str,
-                                               strerror (errno));
-                               }
-                               else {
-                                       *priority = priority_parsed;
-                               }
-                       }
-               }
-       }
-       else if (default_port != 0) {
-               rspamd_snprintf (portbuf, sizeof (portbuf), "%ud", default_port);
-               cur_port = portbuf;
-       }
-       else {
-               cur_port = NULL;
-       }
-
-       if (*tokens[0] != '/') {
-               if ((r = getaddrinfo (cur_tok, cur_port, &hints, &res)) == 0) {
-                       /* Now copy up to max_addrs of addresses */
-                       addr_cnt = 0;
-                       cur = res;
-                       while (cur) {
-                               cur = cur->ai_next;
-                               addr_cnt ++;
-                       }
 
+               if (*addrs == NULL) {
                        *addrs = g_ptr_array_new_full (addr_cnt,
-                                               (GDestroyNotify)rspamd_inet_address_destroy);
+                                       (GDestroyNotify)rspamd_inet_address_destroy);
 
                        if (pool != NULL) {
                                rspamd_mempool_add_destructor (pool,
                                                rspamd_ptr_array_free_hard, *addrs);
                        }
+               }
 
-                       cur = res;
-                       while (cur) {
-                               cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
-                                               cur->ai_addrlen);
+               cur = res;
+               while (cur) {
+                       cur_addr = rspamd_inet_address_from_sa (cur->ai_addr,
+                                       cur->ai_addrlen);
 
-                               if (cur_addr != NULL) {
-                                       g_ptr_array_add (*addrs, cur_addr);
-                               }
-                               cur = cur->ai_next;
+                       if (cur_addr != NULL) {
+                               g_ptr_array_add (*addrs, cur_addr);
                        }
-
-                       freeaddrinfo (res);
-               }
-               else {
-                       msg_err ("address resolution for %s failed: %s",
-                                       tokens[0],
-                                       gai_strerror (r));
-                       goto err;
+                       cur = cur->ai_next;
                }
+
+               freeaddrinfo (res);
        }
        else {
-               /* Special case of unix socket, as getaddrinfo cannot deal with them */
-               *addrs = g_ptr_array_new_full (1,
-                               (GDestroyNotify)rspamd_inet_address_destroy);
-
-               if (pool != NULL) {
-                       rspamd_mempool_add_destructor (pool,
-                                       rspamd_ptr_array_free_hard, *addrs);
-               }
-
-               if (!rspamd_parse_inet_address (&cur_addr, tokens[0], 0)) {
-                       msg_err ("cannot parse unix socket definition %s: %s",
-                                       tokens[0],
-                                       strerror (errno));
-                       goto err;
-               }
+               msg_err_pool ("address resolution for %s failed: %s",
+                               addr_cpy,
+                               gai_strerror (r));
+               g_free (addr_cpy);
 
-               g_ptr_array_add (*addrs, cur_addr);
+               return FALSE;
        }
 
-       /* Restore errno */
-       if (name != NULL) {
-               if (pool == NULL) {
-                       *name = g_strdup (tokens[0]);
-               }
-               else {
-                       *name = rspamd_mempool_strdup (pool, tokens[0]);
-               }
-       }
-       errno = saved_errno;
        return TRUE;
-
-err:
-       errno = saved_errno;
-       return FALSE;
 }
 
 gboolean
-rspamd_parse_host_port_priority (
-       const gchar *str,
+rspamd_parse_host_port_priority (const gchar *str,
        GPtrArray **addrs,
        guint *priority,
        gchar **name,
        guint default_port,
        rspamd_mempool_t *pool)
 {
-       gchar **tokens;
-       gboolean ret;
+       gchar portbuf[8];
+       const gchar *p;
+       rspamd_inet_addr_t *cur_addr = NULL;
+
+       /*
+        * In this function, we can have several possibilities:
+        * 1) Unix socket: check for '.' or '/' at the begin of string
+        * 2) \[ipv6\]: check for '[' at the beginning
+        * 3) '*': means listening on any address
+        * 4) ip|host[:port[:priority]]
+        */
+
+       if (str[0] == '*') {
+               if (!rspamd_check_port_priority (str + 1, default_port, priority,
+                               portbuf, sizeof (portbuf), pool)) {
+                       return FALSE;
+               }
 
-       tokens = g_strsplit_set (str, ":", 0);
-       if (!tokens || !tokens[0]) {
-               return FALSE;
+               if (!rspamd_resolve_addrs (str, 1, addrs, portbuf, AI_PASSIVE, pool)) {
+                       return FALSE;
+               }
        }
+       else if (str[0] == '[') {
+               /* This is braced IPv6 address */
+               p = strchr (str, ']');
 
-       ret = rspamd_parse_host_port_priority_strv (tokens, addrs,
-                       priority, name, default_port, pool);
+               if (p == NULL) {
+                       msg_err ("cannot parse address definition %s: %s",
+                                       str,
+                                       strerror (EINVAL));
 
-       g_strfreev (tokens);
+                       return FALSE;
+               }
 
-       return ret;
-}
+               if (!rspamd_check_port_priority (p + 1, default_port, priority, portbuf,
+                               sizeof (portbuf), pool)) {
+                       return FALSE;
+               }
 
-gboolean
-rspamd_parse_host_port (const gchar *str,
-       GPtrArray **addrs,
-       gchar **name,
-       guint default_port,
-       rspamd_mempool_t *pool)
-{
-       return rspamd_parse_host_port_priority (str, addrs, NULL,
-                       name, default_port, pool);
-}
+               if (!rspamd_resolve_addrs (str + 1, p - str, addrs,
+                               portbuf, 0, pool)) {
+                       return FALSE;
+               }
+       }
+       else if (str[0] == '/' || str[0] == '.') {
+               /* Special case of unix socket, as getaddrinfo cannot deal with them */
+               if (*addrs == NULL) {
+                       *addrs = g_ptr_array_new_full (1,
+                                       (GDestroyNotify)rspamd_inet_address_destroy);
+
+                       if (pool != NULL) {
+                               rspamd_mempool_add_destructor (pool,
+                                               rspamd_ptr_array_free_hard, *addrs);
+                       }
+               }
+
+               if (!rspamd_parse_inet_address (&cur_addr, str, 0)) {
+                       msg_err_pool ("cannot parse unix socket definition %s: %s",
+                                       str,
+                                       strerror (errno));
+
+                       return FALSE;
+               }
+
+               g_ptr_array_add (*addrs, cur_addr);
+       }
+       else {
+               p = strchr (str, ':');
 
+               if (p == NULL) {
+                       /* Just address or IP */
+                       rspamd_check_port_priority ("", default_port, priority, portbuf,
+                                       sizeof (portbuf), pool);
+
+                       if (!rspamd_resolve_addrs (str, strlen (str), addrs,
+                                       portbuf, 0, pool)) {
+                               return FALSE;
+                       }
+               }
+               else {
+                       if (!rspamd_check_port_priority (p + 1, default_port, priority, portbuf,
+                                       sizeof (portbuf), pool)) {
+                               return FALSE;
+                       }
+
+                       if (!rspamd_resolve_addrs (str + 1, p - str, addrs,
+                                       portbuf, 0, pool)) {
+                               return FALSE;
+                       }
+               }
+       }
+
+       return TRUE;
+}
 
 guchar*
 rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen)
index b2075f7f0dd488cd68fb1c3a3e7d0ad3e7c9a324..72d7beb0774f10f082e0e8dc40f94027906c13b1 100644 (file)
@@ -189,10 +189,6 @@ gboolean rspamd_ip_is_valid (const rspamd_inet_addr_t *addr);
  */
 gint rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **addr);
 
-gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
-       GPtrArray **addrs, guint *priority,
-       gchar **name, guint default_port, rspamd_mempool_t *pool);
-
 /**
  * Parse host[:port[:priority]] line
  * @param ina host address
@@ -205,16 +201,6 @@ gboolean rspamd_parse_host_port_priority (const gchar *str,
                guint *priority, gchar **name, guint default_port,
                rspamd_mempool_t *pool);
 
-/**
- * Parse host:port line
- * @param ina host address
- * @param port port
- * @return TRUE if string was parsed
- */
-gboolean rspamd_parse_host_port (const gchar *str,
-               GPtrArray **addrs,
-       gchar **name, guint default_port, rspamd_mempool_t *pool);
-
 /**
  * Destroy the specified IP address
  * @param addr