summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2016-01-24 23:23:37 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2016-01-24 23:23:37 +0000
commitd100debaa37a7477fa06bb95ca5087ed70f99cba (patch)
treec913d1c541646f68b95d444f0b0ce00218bf8fc6
parent1678075da31b6939396a95b9aa2c93c90ee7485b (diff)
downloadrspamd-d100debaa37a7477fa06bb95ca5087ed70f99cba.tar.gz
rspamd-d100debaa37a7477fa06bb95ca5087ed70f99cba.zip
Rework parsing of IP addresses
-rw-r--r--src/libserver/cfg_utils.c48
-rw-r--r--src/libutil/addr.c316
-rw-r--r--src/libutil/addr.h14
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
*/