diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-01-24 23:23:37 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-01-24 23:23:37 +0000 |
commit | d100debaa37a7477fa06bb95ca5087ed70f99cba (patch) | |
tree | c913d1c541646f68b95d444f0b0ce00218bf8fc6 | |
parent | 1678075da31b6939396a95b9aa2c93c90ee7485b (diff) | |
download | rspamd-d100debaa37a7477fa06bb95ca5087ed70f99cba.tar.gz rspamd-d100debaa37a7477fa06bb95ca5087ed70f99cba.zip |
Rework parsing of IP addresses
-rw-r--r-- | src/libserver/cfg_utils.c | 48 | ||||
-rw-r--r-- | src/libutil/addr.c | 316 | ||||
-rw-r--r-- | src/libutil/addr.h | 14 |
3 files changed, 173 insertions, 205 deletions
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c index 32651dd20..475850f95 100644 --- a/src/libserver/cfg_utils.c +++ b/src/libserver/cfg_utils.c @@ -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; } diff --git a/src/libutil/addr.c b/src/libutil/addr.c index 3eeef8e44..f5d1415d9 100644 --- a/src/libutil/addr.c +++ b/src/libutil/addr.c @@ -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) diff --git a/src/libutil/addr.h b/src/libutil/addr.h index b2075f7f0..72d7beb07 100644 --- a/src/libutil/addr.h +++ b/src/libutil/addr.h @@ -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 @@ -206,16 +202,6 @@ gboolean rspamd_parse_host_port_priority (const gchar *str, 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 */ |