static gchar* rspamd_ucl_read_cb (memory_pool_t * pool, gchar * chunk, gint len, struct map_cb_data *data);
static void rspamd_ucl_fin_cb (memory_pool_t * pool, struct map_cb_data *data);
-gboolean
-parse_host_port_priority (memory_pool_t *pool, const gchar *str, gchar **addr, guint16 *port, guint *priority)
+static gboolean
+parse_host_port_priority_strv (memory_pool_t *pool, gchar **tokens,
+ gchar **addr, guint16 *port, guint *priority, guint default_port)
{
- gchar **tokens, *err_str, *cur_tok;
- struct addrinfo hints, *res;
+ gchar *err_str, portbuf[8];
+ const gchar *cur_tok, *cur_port;
+ struct addrinfo hints, *res;
guint port_parsed, priority_parsed, saved_errno = errno;
gint r;
union {
struct sockaddr_in6 v6;
} addr_holder;
- tokens = g_strsplit_set (str, ":", 0);
- if (!tokens || !tokens[0]) {
- return FALSE;
- }
-
/* Now try to parse host and write address to ina */
memset (&hints, 0, sizeof (hints));
- hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Type of the socket */
- hints.ai_flags = 0;
- hints.ai_protocol = 0; /* Any protocol */
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
-
- if (strcmp (tokens[0], "*") == 0) {
- /* XXX: actually we still cannot listen on multiply protocols */
- if (pool != NULL) {
- *addr = memory_pool_alloc (pool, INET_ADDRSTRLEN + 1);
- }
- rspamd_strlcpy (*addr, "0.0.0.0", INET_ADDRSTRLEN + 1);
- goto port_parse;
- }
- else {
- cur_tok = tokens[0];
- }
+ hints.ai_flags = AI_NUMERICSERV;
- if ((r = getaddrinfo (cur_tok, NULL, &hints, &res)) == 0) {
- memcpy (&addr_holder, res->ai_addr, MIN (sizeof (addr_holder), res->ai_addrlen));
- if (res->ai_family == AF_INET) {
- if (pool != NULL) {
- *addr = memory_pool_alloc (pool, INET_ADDRSTRLEN + 1);
- }
- inet_ntop (res->ai_family, &addr_holder.v4.sin_addr, *addr, INET_ADDRSTRLEN + 1);
- }
- else {
- if (pool != NULL) {
- *addr = memory_pool_alloc (pool, INET6_ADDRSTRLEN + 1);
- }
- inet_ntop (res->ai_family, &addr_holder.v6.sin6_addr, *addr, INET6_ADDRSTRLEN + 1);
- }
- freeaddrinfo (res);
+ cur_tok = tokens[0];
+
+ if (strcmp (cur_tok, "*v6") == 0) {
+ hints.ai_family = AF_INET6;
+ hints.ai_flags |= AI_PASSIVE;
+ cur_tok = NULL;
+ }
+ else if (strcmp (cur_tok, "*v4") == 0) {
+ hints.ai_family = AF_INET;
+ hints.ai_flags |= AI_PASSIVE;
+ cur_tok = NULL;
}
else {
- msg_err ("address resolution for %s failed: %s", tokens[0], gai_strerror (r));
- goto err;
+ hints.ai_family = AF_UNSPEC;
}
-port_parse:
if (tokens[1] != NULL) {
/* Port part */
+ rspamd_strlcpy (portbuf, tokens[1], sizeof (portbuf));
+ cur_port = portbuf;
if (port != NULL) {
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));
- goto err;
+ hints.ai_flags ^= AI_NUMERICSERV;
}
- if (port_parsed > G_MAXUINT16) {
+ else if (port_parsed > G_MAXUINT16) {
errno = ERANGE;
msg_warn ("cannot parse port: %s, error: %s", tokens[1], *err_str, strerror (errno));
- goto err;
+ hints.ai_flags ^= AI_NUMERICSERV;
+ }
+ else {
+ *port = port_parsed;
}
- *port = port_parsed;
}
if (priority != NULL) {
if (port != NULL) {
priority_parsed = strtoul (cur_tok, &err_str, 10);
if (*err_str != '\0' || errno != 0) {
msg_warn ("cannot parse priority: %s, at symbol %c, error: %s", tokens[1], *err_str, strerror (errno));
- goto err;
}
- *priority = priority_parsed;
+ else {
+ *priority = priority_parsed;
+ }
}
}
}
-
+ else if (default_port != 0) {
+ rspamd_snprintf (portbuf, sizeof (portbuf), "%u", default_port);
+ cur_port = portbuf;
+ }
+ else {
+ cur_port = NULL;
+ }
+
+ if ((r = getaddrinfo (cur_tok, cur_port, &hints, &res)) == 0) {
+ memcpy (&addr_holder, res->ai_addr, MIN (sizeof (addr_holder), res->ai_addrlen));
+ if (res->ai_family == AF_INET) {
+ if (pool != NULL) {
+ *addr = memory_pool_alloc (pool, INET_ADDRSTRLEN + 1);
+ }
+ inet_ntop (res->ai_family, &addr_holder.v4.sin_addr, *addr, INET_ADDRSTRLEN + 1);
+ }
+ else {
+ if (pool != NULL) {
+ *addr = memory_pool_alloc (pool, INET6_ADDRSTRLEN + 1);
+ }
+ inet_ntop (res->ai_family, &addr_holder.v6.sin6_addr, *addr, INET6_ADDRSTRLEN + 1);
+ }
+ freeaddrinfo (res);
+ }
+ else {
+ msg_err ("address resolution for %s failed: %s", tokens[0], gai_strerror (r));
+ goto err;
+ }
+
/* Restore errno */
errno = saved_errno;
- g_strfreev (tokens);
return TRUE;
err:
errno = saved_errno;
- g_strfreev (tokens);
return FALSE;
}
+gboolean
+parse_host_port_priority (memory_pool_t *pool, const gchar *str, gchar **addr, guint16 *port, guint *priority)
+{
+ gchar **tokens;
+ gboolean ret;
+
+ tokens = g_strsplit_set (str, ":", 0);
+ if (!tokens || !tokens[0]) {
+ return FALSE;
+ }
+
+ ret = parse_host_port_priority_strv (pool, tokens, addr, port, priority, 0);
+
+ g_strfreev (tokens);
+
+ return ret;
+}
+
gboolean
parse_host_port (memory_pool_t *pool, const gchar *str, gchar **addr, guint16 *port)
{
parse_bind_line (struct config_file *cfg, struct worker_conf *cf, const gchar *str)
{
struct rspamd_worker_bind_conf *cnf;
+ gchar **tokens, *tmp;
+ gboolean ret;
- if (str == NULL)
- return 0;
+ if (str == NULL) {
+ return FALSE;
+ }
+
+ tokens = g_strsplit_set (str, ":", 0);
+ if (!tokens || !tokens[0]) {
+ return FALSE;
+ }
cnf = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_worker_bind_conf));
cnf->bind_port = DEFAULT_BIND_PORT;
+ cnf->bind_host = memory_pool_strdup (cfg->cfg_pool, str);
+ cnf->ai = AF_UNSPEC;
- if (str[0] == '/' || str[0] == '.') {
- cnf->bind_host = memory_pool_strdup (cfg->cfg_pool, str);
- cnf->is_unix = TRUE;
+ if (*tokens[0] == '/' || *tokens[0] == '.') {
+ cnf->ai = AF_UNIX;
LL_PREPEND (cf->bind_conf, cnf);
return TRUE;
}
- else {
+ else if (strcmp (tokens[0], "*") == 0) {
+ /* We need to add two listen entries: one for ipv4 and one for ipv6 */
+ tmp = tokens[0];
+ tokens[0] = "*v4";
+ cnf->ai = AF_INET;
+ if ((ret = parse_host_port_priority_strv (cfg->cfg_pool, tokens,
+ &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
+ LL_PREPEND (cf->bind_conf, cnf);
+ }
+ cnf = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_worker_bind_conf));
+ cnf->bind_port = DEFAULT_BIND_PORT;
cnf->bind_host = memory_pool_strdup (cfg->cfg_pool, str);
- if (parse_host_port (cfg->cfg_pool, str, &cnf->bind_host, &cnf->bind_port)) {
+ cnf->ai = AF_INET6;
+ tokens[0] = "*v6";
+ if ((ret &= parse_host_port_priority_strv (cfg->cfg_pool, tokens,
+ &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
+ LL_PREPEND (cf->bind_conf, cnf);
+ }
+ tokens[0] = tmp;
+ }
+ else {
+ if ((ret = parse_host_port_priority_strv (cfg->cfg_pool, tokens,
+ &cnf->bind_host, &cnf->bind_port, NULL, DEFAULT_BIND_PORT))) {
LL_PREPEND (cf->bind_conf, cnf);
- return TRUE;
}
}
- return FALSE;
+ g_strfreev (tokens);
+
+ return ret;
}
void
/* 20 Kb */
cfg->max_diff = 20480;
- cfg->max_statfile_size = DEFAULT_STATFILE_SIZE;
cfg->metrics = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
cfg->c_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
cfg->composite_symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
}
static GList *
-create_listen_socket (const gchar *addr, gint port, gint family, gint listen_type)
+create_listen_socket (const gchar *addr, gint port, gint listen_type)
{
gint listen_sock = -1;
GList *result, *cur;
}
static inline uintptr_t
-make_listen_key (const gchar *addr, gint port, gint family)
+make_listen_key (gint ai, const gchar *addr, gint port)
{
uintptr_t res = 0;
res = murmur32_hash (addr, strlen (addr));
- res ^= murmur32_hash ((guchar *)&port, sizeof (gint));
+ res += murmur32_hash ((guchar *)&ai, sizeof (gint));
+ res += murmur32_hash ((guchar *)&port, sizeof (gint));
return res;
}
{
GList *cur, *ls;
struct worker_conf *cf;
- gint i;
+ gint i, key;
gpointer p;
struct rspamd_worker_bind_conf *bcf;
else {
if (cf->worker->has_socket) {
LL_FOREACH (cf->bind_conf, bcf) {
- if ((p = g_hash_table_lookup (listen_sockets, GINT_TO_POINTER (
- make_listen_key (bcf->bind_host, bcf->bind_port, bcf->is_unix)))) == NULL) {
+ key = make_listen_key (bcf->ai, bcf->bind_host, bcf->bind_port);
+ if ((p = g_hash_table_lookup (listen_sockets, GINT_TO_POINTER (key))) == NULL) {
/* Create listen socket */
ls = create_listen_socket (bcf->bind_host, bcf->bind_port,
- bcf->is_unix ? AF_UNIX : AF_INET,
cf->worker->listen_type);
if (ls == NULL) {
exit (-errno);
}
- g_hash_table_insert (listen_sockets, GINT_TO_POINTER (
- make_listen_key (bcf->bind_host, bcf->bind_port, bcf->is_unix)),
- ls);
+ g_hash_table_insert (listen_sockets, GINT_TO_POINTER (key), ls);
}
else {
/* We had socket for this type of worker */
ls = p;
}
- cf->listen_socks = ls;
+ cf->listen_socks = g_list_concat (cf->listen_socks, ls);
}
}