aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-01-09 15:49:29 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-01-09 15:49:29 +0000
commit288304789907e4d8bbb5b71dc627c2a5aad2f935 (patch)
treef5e36ea28c70f7fdf7d09932042be97f13341436
parent49b2e92d1add1b3746cc71124c1939b6a3288f94 (diff)
downloadrspamd-288304789907e4d8bbb5b71dc627c2a5aad2f935.tar.gz
rspamd-288304789907e4d8bbb5b71dc627c2a5aad2f935.zip
Fix simultaneous bind to ipv6 and ipv6 sockets.
-rw-r--r--CMakeLists.txt1
-rw-r--r--config.h.in2
-rw-r--r--src/cfg_file.h18
-rw-r--r--src/cfg_rcl.c2
-rw-r--r--src/cfg_utils.c180
-rw-r--r--src/main.c20
-rw-r--r--src/settings.c3
-rw-r--r--src/util.c5
8 files changed, 139 insertions, 92 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b3038ba5c..fd2446acf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -790,6 +790,7 @@ CHECK_SYMBOL_EXISTS(MAP_SHARED sys/mman.h HAVE_MMAP_SHARED)
CHECK_SYMBOL_EXISTS(MAP_ANON sys/mman.h HAVE_MMAP_ANON)
CHECK_SYMBOL_EXISTS(MAP_NOCORE sys/mman.h HAVE_MMAP_NOCORE)
CHECK_SYMBOL_EXISTS(O_DIRECT fcntl.h HAVE_O_DIRECT)
+CHECK_SYMBOL_EXISTS(IPV6_V6ONLY "sys/socket.h;netinet/in.h" HAVE_IPV6_V6ONLY)
CHECK_SYMBOL_EXISTS(posix_fadvise fcntl.h HAVE_FADVISE)
CHECK_SYMBOL_EXISTS(posix_fallocate fcntl.h HAVE_POSIX_FALLOCATE)
CHECK_SYMBOL_EXISTS(fallocate fcntl.h HAVE_FALLOCATE)
diff --git a/config.h.in b/config.h.in
index e387d5d1c..2148ebd58 100644
--- a/config.h.in
+++ b/config.h.in
@@ -207,6 +207,8 @@
#cmakedefine HAVE_READPASSPHRASE_H 1
#cmakedefine HAVE_TERMIOS_H 1
+#cmakedefine HAVE_IPV6_V6ONLY 1
+
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
/* Use murmur hash for UTHash for these platforms */
#define HASH_FUNCTION HASH_MUR
diff --git a/src/cfg_file.h b/src/cfg_file.h
index 55ced8456..a1b3db8ed 100644
--- a/src/cfg_file.h
+++ b/src/cfg_file.h
@@ -15,10 +15,9 @@
#include "utlist.h"
#include "ucl.h"
-#define DEFAULT_BIND_PORT 768
-#define DEFAULT_CONTROL_PORT 7608
-#define DEFAULT_LMTP_PORT 7609
-#define MAX_MEMCACHED_SERVERS 48
+#define DEFAULT_BIND_PORT 11333
+#define DEFAULT_CONTROL_PORT 11334
+#define MAX_MEMCACHED_SERVERS 4
#define DEFAULT_MEMCACHED_PORT 11211
/* Memcached timeouts */
#define DEFAULT_MEMCACHED_CONNECT_TIMEOUT 1000
@@ -27,14 +26,6 @@
#define DEFAULT_UPSTREAM_ERROR_TIME 10
#define DEFAULT_UPSTREAM_DEAD_TIME 300
#define DEFAULT_UPSTREAM_MAXERRORS 10
-/* Statfile pool size, 50Mb */
-#define DEFAULT_STATFILE_SIZE 52428800L
-
-/* 1 worker by default */
-#define DEFAULT_WORKERS_NUM 1
-
-#define DEFAULT_SCORE 10.0
-#define DEFAULT_REJECT_SCORE 999.0
struct expression;
struct tokenizer;
@@ -235,7 +226,7 @@ struct classifier_config {
struct rspamd_worker_bind_conf {
gchar *bind_host;
guint16 bind_port;
- gboolean is_unix;
+ gint ai;
struct rspamd_worker_bind_conf *next;
};
@@ -308,7 +299,6 @@ struct config_file {
gboolean log_color; /**< output colors for console output */
gboolean log_extended; /**< log extended information */
- gsize max_statfile_size; /**< maximum size for statfile */
guint32 statfile_sync_interval; /**< synchronization interval */
guint32 statfile_sync_timeout; /**< synchronization timeout */
gboolean mlock_statfile_pool; /**< use mlock (2) for locking statfiles */
diff --git a/src/cfg_rcl.c b/src/cfg_rcl.c
index 188bd3315..0301d475f 100644
--- a/src/cfg_rcl.c
+++ b/src/cfg_rcl.c
@@ -1023,8 +1023,6 @@ rspamd_rcl_config_init (void)
*/
sub = rspamd_rcl_add_section (&new, "options", rspamd_rcl_options_handler, UCL_OBJECT,
FALSE, TRUE);
- rspamd_rcl_add_default_handler (sub, "statfile_pool_size", rspamd_rcl_parse_struct_integer,
- G_STRUCT_OFFSET (struct config_file, max_statfile_size), RSPAMD_CL_FLAG_INT_SIZE);
rspamd_rcl_add_default_handler (sub, "cache_file", rspamd_rcl_parse_struct_string,
G_STRUCT_OFFSET (struct config_file, cache_filename), RSPAMD_CL_FLAG_STRING_PATH);
rspamd_rcl_add_default_handler (sub, "dns_nameserver", rspamd_rcl_parse_struct_string_list,
diff --git a/src/cfg_utils.c b/src/cfg_utils.c
index 282f72b7a..56310669e 100644
--- a/src/cfg_utils.c
+++ b/src/cfg_utils.c
@@ -49,11 +49,13 @@ struct rspamd_ucl_map_cbdata {
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 {
@@ -61,70 +63,46 @@ parse_host_port_priority (memory_pool_t *pool, const gchar *str, gchar **addr, g
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) {
@@ -139,25 +117,70 @@ port_parse:
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)
{
return parse_host_port_priority (pool, str, addr, port, NULL);
@@ -173,28 +196,58 @@ gboolean
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
@@ -220,7 +273,6 @@ init_defaults (struct config_file *cfg)
/* 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);
diff --git a/src/main.c b/src/main.c
index 1765a47b1..1cb641cda 100644
--- a/src/main.c
+++ b/src/main.c
@@ -527,7 +527,7 @@ delay_fork (struct worker_conf *cf)
}
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;
@@ -565,12 +565,13 @@ fork_delayed (struct rspamd_main *rspamd)
}
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;
}
@@ -580,7 +581,7 @@ spawn_workers (struct rspamd_main *rspamd)
{
GList *cur, *ls;
struct worker_conf *cf;
- gint i;
+ gint i, key;
gpointer p;
struct rspamd_worker_bind_conf *bcf;
@@ -595,24 +596,21 @@ spawn_workers (struct rspamd_main *rspamd)
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);
}
}
diff --git a/src/settings.c b/src/settings.c
index 7f92e112d..b5e043fbf 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -474,7 +474,8 @@ check_metric_settings (struct metric_result *res, double *score, double *rscore)
double *sc, *rs;
struct metric *metric = res->metric;
- *rscore = DEFAULT_REJECT_SCORE;
+ /* XXX: what the fuck is that? */
+ *rscore = 10.0;
if (us != NULL) {
if ((rs = g_hash_table_lookup (us->reject_scores, metric->name)) != NULL) {
diff --git a/src/util.c b/src/util.c
index 938bb66cc..4a88bb1c9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -116,6 +116,11 @@ make_inet_socket (gint type, struct addrinfo *addr, gboolean is_server, gboolean
if (is_server) {
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
+#ifdef HAVE_IPV6_V6ONLY
+ if (cur->ai_family == AF_INET6) {
+ setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
+ }
+#endif
r = bind (fd, cur->ai_addr, cur->ai_addrlen);
}
else {