summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt39
-rw-r--r--centos/rspamd.spec2
-rw-r--r--conf/rspamd.systemd.conf20
-rw-r--r--contrib/http-parser/http_parser.c32
-rw-r--r--contrib/http-parser/http_parser.h2
-rw-r--r--src/client/rspamc.c6
-rw-r--r--src/controller.c26
-rw-r--r--src/fuzzy_storage.c20
-rw-r--r--src/libmime/filter.c8
-rw-r--r--src/libmime/message.c2
-rw-r--r--src/libmime/smtp_utils.c2
-rw-r--r--src/libserver/cfg_file.h2
-rw-r--r--src/libserver/cfg_utils.c5
-rw-r--r--src/libserver/protocol.c90
-rw-r--r--src/libserver/roll_history.c27
-rw-r--r--src/libserver/roll_history.h3
-rw-r--r--src/libserver/spf.c10
-rw-r--r--src/libserver/task.c28
-rw-r--r--src/libserver/task.h25
-rw-r--r--src/libserver/url.c27
-rw-r--r--src/libutil/addr.c600
-rw-r--r--src/libutil/addr.h135
-rw-r--r--src/libutil/http.c12
-rw-r--r--src/libutil/http.h6
-rw-r--r--src/libutil/logger.h2
-rw-r--r--src/libutil/radix.c14
-rw-r--r--src/libutil/upstream.c90
-rw-r--r--src/libutil/upstream.h4
-rw-r--r--src/libutil/util.c9
-rw-r--r--src/libutil/util.h6
-rw-r--r--src/lua/lua_common.h3
-rw-r--r--src/lua/lua_config.c4
-rw-r--r--src/lua/lua_dns.c16
-rw-r--r--src/lua/lua_http.c23
-rw-r--r--src/lua/lua_ip.c190
-rw-r--r--src/lua/lua_redis.c7
-rw-r--r--src/lua/lua_task.c4
-rw-r--r--src/lua_worker.c10
-rw-r--r--src/main.c29
-rw-r--r--src/plugins/dkim_check.c2
-rw-r--r--src/plugins/fuzzy_check.c4
-rw-r--r--src/plugins/regexp.c10
-rw-r--r--src/plugins/spf.c40
-rw-r--r--src/smtp_proxy.c9
-rw-r--r--src/worker.c22
-rw-r--r--test/lua/unit/regxep.lua4
-rw-r--r--test/rspamd_http_test.c17
-rw-r--r--test/rspamd_upstream_test.c17
48 files changed, 1120 insertions, 545 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3754197f6..a330a5a20 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,7 +41,7 @@ OPTION(NO_SHARED "Build internal libs static [default: ON]" O
OPTION(FORCE_GMIME24 "Link with gmime2.4 [default: OFF]" OFF)
OPTION(INSTALL_EXAMPLES "Install examples [default: OFF]" OFF)
OPTION(INSTALL_WEBUI "Install web interface [default: ON]" ON)
-OPTION(WANT_SYSTEMD_UNITS "Install systemd unit files on Linux [default: ON]" ON)
+OPTION(WANT_SYSTEMD_UNITS "Install systemd unit files on Linux [default: OFF]" OFF)
# Build optimized code for following CPU (default i386)
#SET(CPU_TUNE "i686")
@@ -103,6 +103,7 @@ IF(NOT SYSTEMDDIR)
SET(SYSTEMDDIR ${CMAKE_INSTALL_PREFIX}/lib/systemd/system)
ENDIF(NOT SYSTEMDDIR)
+
############################# INCLUDE SECTION #############################################
INCLUDE(CheckIncludeFiles)
@@ -195,27 +196,28 @@ MACRO(FindLua _major _minor)
ENDIF(LUA_LIBRARY AND LUA_INCLUDE_DIR)
ENDMACRO(FindLua _major _minor)
-FUNCTION(INSTALL_IF_NOT_EXISTS src dest suffix)
+FUNCTION(INSTALL_IF_NOT_EXISTS src dest destname suffix)
IF(NOT IS_ABSOLUTE "${src}")
SET(src "${CMAKE_CURRENT_SOURCE_DIR}/${src}")
ENDIF()
GET_FILENAME_COMPONENT(src_name "${src}" NAME)
+ GET_FILENAME_COMPONENT(dest_name "${destname}" NAME)
IF(NOT IS_ABSOLUTE "${dest}")
SET(dest "${CMAKE_INSTALL_PREFIX}/${dest}")
ENDIF()
INSTALL(CODE "
- IF(NOT EXISTS \"\$ENV{DESTDIR}${dest}/${src_name}${suffix}\")
+ IF(NOT EXISTS \"\$ENV{DESTDIR}${dest}/${dest_name}${suffix}\")
#FILE(INSTALL \"${src}\" DESTINATION \"${dest}\")
- MESSAGE(STATUS \"Installing: \$ENV{DESTDIR}${dest}/${src_name}${suffix}\")
+ MESSAGE(STATUS \"Installing: \$ENV{DESTDIR}${dest}/${dest_name}${suffix}\")
EXECUTE_PROCESS(COMMAND \${CMAKE_COMMAND} -E copy \"${src}\"
- \"\$ENV{DESTDIR}${dest}/${src_name}${suffix}\"
+ \"\$ENV{DESTDIR}${dest}/${dest_name}${suffix}\"
RESULT_VARIABLE copy_result
ERROR_VARIABLE error_output)
IF(copy_result)
MESSAGE(FATAL_ERROR \${error_output})
ENDIF()
ELSE()
- MESSAGE(STATUS \"Skipping : \$ENV{DESTDIR}${dest}/${src_name}${suffix}\")
+ MESSAGE(STATUS \"Skipping : \$ENV{DESTDIR}${dest}/${dest_name}${suffix}\")
ENDIF()
")
ENDFUNCTION(INSTALL_IF_NOT_EXISTS)
@@ -420,7 +422,7 @@ IF(OPENSSL_FOUND)
INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}")
ENDIF(OPENSSL_FOUND)
-ProcessPackage(GLIB2 glib-2.0>=2.16)
+ProcessPackage(GLIB2 glib-2.0>=2.30)
ProcessPackage(GTHREAD gthread-2.0)
ProcessPackage(HIREDIS hiredis libhiredis)
ProcessPackage(PCRE pcre libpcre pcre3 libpcre3)
@@ -1036,15 +1038,34 @@ MATH(EXPR CONFLIST_MAX ${CONFLIST_COUNT}-1)
FOREACH(CONF_IDX RANGE ${CONFLIST_MAX})
LIST(GET CONFFILES ${CONF_IDX} CONF_FILE)
IF(BUILD_PORT)
- INSTALL_IF_NOT_EXISTS(${CONF_FILE} ${CONFDIR} ".sample")
+ INSTALL_IF_NOT_EXISTS(${CONF_FILE} ${CONFDIR} ${CONF_FILE} ".sample")
ELSE(BUILD_PORT)
- INSTALL_IF_NOT_EXISTS(${CONF_FILE} ${CONFDIR} "")
+ INSTALL_IF_NOT_EXISTS(${CONF_FILE} ${CONFDIR} ${CONF_FILE} "")
ENDIF(BUILD_PORT)
IF(INSTALL_EXAMPLES MATCHES "ON")
INSTALL(FILES ${CONF_FILE} DESTINATION ${EXAMPLESDIR})
ENDIF(INSTALL_EXAMPLES MATCHES "ON")
ENDFOREACH(CONF_IDX RANGE ${CONFLIST_MAX})
+# Main config is special due to systemd
+IF(WANT_SYSTEMD_UNITS MATCHES "ON")
+ SET(MAIN_CONF "conf/rspamd.systemd.conf")
+ELSE(WANT_SYSTEMD_UNITS MATCHES "ON")
+ SET(MAIN_CONF "conf/rspamd.sysvinit.conf")
+ENDIF(WANT_SYSTEMD_UNITS MATCHES "ON")
+IF(BUILD_PORT)
+ INSTALL_IF_NOT_EXISTS(${MAIN_CONF} ${CONFDIR} "rspamd.conf" ".sample")
+ELSE(BUILD_PORT)
+ INSTALL_IF_NOT_EXISTS(${MAIN_CONF} ${CONFDIR} "rspamd.conf" "")
+ENDIF(BUILD_PORT)
+# Debian is also special
+IF(DEBIAN_BUILD)
+ INSTALL_IF_NOT_EXISTS("conf/rspamd.sysvinit.conf" ${CONFDIR} "rspamd.sysvinit.conf" "")
+ENDIF(DEBIAN_BUILD)
+IF(INSTALL_EXAMPLES MATCHES "ON")
+ INSTALL(FILES ${MAIN_CONF} DESTINATION ${EXAMPLESDIR})
+ENDIF(INSTALL_EXAMPLES MATCHES "ON")
+
# Lua plugins
FILE(GLOB LUA_PLUGINS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src/plugins/lua"
diff --git a/centos/rspamd.spec b/centos/rspamd.spec
index c037070b7..45010b145 100644
--- a/centos/rspamd.spec
+++ b/centos/rspamd.spec
@@ -70,6 +70,7 @@ lua.
%if 0%{?el6}
-DWANT_SYSTEMD_UNITS=OFF \
%else
+ -DWANT_SYSTEMD_UNITS=ON \
-DSYSTEMDDIR=%{_unitdir} \
%endif
-DLOGDIR=%{_localstatedir}/log/rspamd \
@@ -178,7 +179,6 @@ fi
%config(noreplace) %{rspamd_confdir}/common.conf
%config(noreplace) %{rspamd_confdir}/logging.inc
%config(noreplace) %{rspamd_confdir}/options.inc
-%config(noreplace) %{rspamd_confdir}/%{name}.sysvinit.conf
%config(noreplace) %{rspamd_confdir}/worker-controller.inc
%config(noreplace) %{rspamd_confdir}/worker-normal.inc
%if 0%{?el6}
diff --git a/conf/rspamd.systemd.conf b/conf/rspamd.systemd.conf
new file mode 100644
index 000000000..06dbe8599
--- /dev/null
+++ b/conf/rspamd.systemd.conf
@@ -0,0 +1,20 @@
+.include "$CONFDIR/common.conf"
+
+options {
+ .include "$CONFDIR/options.inc"
+}
+
+logging {
+ type = "console";
+ .include "$CONFDIR/logging.inc"
+}
+
+worker {
+ bind_socket = "systemd:0";
+ .include "$CONFDIR/worker-normal.inc"
+}
+
+worker {
+ bind_socket = "systemd:1";
+ .include "$CONFDIR/worker-controller.inc"
+}
diff --git a/contrib/http-parser/http_parser.c b/contrib/http-parser/http_parser.c
index 129df138d..33f5ed301 100644
--- a/contrib/http-parser/http_parser.c
+++ b/contrib/http-parser/http_parser.c
@@ -1215,19 +1215,21 @@ size_t http_parser_execute (http_parser *parser,
break;
}
- case s_req_spamc_start:
- switch (ch) {
- case 'S':
- case 'R':
- parser->state = s_req_spamc;
- break;
- case ' ':
- break;
- default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
- goto error;
- }
- break;
+ case s_req_spamc_start: {
+ if (ch == 'S') {
+ parser->flags |= F_SPAMC;
+ parser->state = s_req_spamc;
+ }
+ else if (ch == 'R') {
+ parser->state = s_req_spamc;
+ }
+ else if (ch != ' ') {
+ SET_ERRNO(HPE_INVALID_CONSTANT);
+ goto error;
+ }
+
+ break;
+ }
case s_req_spamc:
{
@@ -1607,7 +1609,7 @@ size_t http_parser_execute (http_parser *parser,
parser->flags |= F_CONNECTION_KEEP_ALIVE;
break;
case h_connection_close:
- parser->flags |= F_CONNECTION_CLOSE;
+ /* XXX: not needed for rspamd parser->flags |= F_CONNECTION_CLOSE; */
break;
case h_transfer_encoding_chunked:
parser->flags |= F_CHUNKED;
@@ -1957,7 +1959,7 @@ http_should_keep_alive (const http_parser *parser)
{
if (parser->http_major > 0 && parser->http_minor > 0) {
/* HTTP/1.1 */
- if (parser->flags & F_CONNECTION_CLOSE) {
+ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
return 0;
}
} else {
diff --git a/contrib/http-parser/http_parser.h b/contrib/http-parser/http_parser.h
index a322634f1..bac517f51 100644
--- a/contrib/http-parser/http_parser.h
+++ b/contrib/http-parser/http_parser.h
@@ -129,7 +129,7 @@ enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
- , F_CONNECTION_CLOSE = 1 << 2
+ , F_SPAMC = 1 << 2
, F_TRAILING = 1 << 3
, F_UPGRADE = 1 << 4
, F_SKIPBODY = 1 << 5
diff --git a/src/client/rspamc.c b/src/client/rspamc.c
index 42b995630..d5accd8a8 100644
--- a/src/client/rspamc.c
+++ b/src/client/rspamc.c
@@ -36,13 +36,13 @@
static gchar *connect_str = "localhost";
static gchar *password = NULL;
-static gchar *ip = NULL;
+static gchar *ip = "127.0.0.1";
static gchar *from = NULL;
static gchar *deliver_to = NULL;
static gchar *rcpt = NULL;
static gchar *user = NULL;
-static gchar *helo = NULL;
-static gchar *hostname = NULL;
+static gchar *helo = "localhost.localdomain";
+static gchar *hostname = "localhost";
static gchar *classifier = "bayes";
static gchar *local_addr = NULL;
static gint weight = 0;
diff --git a/src/controller.c b/src/controller.c
index ca7a4f686..e1555f12a 100644
--- a/src/controller.c
+++ b/src/controller.c
@@ -126,7 +126,7 @@ struct rspamd_controller_session {
rspamd_mempool_t *pool;
struct rspamd_task *task;
struct rspamd_classifier_config *cl;
- rspamd_inet_addr_t from_addr;
+ rspamd_inet_addr_t *from_addr;
gboolean is_spam;
};
@@ -141,14 +141,14 @@ rspamd_controller_check_password (struct rspamd_http_connection_entry *entry,
gboolean ret = TRUE;
/* Access list logic */
- if (!session->from_addr.af == AF_UNIX) {
+ if (!rspamd_inet_address_get_af(session->from_addr) == AF_UNIX) {
msg_info ("allow unauthorized connection from a unix socket");
return TRUE;
}
else if (ctx->secure_map && radix_find_compressed_addr (ctx->secure_map,
- &session->from_addr) != RADIX_NO_VALUE) {
+ session->from_addr) != RADIX_NO_VALUE) {
msg_info ("allow unauthorized connection from a trusted IP %s",
- rspamd_inet_address_to_string (&session->from_addr));
+ rspamd_inet_address_to_string (session->from_addr));
return TRUE;
}
@@ -687,8 +687,7 @@ rspamd_controller_handle_history (struct rspamd_http_connection_entry *conn_ent,
timebuf), "time", 0, false);
ucl_object_insert_key (obj, ucl_object_fromstring (
row->message_id), "id", 0, false);
- ucl_object_insert_key (obj, ucl_object_fromstring (
- rspamd_inet_address_to_string (&row->from_addr)),
+ ucl_object_insert_key (obj, ucl_object_fromstring (row->from_addr),
"ip", 0, false);
ucl_object_insert_key (obj,
ucl_object_fromstring (rspamd_action_to_str (
@@ -737,7 +736,7 @@ rspamd_controller_learn_fin_task (void *ud)
}
/* Successful learn */
msg_info ("<%s> learned message: %s",
- rspamd_inet_address_to_string (&session->from_addr),
+ rspamd_inet_address_to_string (session->from_addr),
task->message_id);
rspamd_controller_send_string (conn_ent, "{\"success\":true}");
@@ -1024,7 +1023,7 @@ rspamd_controller_handle_saveactions (
dump_dynamic_config (ctx->cfg);
msg_info ("<%s> modified %d actions",
- rspamd_inet_address_to_string (&session->from_addr),
+ rspamd_inet_address_to_string (session->from_addr),
added);
rspamd_controller_send_string (conn_ent, "{\"success\":true}");
@@ -1135,7 +1134,7 @@ rspamd_controller_handle_savesymbols (
dump_dynamic_config (ctx->cfg);
msg_info ("<%s> modified %d symbols",
- rspamd_inet_address_to_string (&session->from_addr),
+ rspamd_inet_address_to_string (session->from_addr),
added);
rspamd_controller_send_string (conn_ent, "{\"success\":true}");
@@ -1235,7 +1234,7 @@ rspamd_controller_handle_savemap (struct rspamd_http_connection_entry *conn_ent,
}
msg_info ("<%s>, map %s saved",
- rspamd_inet_address_to_string (&session->from_addr),
+ rspamd_inet_address_to_string (session->from_addr),
map->uri);
/* Close and unlock */
close (fd);
@@ -1372,7 +1371,7 @@ rspamd_controller_handle_statreset (
}
msg_info ("<%s> reset stat",
- rspamd_inet_address_to_string (&session->from_addr));
+ rspamd_inet_address_to_string (session->from_addr));
return rspamd_controller_handle_stat_common (conn_ent, msg, TRUE);
}
@@ -1492,6 +1491,7 @@ rspamd_controller_finish_handler (struct rspamd_http_connection_entry *conn_ent)
rspamd_mempool_delete (session->pool);
}
+ rspamd_inet_address_destroy (session->from_addr);
g_slice_free1 (sizeof (struct rspamd_controller_session), session);
}
@@ -1501,7 +1501,7 @@ rspamd_controller_accept_socket (gint fd, short what, void *arg)
struct rspamd_worker *worker = (struct rspamd_worker *) arg;
struct rspamd_controller_worker_ctx *ctx;
struct rspamd_controller_session *nsession;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gint nfd;
ctx = worker->ctx;
@@ -1520,7 +1520,7 @@ rspamd_controller_accept_socket (gint fd, short what, void *arg)
nsession->pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
nsession->ctx = ctx;
- memcpy (&nsession->from_addr, &addr, sizeof (addr));
+ nsession->from_addr = addr;
rspamd_http_router_handle_socket (ctx->http, nfd, nsession);
}
diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c
index 1f238432a..77a5b9a55 100644
--- a/src/fuzzy_storage.c
+++ b/src/fuzzy_storage.c
@@ -105,7 +105,7 @@ struct fuzzy_session {
gint fd;
guint64 time;
gboolean legacy;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
struct rspamd_fuzzy_storage_ctx *ctx;
};
@@ -114,7 +114,7 @@ rspamd_fuzzy_check_client (struct fuzzy_session *session)
{
if (session->ctx->update_ips != NULL) {
if (radix_find_compressed_addr (session->ctx->update_ips,
- &session->addr) == RADIX_NO_VALUE) {
+ session->addr) == RADIX_NO_VALUE) {
return FALSE;
}
}
@@ -142,12 +142,11 @@ rspamd_fuzzy_write_reply (struct fuzzy_session *session,
else {
r = rspamd_snprintf (buf, sizeof (buf), "ERR" CRLF);
}
- r = sendto (session->fd, buf, r, 0, &session->addr.addr.sa,
- session->addr.slen);
+ r = rspamd_inet_address_sendto (session->fd, buf, r, 0, session->addr);
}
else {
- r = sendto (session->fd, rep, sizeof (*rep), 0, &session->addr.addr.sa,
- session->addr.slen);
+ r = rspamd_inet_address_sendto (session->fd, rep, sizeof (*rep), 0,
+ session->addr);
}
if (r == -1) {
@@ -233,14 +232,13 @@ accept_fuzzy_socket (gint fd, short what, void *arg)
session.worker = worker;
session.fd = fd;
- session.addr.slen = sizeof (session.addr.addr);
session.ctx = worker->ctx;
session.time = (guint64)time (NULL);
/* Got some data */
if (what == EV_READ) {
- while ((r = recvfrom (fd, buf, sizeof (buf), 0,
- &session.addr.addr.sa, &session.addr.slen)) == -1) {
+ while ((r = rspamd_inet_address_recvfrom (fd, buf, sizeof (buf), 0,
+ &session.addr)) == -1) {
if (errno == EINTR) {
continue;
}
@@ -249,7 +247,7 @@ accept_fuzzy_socket (gint fd, short what, void *arg)
strerror (errno));
return;
}
- session.addr.af = session.addr.addr.sa.sa_family;
+
if ((guint)r == sizeof (struct legacy_fuzzy_cmd)) {
session.legacy = TRUE;
l = (struct legacy_fuzzy_cmd *)buf;
@@ -279,6 +277,8 @@ accept_fuzzy_socket (gint fd, short what, void *arg)
session.cmd = cmd;
rspamd_fuzzy_process_command (&session);
}
+
+ rspamd_inet_address_destroy (session.addr);
}
}
diff --git a/src/libmime/filter.c b/src/libmime/filter.c
index 89bbfad10..7736ba4cf 100644
--- a/src/libmime/filter.c
+++ b/src/libmime/filter.c
@@ -367,7 +367,7 @@ rspamd_process_filters (struct rspamd_task *task)
wl = ucl_object_find_key (task->settings, "whitelist");
if (wl != NULL) {
msg_info ("<%s> is whitelisted", task->message_id);
- task->is_skipped = TRUE;
+ task->flags |= RSPAMD_TASK_FLAG_SKIP;
return 0;
}
}
@@ -378,7 +378,7 @@ rspamd_process_filters (struct rspamd_task *task)
cur = task->cfg->metrics_list;
while (cur) {
metric = cur->data;
- if (!task->pass_all_filters &&
+ if (!(task->flags & RSPAMD_TASK_FLAG_PASS_ALL) &&
metric->actions[METRIC_ACTION_REJECT].score > 0 &&
check_metric_is_spam (task, metric)) {
msg_info ("<%s> has already scored more than %.2f, so do not "
@@ -648,7 +648,7 @@ struct classifiers_cbdata {
void
rspamd_process_statistics (struct rspamd_task *task)
{
- if (task->is_skipped) {
+ if (RSPAMD_TASK_IS_SKIPPED (task)) {
return;
}
@@ -665,7 +665,7 @@ rspamd_process_statistic_threaded (gpointer data, gpointer user_data)
struct rspamd_task *task = (struct rspamd_task *)data;
struct lua_locked_state *nL = user_data;
- if (task->is_skipped) {
+ if (RSPAMD_TASK_IS_SKIPPED (task)) {
remove_async_thread (task->s);
return;
}
diff --git a/src/libmime/message.c b/src/libmime/message.c
index 3786219ef..f59fe4671 100644
--- a/src/libmime/message.c
+++ b/src/libmime/message.c
@@ -1525,7 +1525,7 @@ process_message (struct rspamd_task *task)
*/
g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE);
- if (task->is_mime) {
+ if (task->flags & RSPAMD_TASK_FLAG_MIME) {
debug_task ("construct mime parser from string length %d",
(gint)task->msg.len);
diff --git a/src/libmime/smtp_utils.c b/src/libmime/smtp_utils.c
index a5a2f26ef..5a8683d7b 100644
--- a/src/libmime/smtp_utils.c
+++ b/src/libmime/smtp_utils.c
@@ -179,7 +179,7 @@ smtp_metric_callback (gpointer key, gpointer value, gpointer ud)
cd->res = metric_res;
}
- if (!task->is_skipped) {
+ if (!RSPAMD_TASK_IS_SKIPPED (task)) {
cd->log_offset += rspamd_snprintf (cd->log_buf + cd->log_offset,
cd->log_size - cd->log_offset,
"(%s: %c (%s): [%.2f/%.2f/%.2f] [",
diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h
index 44728afe8..08b70f5c9 100644
--- a/src/libserver/cfg_file.h
+++ b/src/libserver/cfg_file.h
@@ -163,7 +163,7 @@ struct rspamd_classifier_config {
};
struct rspamd_worker_bind_conf {
- rspamd_inet_addr_t *addrs;
+ GPtrArray *addrs;
guint cnt;
gchar *name;
gboolean is_systemd;
diff --git a/src/libserver/cfg_utils.c b/src/libserver/cfg_utils.c
index 234f639d4..983a73f3f 100644
--- a/src/libserver/cfg_utils.c
+++ b/src/libserver/cfg_utils.c
@@ -113,7 +113,9 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
cnf->is_systemd = TRUE;
cnf->cnt = strtoul (tokens[1], &err, 10);
cnf->addrs = NULL;
+
if (err == NULL || *err == '\0') {
+ cnf->name = rspamd_mempool_strdup (cfg->cfg_pool, str);
LL_PREPEND (cf->bind_conf, cnf);
}
else {
@@ -123,11 +125,12 @@ rspamd_parse_bind_line (struct rspamd_config *cfg,
}
else {
if (!rspamd_parse_host_port_priority_strv (tokens, &cnf->addrs,
- &cnf->cnt, NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
+ NULL, &cnf->name, DEFAULT_BIND_PORT, cfg->cfg_pool)) {
msg_err ("cannot parse bind line: %s", str);
ret = FALSE;
}
else {
+ cnf->cnt = cnf->addrs->len;
LL_PREPEND (cf->bind_conf, cnf);
}
}
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index 599d6e4ce..3c6dd41a9 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -232,7 +232,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
struct rspamd_http_message *msg)
{
gchar *headern, *tmp;
- gboolean res = TRUE, validh;
+ gboolean res = TRUE, validh, fl;
struct rspamd_http_header *h;
LL_FOREACH (msg->headers, h)
@@ -284,7 +284,13 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
case 'j':
case 'J':
if (g_ascii_strcasecmp (headern, JSON_HEADER) == 0) {
- task->is_json = rspamd_config_parse_flag (h->value->str);
+ fl = rspamd_config_parse_flag (h->value->str);
+ if (fl) {
+ task->flags |= RSPAMD_TASK_FLAG_JSON;
+ }
+ else {
+ task->flags &= ~RSPAMD_TASK_FLAG_JSON;
+ }
}
else {
debug_task ("wrong header: %s", headern);
@@ -336,7 +342,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
if (g_ascii_strcasecmp (headern, PASS_HEADER) == 0) {
if (h->value->len == sizeof ("all") - 1 &&
g_ascii_strcasecmp (h->value->str, "all") == 0) {
- task->pass_all_filters = TRUE;
+ task->flags |= RSPAMD_TASK_FLAG_PASS_ALL;
debug_task ("pass all filters");
}
}
@@ -361,7 +367,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
if (g_ascii_strcasecmp (headern, URLS_HEADER) == 0) {
if (h->value->len == sizeof ("extended") - 1 &&
g_ascii_strcasecmp (h->value->str, "extended") == 0) {
- task->extended_urls = TRUE;
+ task->flags |= RSPAMD_TASK_FLAG_EXT_URLS;
debug_task ("extended urls information");
}
}
@@ -373,7 +379,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
case 'L':
if (g_ascii_strcasecmp (headern, NO_LOG_HEADER) == 0) {
if (g_ascii_strcasecmp (h->value->str, "no") == 0) {
- task->no_log = TRUE;
+ task->flags |= RSPAMD_TASK_FLAG_NO_LOG;
}
}
else {
@@ -418,17 +424,22 @@ rspamd_protocol_handle_request (struct rspamd_task *task,
if (msg->method == HTTP_SYMBOLS) {
task->cmd = CMD_SYMBOLS;
- task->is_json = FALSE;
+ task->flags &= ~RSPAMD_TASK_FLAG_JSON;
}
else if (msg->method == HTTP_CHECK) {
task->cmd = CMD_CHECK;
- task->is_json = FALSE;
+ task->flags &= ~RSPAMD_TASK_FLAG_JSON;
}
else {
- task->is_json = TRUE;
+ task->flags |= RSPAMD_TASK_FLAG_JSON;
ret = rspamd_protocol_handle_url (task, msg);
}
+ if (msg->flags & RSPAMD_HTTP_FLAG_SPAMC) {
+ task->flags &= ~RSPAMD_TASK_FLAG_JSON;
+ task->flags |= RSPAMD_TASK_FLAG_SPAMC;
+ }
+
return ret;
}
@@ -474,7 +485,7 @@ urls_protocol_cb (gpointer key, gpointer value, gpointer ud)
struct rspamd_url *url = value;
ucl_object_t *obj, *elt;
- if (!cb->task->extended_urls) {
+ if (!(cb->task->flags & RSPAMD_TASK_FLAG_EXT_URLS)) {
obj = ucl_object_fromlstring (url->host, url->hostlen);
}
else {
@@ -503,7 +514,7 @@ urls_protocol_cb (gpointer key, gpointer value, gpointer ud)
cb->task->message_id,
cb->task->user ?
cb->task->user : "unknown",
- rspamd_inet_address_to_string (&cb->task->from_addr),
+ rspamd_inet_address_to_string (cb->task->from_addr),
struri (url));
}
@@ -666,7 +677,7 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
action = mres->action;
is_spam = (action == METRIC_ACTION_REJECT);
- if (task->is_skipped) {
+ if (RSPAMD_TASK_IS_SKIPPED (task)) {
action_char = 'S';
}
else if (is_spam) {
@@ -684,7 +695,7 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
obj = ucl_object_typed_new (UCL_OBJECT);
ucl_object_insert_key (obj, ucl_object_frombool (is_spam),
"is_spam", 0, false);
- ucl_object_insert_key (obj, ucl_object_frombool (task->is_skipped),
+ ucl_object_insert_key (obj, ucl_object_frombool (RSPAMD_TASK_IS_SKIPPED (task)),
"is_skipped", 0, false);
ucl_object_insert_key (obj, ucl_object_fromdouble (mres->score),
"score", 0, false);
@@ -728,7 +739,7 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
}
static void
-rspamd_ucl_tolegacy_output (struct rspamd_task *task,
+rspamd_ucl_torspamc_output (struct rspamd_task *task,
ucl_object_t *top,
GString *out)
{
@@ -786,6 +797,40 @@ rspamd_ucl_tolegacy_output (struct rspamd_task *task,
g_string_append_printf (out, "Message-ID: %s\r\n", task->message_id);
}
+static void
+rspamd_ucl_tospamc_output (struct rspamd_task *task,
+ ucl_object_t *top,
+ GString *out)
+{
+ const ucl_object_t *metric, *score,
+ *required_score, *is_spam, *elt;
+ ucl_object_iter_t iter = NULL;
+
+ metric = ucl_object_find_key (top, DEFAULT_METRIC);
+ if (metric != NULL) {
+ score = ucl_object_find_key (metric, "score");
+ required_score = ucl_object_find_key (metric, "required_score");
+ is_spam = ucl_object_find_key (metric, "is_spam");
+ g_string_append_printf (out,
+ "Spam: %s ; %.2f / %.2f\r\n\r\n",
+ ucl_object_toboolean (is_spam) ? "True" : "False",
+ ucl_object_todouble (score),
+ ucl_object_todouble (required_score));
+
+ while ((elt = ucl_iterate_object (metric, &iter, true)) != NULL) {
+ if (elt->type == UCL_OBJECT) {
+ g_string_append_printf (out, "%s,",
+ ucl_object_key (elt));
+ }
+ }
+ /* Ugly hack, but the whole spamc is ugly */
+ if (out->str[out->len - 1] == ',') {
+ g_string_truncate (out, out->len - 1);
+ g_string_append (out, CRLF);
+ }
+ }
+}
+
void
rspamd_protocol_http_reply (struct rspamd_http_message *msg,
struct rspamd_task *task)
@@ -809,7 +854,7 @@ rspamd_protocol_http_reply (struct rspamd_http_message *msg,
rspamd_printf_gstring (logbuf, "user: %s, ", task->user);
}
- if (!task->no_log) {
+ if (!(task->flags & RSPAMD_TASK_FLAG_NO_LOG)) {
rspamd_roll_history_update (task->worker->srv->history, task);
}
@@ -848,18 +893,23 @@ rspamd_protocol_http_reply (struct rspamd_http_message *msg,
"message-id", 0, false);
write_hashes_to_log (task, logbuf);
- if (!task->no_log) {
+ if (!(task->flags & RSPAMD_TASK_FLAG_NO_LOG)) {
msg_info ("%v", logbuf);
}
g_string_free (logbuf, TRUE);
msg->body = g_string_sized_new (BUFSIZ);
- if (msg->method < HTTP_SYMBOLS) {
+ if (msg->method < HTTP_SYMBOLS && !RSPAMD_TASK_IS_SPAMC (task)) {
rspamd_ucl_emit_gstring (top, UCL_EMIT_JSON_COMPACT, msg->body);
}
else {
- rspamd_ucl_tolegacy_output (task, top, msg->body);
+ if (RSPAMD_TASK_IS_SPAMC (task)) {
+ rspamd_ucl_tospamc_output (task, top, msg->body);
+ }
+ else {
+ rspamd_ucl_torspamc_output (task, top, msg->body);
+ }
}
ucl_object_unref (top);
@@ -889,10 +939,14 @@ rspamd_protocol_write_reply (struct rspamd_task *task)
msg->peer_key = rspamd_http_connection_key_ref (task->peer_key);
msg_info ("<%s> writing encrypted reply", task->message_id);
}
- if (!task->is_json) {
+ if (!RSPAMD_TASK_IS_JSON (task)) {
/* Turn compatibility on */
msg->method = HTTP_SYMBOLS;
}
+ if (RSPAMD_TASK_IS_SPAMC (task)) {
+ msg->flags |= RSPAMD_HTTP_FLAG_SPAMC;
+ }
+
msg->date = time (NULL);
task->state = WRITING_REPLY;
diff --git a/src/libserver/roll_history.c b/src/libserver/roll_history.c
index 5edf5bea0..2f5c5ddb3 100644
--- a/src/libserver/roll_history.c
+++ b/src/libserver/roll_history.c
@@ -27,6 +27,7 @@
#include "main.h"
#include "roll_history.h"
+static const gchar rspamd_history_magic[] = {'r', 's', 'h', '1'};
/**
* Returns new roll history
@@ -108,7 +109,9 @@ rspamd_roll_history_update (struct roll_history *history,
}
/* Add information from task to roll history */
- memcpy (&row->from_addr, &task->from_addr, sizeof (row->from_addr));
+ rspamd_strlcpy (row->from_addr,
+ rspamd_inet_address_to_string (task->from_addr),
+ sizeof (row->from_addr));
memcpy (&row->tv, &task->tv, sizeof (row->tv));
/* Strings */
@@ -161,6 +164,7 @@ rspamd_roll_history_load (struct roll_history *history, const gchar *filename)
{
gint fd;
struct stat st;
+ gchar magic[sizeof(rspamd_history_magic)];
if (stat (filename, &st) == -1) {
msg_info ("cannot load history from %s: %s", filename,
@@ -168,7 +172,7 @@ rspamd_roll_history_load (struct roll_history *history, const gchar *filename)
return FALSE;
}
- if (st.st_size != sizeof (history->rows)) {
+ if (st.st_size != sizeof (history->rows) + sizeof (rspamd_history_magic)) {
msg_info ("cannot load history from %s: size mismatch", filename);
return FALSE;
}
@@ -179,6 +183,19 @@ rspamd_roll_history_load (struct roll_history *history, const gchar *filename)
return FALSE;
}
+ if (read (fd, magic, sizeof (magic)) == -1) {
+ close (fd);
+ msg_info ("cannot read history from %s: %s", filename,
+ strerror (errno));
+ return FALSE;
+ }
+
+ if (memcmp (magic, rspamd_history_magic, sizeof (magic)) != 0) {
+ close (fd);
+ msg_info ("cannot read history from %s: bad magic", filename);
+ return FALSE;
+ }
+
if (read (fd, history->rows, sizeof (history->rows)) == -1) {
close (fd);
msg_info ("cannot read history from %s: %s", filename,
@@ -207,6 +224,12 @@ rspamd_roll_history_save (struct roll_history *history, const gchar *filename)
return FALSE;
}
+ if (write (fd, rspamd_history_magic, sizeof (rspamd_history_magic)) == -1) {
+ close (fd);
+ msg_info ("cannot write history to %s: %s", filename, strerror (errno));
+ return FALSE;
+ }
+
if (write (fd, history->rows, sizeof (history->rows)) == -1) {
close (fd);
msg_info ("cannot write history to %s: %s", filename, strerror (errno));
diff --git a/src/libserver/roll_history.h b/src/libserver/roll_history.h
index d4034202c..2e8e1e5cd 100644
--- a/src/libserver/roll_history.h
+++ b/src/libserver/roll_history.h
@@ -36,6 +36,7 @@
#define HISTORY_MAX_ID 100
#define HISTORY_MAX_SYMBOLS 200
#define HISTORY_MAX_USER 20
+#define HISTORY_MAX_ADDR 32
#define HISTORY_MAX_ROWS 200
struct rspamd_task;
@@ -45,7 +46,7 @@ struct roll_history_row {
gchar message_id[HISTORY_MAX_ID];
gchar symbols[HISTORY_MAX_SYMBOLS];
gchar user[HISTORY_MAX_USER];
- rspamd_inet_addr_t from_addr;
+ gchar from_addr[HISTORY_MAX_ADDR];
gsize len;
guint scan_time;
gint action;
diff --git a/src/libserver/spf.c b/src/libserver/spf.c
index 5868584a6..13eff0c27 100644
--- a/src/libserver/spf.c
+++ b/src/libserver/spf.c
@@ -825,7 +825,7 @@ parse_spf_ptr (struct rspamd_task *task,
cb->ptr_host = host;
ptr =
rdns_generate_ptr_from_str (rspamd_inet_address_to_string (
- &task->from_addr));
+ task->from_addr));
if (ptr == NULL) {
return FALSE;
}
@@ -1259,16 +1259,10 @@ expand_spf_macro (struct rspamd_task *task, struct spf_record *rec,
/* Read macro name */
switch (g_ascii_tolower (*p)) {
case 'i':
-#ifdef HAVE_INET_PTON
len = rspamd_strlcpy (ip_buf,
- rspamd_inet_address_to_string (&task->from_addr),
+ rspamd_inet_address_to_string (task->from_addr),
sizeof (ip_buf));
memcpy (c, ip_buf, len);
-#else
- tmp = inet_ntoa (task->from_addr);
- len = strlen (tmp);
- memcpy (c, tmp, len);
-#endif
c += len;
break;
case 's':
diff --git a/src/libserver/task.c b/src/libserver/task.c
index b43438a27..f6eeef2b1 100644
--- a/src/libserver/task.c
+++ b/src/libserver/task.c
@@ -50,7 +50,9 @@ rspamd_task_new (struct rspamd_worker *worker)
new_task->state = READ_MESSAGE;
if (worker) {
new_task->cfg = worker->srv->cfg;
- new_task->pass_all_filters = new_task->cfg->check_all_filters;
+ if (new_task->cfg->check_all_filters) {
+ new_task->flags |= RSPAMD_TASK_FLAG_PASS_ALL;
+ }
}
#ifdef HAVE_CLOCK_GETTIME
# ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
@@ -99,8 +101,7 @@ rspamd_task_new (struct rspamd_worker *worker)
(rspamd_mempool_destruct_t) g_tree_destroy,
new_task->urls);
new_task->sock = -1;
- new_task->is_mime = TRUE;
- new_task->is_json = TRUE;
+ new_task->flags |= (RSPAMD_TASK_FLAG_MIME|RSPAMD_TASK_FLAG_JSON);
new_task->pre_result.action = METRIC_ACTION_NOACTION;
new_task->message_id = new_task->queue_id = "undef";
@@ -182,7 +183,7 @@ rspamd_task_fin (void *arg)
return TRUE;
}
/* Add task to classify to classify pool */
- if (!task->is_skipped && task->classify_pool) {
+ if (!RSPAMD_TASK_IS_SKIPPED (task) && task->classify_pool) {
register_async_thread (task->s);
g_thread_pool_push (task->classify_pool, task, &err);
if (err != NULL) {
@@ -191,7 +192,7 @@ rspamd_task_fin (void *arg)
g_error_free (err);
}
}
- if (task->is_skipped) {
+ if (RSPAMD_TASK_IS_SKIPPED (task)) {
rspamd_task_reply (task);
}
else {
@@ -212,7 +213,8 @@ rspamd_task_restore (void *arg)
struct rspamd_task *task = (struct rspamd_task *) arg;
/* Call post filters */
- if (task->state == WAIT_POST_FILTER && !task->skip_extra_filters) {
+ if (task->state == WAIT_POST_FILTER &&
+ !(task->flags & RSPAMD_TASK_FLAG_SKIP_EXTRA)) {
rspamd_lua_call_post_filters (task);
}
task->s->wanna_die = TRUE;
@@ -272,6 +274,12 @@ rspamd_task_free (struct rspamd_task *task, gboolean is_soft)
if (task->peer_key != NULL) {
rspamd_http_connection_key_unref (task->peer_key);
}
+ if (task->client_addr) {
+ rspamd_inet_address_destroy (task->client_addr);
+ }
+ if (task->from_addr) {
+ rspamd_inet_address_destroy (task->from_addr);
+ }
rspamd_mempool_delete (task->task_pool);
g_slice_free1 (sizeof (struct rspamd_task), task);
}
@@ -320,7 +328,9 @@ rspamd_task_process (struct rspamd_task *task,
task->state = WRITE_REPLY;
return FALSE;
}
- task->skip_extra_filters = !process_extra_filters;
+ if (!process_extra_filters) {
+ task->flags |= RSPAMD_TASK_FLAG_SKIP_EXTRA;
+ }
if (!process_extra_filters || task->cfg->pre_filters == NULL) {
r = rspamd_process_filters (task);
if (r == -1) {
@@ -330,7 +340,7 @@ rspamd_task_process (struct rspamd_task *task,
return FALSE;
}
/* Add task to classify to classify pool */
- if (!task->is_skipped && classify_pool) {
+ if (!RSPAMD_TASK_IS_SKIPPED (task) && classify_pool) {
register_async_thread (task->s);
g_thread_pool_push (classify_pool, task, &err);
if (err != NULL) {
@@ -342,7 +352,7 @@ rspamd_task_process (struct rspamd_task *task,
task->classify_pool = classify_pool;
}
}
- if (task->is_skipped) {
+ if (RSPAMD_TASK_IS_SKIPPED (task)) {
/* Call write_socket to write reply and exit */
task->state = WRITE_REPLY;
}
diff --git a/src/libserver/task.h b/src/libserver/task.h
index 135e8bf92..799182f01 100644
--- a/src/libserver/task.h
+++ b/src/libserver/task.h
@@ -51,6 +51,19 @@ enum rspamd_metric_action {
METRIC_ACTION_MAX
};
+#define RSPAMD_TASK_FLAG_MIME (1 << 0)
+#define RSPAMD_TASK_FLAG_JSON (1 << 1)
+#define RSPAMD_TASK_FLAG_SKIP_EXTRA (1 << 2)
+#define RSPAMD_TASK_FLAG_SKIP (1 << 3)
+#define RSPAMD_TASK_FLAG_EXT_URLS (1 << 4)
+#define RSPAMD_TASK_FLAG_SPAMC (1 << 5)
+#define RSPAMD_TASK_FLAG_PASS_ALL (1 << 6)
+#define RSPAMD_TASK_FLAG_NO_LOG (1 << 7)
+
+#define RSPAMD_TASK_IS_SKIPPED(task) (((task)->flags & RSPAMD_TASK_FLAG_SKIP))
+#define RSPAMD_TASK_IS_JSON(task) (((task)->flags & RSPAMD_TASK_FLAG_JSON))
+#define RSPAMD_TASK_IS_SPAMC(task) (((task)->flags & RSPAMD_TASK_FLAG_SPAMC))
+
typedef gint (*protocol_reply_func)(struct rspamd_task *task);
struct custom_command {
@@ -75,18 +88,14 @@ struct rspamd_task {
enum rspamd_command cmd; /**< command */
struct custom_command *custom_cmd; /**< custom command if any */
gint sock; /**< socket descriptor */
- gboolean is_mime; /**< if this task is mime task */
- gboolean is_json; /**< output is JSON */
- gboolean skip_extra_filters; /**< skip pre and post filters */
- gboolean is_skipped; /**< whether message was skipped by configuration */
- gboolean extended_urls; /**< output URLs in details */
+ gint flags;
gchar *helo; /**< helo header value */
gchar *queue_id; /**< queue id if specified */
const gchar *message_id; /**< message id */
- rspamd_inet_addr_t from_addr; /**< from addr for a task */
- rspamd_inet_addr_t client_addr; /**< address of connected socket */
+ rspamd_inet_addr_t *from_addr; /**< from addr for a task */
+ rspamd_inet_addr_t *client_addr; /**< address of connected socket */
gchar *deliver_to; /**< address to deliver */
gchar *user; /**< user to deliver */
gchar *subject; /**< subject (for non-mime) */
@@ -131,8 +140,6 @@ struct rspamd_task {
#endif
struct timeval tv; /**< time of connection */
guint32 scan_milliseconds; /**< how much milliseconds passed */
- gboolean pass_all_filters; /**< pass task throught every rule */
- gboolean no_log; /**< do not log or write this task to the history */
guint32 parser_recursion; /**< for avoiding recursion stack overflow */
gboolean (*fin_callback)(void *arg); /**< calback for filters finalizing */
void *fin_arg; /**< argument for fin callback */
diff --git a/src/libserver/url.c b/src/libserver/url.c
index bdb59f699..a3dbf92f4 100644
--- a/src/libserver/url.c
+++ b/src/libserver/url.c
@@ -1247,6 +1247,9 @@ rspamd_web_parse (struct http_parser_url *u, const gchar *str, gsize len,
}
else if (!is_urlsafe (t)) {
if (strict) {
+ if (g_ascii_isspace (t)) {
+ goto set;
+ }
goto out;
}
else {
@@ -1265,6 +1268,9 @@ rspamd_web_parse (struct http_parser_url *u, const gchar *str, gsize len,
}
else if (!is_urlsafe (t)) {
if (strict) {
+ if (g_ascii_isspace (t)) {
+ goto set;
+ }
goto out;
}
else {
@@ -1276,6 +1282,9 @@ rspamd_web_parse (struct http_parser_url *u, const gchar *str, gsize len,
case parse_part:
if (!is_urlsafe (t)) {
if (strict) {
+ if (g_ascii_isspace (t)) {
+ goto set;
+ }
goto out;
}
else {
@@ -1352,6 +1361,7 @@ rspamd_url_parse (struct rspamd_url *uri, gchar *uristring, gsize len,
{
struct http_parser_url u;
gchar *p, *comp;
+ const gchar *end;
guint i, complen, ret;
const struct {
@@ -1403,20 +1413,27 @@ rspamd_url_parse (struct rspamd_url *uri, gchar *uristring, gsize len,
if (len > sizeof ("mailto:") - 1) {
/* For mailto: urls we also need to add slashes to make it a valid URL */
if (g_ascii_strncasecmp (p, "mailto:", sizeof ("mailto:") - 1) == 0) {
- ret = rspamd_mailto_parse (&u, uristring, len, NULL);
+ ret = rspamd_mailto_parse (&u, uristring, len, &end);
}
else {
- ret = rspamd_web_parse (&u, uristring, len, NULL, TRUE);
+ ret = rspamd_web_parse (&u, uristring, len, &end, TRUE);
}
}
else {
- ret = rspamd_web_parse (&u, uristring, len, NULL, TRUE);
+ ret = rspamd_web_parse (&u, uristring, len, &end, TRUE);
}
if (ret != 0) {
return URI_ERRNO_BAD_FORMAT;
}
+ if (end > uristring && (guint)(end - uristring) != len) {
+ /* We have extra data at the end of uri, so we are ignoring it for now */
+ p = rspamd_mempool_alloc (pool, end - uristring + 1);
+ rspamd_strlcpy (p, uristring, end - uristring + 1);
+ len = end - uristring ;
+ }
+
for (i = 0; i < UF_MAX; i ++) {
if (u.field_set & (1 << i)) {
comp = p + u.field_data[i].off;
@@ -1725,8 +1742,8 @@ url_email_end (const gchar *begin,
/* Strip strange symbols at the end */
if (got_at) {
- while ((!is_domain (*p) || *p == '.' || *p == '_') &&
- p >= match->m_begin) {
+ while (p >= match->m_begin &&
+ (!is_domain (*p) || *p == '.' || *p == '_')) {
p --;
}
p ++;
diff --git a/src/libutil/addr.c b/src/libutil/addr.c
index 3c4db3c8f..2db961574 100644
--- a/src/libutil/addr.c
+++ b/src/libutil/addr.c
@@ -32,28 +32,108 @@ enum {
RSPAMD_IPV6_UNSUPPORTED
} ipv6_status = RSPAMD_IPV6_UNDEFINED;
+/**
+ * Union that is used for storing sockaddrs
+ */
+union sa_union {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+ struct sockaddr_un su;
+ struct sockaddr_storage ss;
+};
+
+union sa_inet {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+};
+
+struct rspamd_addr_unix {
+ struct sockaddr_un addr;
+ gint mode;
+ uid_t owner;
+ gid_t group;
+};
+
+struct rspamd_addr_inet {
+ union sa_inet addr;
+};
+
+struct rspamd_inet_addr_s {
+ union {
+ struct rspamd_addr_inet in;
+ struct rspamd_addr_unix *un;
+ } u;
+ gint af;
+ socklen_t slen;
+};
static void
rspamd_ip_validate_af (rspamd_inet_addr_t *addr)
{
- if (addr->addr.sa.sa_family != addr->af) {
- addr->addr.sa.sa_family = addr->af;
+ if (addr->af != AF_UNIX) {
+ if (addr->u.in.addr.sa.sa_family != addr->af) {
+ addr->u.in.addr.sa.sa_family = addr->af;
+ }
+ }
+ else {
+ addr->u.un->addr.sun_family = AF_UNIX;
}
+
if (addr->af == AF_INET) {
- addr->slen = sizeof (addr->addr.s4);
+ addr->slen = sizeof (struct sockaddr_in);
}
else if (addr->af == AF_INET6) {
- addr->slen = sizeof (addr->addr.s6);
+ addr->slen = sizeof (struct sockaddr_in6);
}
else if (addr->af == AF_UNIX) {
#ifdef SUN_LEN
- addr->slen = SUN_LEN (&addr->addr.su);
+ addr->slen = SUN_LEN (&addr->u.un->addr);
#else
- addr->slen = sizeof (addr->addr.su);
+ addr->slen = sizeof (addr->u.un->addr);
+#endif
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = addr->slen;
#endif
}
}
+
+static rspamd_inet_addr_t *
+rspamd_inet_addr_create (gint af)
+{
+ rspamd_inet_addr_t *addr;
+
+ addr = g_slice_alloc0 (sizeof (rspamd_inet_addr_t));
+
+ if (af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ addr->slen = sizeof (addr->u.un->addr);
+ /* Zero terminate to avoid issues with SUN_LEN */
+ addr->u.un->addr.sun_path[0] = '\0';
+ }
+
+ addr->af = af;
+
+ rspamd_ip_validate_af (addr);
+
+ return addr;
+}
+
+void
+rspamd_inet_address_destroy (rspamd_inet_addr_t *addr)
+{
+ if (addr) {
+ if (addr->af == AF_UNIX) {
+ if (addr->u.un) {
+ g_slice_free1 (sizeof (*addr->u.un), addr->u.un);
+ }
+ }
+ g_slice_free1 (sizeof (rspamd_inet_addr_t), addr);
+ }
+}
+
static void
rspamd_ip_check_ipv6 (void)
{
@@ -90,22 +170,22 @@ rspamd_ip_check_ipv6 (void)
}
gboolean
-rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
+rspamd_ip_is_valid (const rspamd_inet_addr_t *addr)
{
const struct in_addr ip4_any = { INADDR_ANY }, ip4_none = { INADDR_NONE };
const struct in6_addr ip6_any = IN6ADDR_ANY_INIT;
gboolean ret = FALSE;
if (G_LIKELY (addr->af == AF_INET)) {
- if (memcmp (&addr->addr.s4.sin_addr, &ip4_any,
+ if (memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_any,
sizeof (struct in_addr)) != 0 &&
- memcmp (&addr->addr.s4.sin_addr, &ip4_none,
+ memcmp (&addr->u.in.addr.s4.sin_addr, &ip4_none,
sizeof (struct in_addr)) != 0) {
ret = TRUE;
}
}
else if (G_UNLIKELY (addr->af == AF_INET6)) {
- if (memcmp (&addr->addr.s6.sin6_addr, &ip6_any,
+ if (memcmp (&addr->u.in.addr.s6.sin6_addr, &ip6_any,
sizeof (struct in6_addr)) != 0) {
ret = TRUE;
}
@@ -115,20 +195,34 @@ rspamd_ip_is_valid (rspamd_inet_addr_t *addr)
}
gint
-rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
+rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t **target)
{
gint nfd, serrno;
- socklen_t len = sizeof (addr->addr.ss);
+ union sa_union su;
+ socklen_t len = sizeof (su);
+ rspamd_inet_addr_t *addr = NULL;
+
+ if ((nfd = accept (sock, &su.sa, &len)) == -1) {
+ if (target) {
+ *target = NULL;
+ }
- if ((nfd = accept (sock, &addr->addr.sa, &len)) == -1) {
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
return 0;
}
return -1;
}
+ addr = rspamd_inet_addr_create (su.sa.sa_family);
addr->slen = len;
- addr->af = addr->addr.sa.sa_family;
+
+ if (addr->af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+ }
+ else {
+ memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+ }
if (rspamd_socket_nonblocking (nfd) < 0) {
goto out;
@@ -140,37 +234,48 @@ rspamd_accept_from_socket (gint sock, rspamd_inet_addr_t *addr)
goto out;
}
+ if (target) {
+ *target = addr;
+ }
+ else {
+ /* Avoid leak */
+ rspamd_inet_address_destroy (addr);
+ }
+
return (nfd);
out:
serrno = errno;
close (nfd);
errno = serrno;
+ rspamd_inet_address_destroy (addr);
+
return (-1);
}
static gboolean
-rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_unix_path (rspamd_inet_addr_t **target, const char *src)
{
gchar **tokens, **cur_tok, *p, *pwbuf;
gint pwlen;
struct passwd pw, *ppw;
struct group gr, *pgr;
+ rspamd_inet_addr_t *addr;
tokens = g_strsplit_set (src, " ", -1);
- target->af = AF_UNIX;
- target->slen = sizeof (target->addr.su);
- rspamd_strlcpy (target->addr.su.sun_path, tokens[0],
- sizeof (target->addr.su.sun_path));
- #ifdef FREEBSD
- target->addr.su.sun_len = SUN_LEN (&target->addr.su);
+ addr = rspamd_inet_addr_create (AF_UNIX);
+
+ rspamd_strlcpy (addr->u.un->addr.sun_path, tokens[0],
+ sizeof (addr->u.un->addr.sun_path));
+ #if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
#endif
- target->mode = 00644;
- target->owner = 0;
- target->group = 0;
+ addr->u.un->mode = 00644;
+ addr->u.un->mode = 0;
+ addr->u.un->group = 0;
cur_tok = &tokens[1];
pwlen = sysconf (_SC_GETPW_R_SIZE_MAX);
@@ -181,12 +286,12 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (g_ascii_strncasecmp (*cur_tok, "mode=", sizeof ("mode=") - 1) == 0) {
p = strchr (*cur_tok, '=');
/* XXX: add error check */
- target->mode = strtoul (p + 1, NULL, 0);
+ addr->u.un->mode = strtoul (p + 1, NULL, 0);
- if (target->mode == 0) {
+ if (addr->u.un->mode == 0) {
msg_err ("bad mode: %s", p + 1);
errno = EINVAL;
- return FALSE;
+ goto err;
}
}
else if (g_ascii_strncasecmp (*cur_tok, "owner=",
@@ -198,10 +303,10 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (ppw == NULL) {
errno = ENOENT;
}
- return FALSE;
+ goto err;
}
- target->owner = pw.pw_uid;
- target->group = pw.pw_gid;
+ addr->u.un->owner = pw.pw_uid;
+ addr->u.un->group = pw.pw_gid;
}
else if (g_ascii_strncasecmp (*cur_tok, "group=",
sizeof ("group=") - 1) == 0) {
@@ -212,70 +317,92 @@ rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
if (pgr == NULL) {
errno = ENOENT;
}
- return FALSE;
+ goto err;
}
- target->group = gr.gr_gid;
+ addr->u.un->group = gr.gr_gid;
}
cur_tok ++;
}
+ if (target) {
+ rspamd_ip_validate_af (addr);
+ *target = addr;
+ }
+ else {
+ rspamd_inet_address_destroy (addr);
+ }
+
return TRUE;
+
+err:
+
+ rspamd_inet_address_destroy (addr);
+ return FALSE;
}
gboolean
-rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
+rspamd_parse_inet_address (rspamd_inet_addr_t **target, const char *src)
{
gboolean ret = FALSE;
+ rspamd_inet_addr_t *addr = NULL;
+ union sa_inet su;
+
+ g_assert (src != NULL);
+ g_assert (target != NULL);
rspamd_ip_check_ipv6 ();
if (src[0] == '/' || src[0] == '.') {
return rspamd_parse_unix_path (target, src);
}
- else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
- inet_pton (AF_INET6, src, &target->addr.s6.sin6_addr) == 1) {
- target->af = AF_INET6;
- target->slen = sizeof (target->addr.s6);
+ else if (inet_pton (AF_INET, src, &su.s4.sin_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET);
+ memcpy (&addr->u.in.addr.s4.sin_addr, &su.s4.sin_addr,
+ sizeof (struct in_addr));
ret = TRUE;
}
- else if (inet_pton (AF_INET, src, &target->addr.s4.sin_addr) == 1) {
- target->af = AF_INET;
- target->slen = sizeof (target->addr.s4);
+ else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
+ inet_pton (AF_INET6, src, &su.s6.sin6_addr) == 1) {
+ addr = rspamd_inet_addr_create (AF_INET6);
+ memcpy (&addr->u.in.addr.s6.sin6_addr, &su.s6.sin6_addr,
+ sizeof (struct in6_addr));
ret = TRUE;
}
- target->addr.sa.sa_family = target->af;
+ if (ret && target) {
+ *target = addr;
+ }
return ret;
}
const char *
-rspamd_inet_address_to_string (rspamd_inet_addr_t *addr)
+rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr)
{
static char addr_str[INET6_ADDRSTRLEN + 1];
switch (addr->af) {
case AF_INET:
- return inet_ntop (addr->af, &addr->addr.s4.sin_addr, addr_str,
+ return inet_ntop (addr->af, &addr->u.in.addr.s4.sin_addr, addr_str,
sizeof (addr_str));
case AF_INET6:
- return inet_ntop (addr->af, &addr->addr.s6.sin6_addr, addr_str,
+ return inet_ntop (addr->af, &addr->u.in.addr.s6.sin6_addr, addr_str,
sizeof (addr_str));
case AF_UNIX:
- return addr->addr.su.sun_path;
+ return addr->u.un->addr.sun_path;
}
return "undefined";
}
uint16_t
-rspamd_inet_address_get_port (rspamd_inet_addr_t *addr)
+rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr)
{
switch (addr->af) {
case AF_INET:
- return ntohs (addr->addr.s4.sin_port);
+ return ntohs (addr->u.in.addr.s4.sin_port);
case AF_INET6:
- return ntohs (addr->addr.s6.sin6_port);
+ return ntohs (addr->u.in.addr.s6.sin6_port);
}
return 0;
@@ -286,32 +413,38 @@ rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port)
{
switch (addr->af) {
case AF_INET:
- addr->addr.s4.sin_port = htons (port);
+ addr->u.in.addr.s4.sin_port = htons (port);
break;
case AF_INET6:
- addr->addr.s6.sin6_port = htons (port);
+ addr->u.in.addr.s6.sin6_port = htons (port);
break;
}
}
int
-rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
gboolean async)
{
int fd, r;
+ const struct sockaddr *sa;
if (addr == NULL) {
return -1;
}
- rspamd_ip_validate_af (addr);
-
fd = rspamd_socket_create (addr->af, type, 0, async);
if (fd == -1) {
return -1;
}
- r = connect (fd, &addr->addr.sa, addr->slen);
+ if (addr->af == AF_UNIX) {
+ sa = (const struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
+ }
+
+ r = connect (fd, sa, addr->slen);
if (r == -1) {
if (!async || errno != EINPROGRESS) {
@@ -326,29 +459,46 @@ rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
}
int
-rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
gboolean async)
{
gint fd, r;
gint on = 1;
+ const struct sockaddr *sa;
+ const char *path;
if (addr == NULL) {
return -1;
}
- rspamd_ip_validate_af (addr);
fd = rspamd_socket_create (addr->af, type, 0, async);
if (fd == -1) {
return -1;
}
- if (addr->af == AF_UNIX && access (addr->addr.su.sun_path, W_OK) != -1) {
+ if (addr->af == AF_UNIX && access (addr->u.un->addr.sun_path, W_OK) != -1) {
/* Unlink old socket */
- (void)unlink (addr->addr.su.sun_path);
+ (void)unlink (addr->u.un->addr.sun_path);
+ }
+
+ if (addr->af == AF_UNIX) {
+ sa = (const struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
}
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
- r = bind (fd, &addr->addr.sa, addr->slen);
+
+#ifdef HAVE_IPV6_V6ONLY
+ if (addr->af == AF_INET6) {
+ /* We need to set this flag to avoid errors */
+ on = 1;
+ setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, (const void *)&on, sizeof (gint));
+ }
+#endif
+
+ r = bind (fd, sa, addr->slen);
if (r == -1) {
if (!async || errno != EINPROGRESS) {
close (fd);
@@ -361,15 +511,16 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
if (type != SOCK_DGRAM) {
if (addr->af == AF_UNIX) {
+ path = addr->u.un->addr.sun_path;
/* Try to set mode and owner */
- if (chown (addr->addr.su.sun_path, addr->owner, addr->group) == -1) {
+ if (chown (path, addr->u.un->owner, addr->u.un->group) == -1) {
msg_info ("cannot change owner for %s to %d:%d: %s",
- addr->addr.su.sun_path, addr->owner, addr->group,
+ path, addr->u.un->owner, addr->u.un->group,
strerror (errno));
}
- if (chmod (addr->addr.su.sun_path, addr->mode) == -1) {
+ if (chmod (path, addr->u.un->mode) == -1) {
msg_info ("cannot change mode for %s to %od %s",
- addr->addr.su.sun_path, addr->mode, strerror (errno));
+ path, addr->u.un->mode, strerror (errno));
}
}
r = listen (fd, -1);
@@ -384,10 +535,67 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
return fd;
}
+gssize
+rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+ rspamd_inet_addr_t **target)
+{
+ gssize ret;
+ union sa_union su;
+ socklen_t slen = sizeof (su);
+ rspamd_inet_addr_t *addr = NULL;
+
+ if ((ret = recvfrom (fd, buf, len, fl, &su.sa, &slen)) == -1) {
+ if (target) {
+ *target = NULL;
+ }
+
+ return -1;
+ }
+
+ if (target) {
+ addr = rspamd_inet_addr_create (su.sa.sa_family);
+ addr->slen = len;
+
+ if (addr->af == AF_UNIX) {
+ addr->u.un = g_slice_alloc (sizeof (*addr->u.un));
+ memcpy (&addr->u.un->addr, &su.su, sizeof (struct sockaddr_un));
+ }
+ else {
+ memcpy (&addr->u.in.addr, &su, MIN (len, sizeof (addr->u.in.addr)));
+ }
+
+ *target = addr;
+ }
+
+ return (ret);
+}
+
+gssize
+rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+ const rspamd_inet_addr_t *addr)
+{
+ gssize r;
+ const struct sockaddr *sa;
+
+ if (addr == NULL) {
+ return -1;
+ }
+
+ if (addr->af == AF_UNIX) {
+ sa = (struct sockaddr *)&addr->u.un->addr;
+ }
+ else {
+ sa = &addr->u.in.addr.sa;
+ }
+
+ r = sendto (fd, buf, len, fl, sa, addr->slen);
+
+ return r;
+}
+
gboolean
rspamd_parse_host_port_priority_strv (gchar **tokens,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
guint *priority,
gchar **name,
guint default_port,
@@ -476,34 +684,30 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
/* Now copy up to max_addrs of addresses */
addr_cnt = 0;
cur = res;
- while (cur && addr_cnt < *max_addrs) {
+ while (cur) {
cur = cur->ai_next;
addr_cnt ++;
}
- if (pool == NULL) {
- *addr = g_new (rspamd_inet_addr_t, addr_cnt);
- }
- else {
- *addr = rspamd_mempool_alloc (pool, addr_cnt *
- sizeof (rspamd_inet_addr_t));
+ *addrs = g_ptr_array_new_full (addr_cnt,
+ (GDestroyNotify)rspamd_inet_address_destroy);
+
+ if (pool != NULL) {
+ rspamd_mempool_add_destructor (pool,
+ rspamd_ptr_array_free_hard, *addrs);
}
cur = res;
- addr_cnt = 0;
- while (cur && addr_cnt < *max_addrs) {
- cur_addr = &(*addr)[addr_cnt];
- memcpy (&cur_addr->addr, cur->ai_addr,
- MIN (sizeof (cur_addr->addr), cur->ai_addrlen));
- cur_addr->af = cur->ai_family;
- rspamd_ip_validate_af (cur_addr);
- cur_addr->slen = cur->ai_addrlen;
+ 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;
- addr_cnt ++;
}
- *max_addrs = addr_cnt;
-
freeaddrinfo (res);
}
else {
@@ -515,21 +719,22 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
}
else {
/* Special case of unix socket, as getaddrinfo cannot deal with them */
- if (pool == NULL) {
- *addr = g_new0 (rspamd_inet_addr_t, 1);
- }
- else {
- *addr = rspamd_mempool_alloc0 (pool, sizeof (rspamd_inet_addr_t));
+ *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);
}
- cur_addr = *addr;
- if (!rspamd_parse_inet_address (cur_addr, tokens[0])) {
+ if (!rspamd_parse_inet_address (&cur_addr, tokens[0])) {
msg_err ("cannot parse unix socket definition %s: %s",
tokens[0],
strerror (errno));
goto err;
}
- *max_addrs = 1;
+
+ g_ptr_array_add (*addrs, cur_addr);
}
/* Restore errno */
@@ -552,8 +757,7 @@ err:
gboolean
rspamd_parse_host_port_priority (
const gchar *str,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
guint *priority,
gchar **name,
guint default_port,
@@ -567,7 +771,7 @@ rspamd_parse_host_port_priority (
return FALSE;
}
- ret = rspamd_parse_host_port_priority_strv (tokens, addr, max_addrs,
+ ret = rspamd_parse_host_port_priority_strv (tokens, addrs,
priority, name, default_port, pool);
g_strfreev (tokens);
@@ -577,12 +781,214 @@ rspamd_parse_host_port_priority (
gboolean
rspamd_parse_host_port (const gchar *str,
- rspamd_inet_addr_t **addr,
- guint *max_addrs,
+ GPtrArray **addrs,
gchar **name,
guint default_port,
rspamd_mempool_t *pool)
{
- return rspamd_parse_host_port_priority (str, addr, max_addrs, NULL,
+ return rspamd_parse_host_port_priority (str, addrs, NULL,
name, default_port, pool);
}
+
+
+guchar*
+rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen)
+{
+ guchar *res = NULL;
+ static struct in_addr local = {INADDR_LOOPBACK};
+
+ g_assert (addr != NULL);
+ g_assert (klen != NULL);
+
+ if (addr->af == AF_INET) {
+ *klen = sizeof (struct in_addr);
+ res = (guchar *)&addr->u.in.addr.s4.sin_addr;
+ }
+ else if (addr->af == AF_INET6) {
+ *klen = sizeof (struct in6_addr);
+ res = (guchar *)&addr->u.in.addr.s6.sin6_addr;
+ }
+ else if (addr->af == AF_UNIX) {
+ *klen = sizeof (struct in_addr);
+ res = (guchar *)&local;
+ }
+
+ return res;
+}
+
+
+rspamd_inet_addr_t *
+rspamd_inet_address_new (int af, const void *init)
+{
+ rspamd_inet_addr_t *addr;
+
+ addr = rspamd_inet_addr_create (af);
+
+ if (init != NULL) {
+ if (af == AF_UNIX) {
+ /* Init is a path */
+ rspamd_strlcpy (addr->u.un->addr.sun_path, init,
+ sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = SUN_LEN (&addr->u.un->addr);
+#endif
+ }
+ else if (af == AF_INET) {
+ memcpy (&addr->u.in.addr.s4.sin_addr, init, sizeof (struct in_addr));
+ }
+ else if (af == AF_INET6) {
+ memcpy (&addr->u.in.addr.s6.sin6_addr, init, sizeof (struct in6_addr));
+ }
+ }
+
+ return addr;
+}
+
+rspamd_inet_addr_t *
+rspamd_inet_address_from_sa (const struct sockaddr *sa, socklen_t slen)
+{
+ rspamd_inet_addr_t *addr;
+
+ g_assert (sa != NULL);
+ g_assert (slen >= sizeof (struct sockaddr));
+
+ addr = rspamd_inet_addr_create (sa->sa_family);
+
+ if (sa->sa_family == AF_UNIX) {
+ /* Init is a path */
+ const struct sockaddr_un *un = (const struct sockaddr_un *)sa;
+
+ g_assert (slen >= SUN_LEN (un));
+
+ rspamd_strlcpy (addr->u.un->addr.sun_path, un->sun_path,
+ sizeof (addr->u.un->addr.sun_path));
+#if defined(FREEBSD) || defined(__APPLE__)
+ addr->u.un->addr.sun_len = un->sun_len;
+#endif
+ }
+ else if (sa->sa_family == AF_INET) {
+ g_assert (slen >= sizeof (struct sockaddr_in));
+ memcpy (&addr->u.in.addr.s4, sa, sizeof (struct sockaddr_in));
+ }
+ else if (sa->sa_family == AF_INET6) {
+ g_assert (slen >= sizeof (struct sockaddr_in6));
+ memcpy (&addr->u.in.addr.s6, sa, sizeof (struct sockaddr_in6));
+ }
+ else {
+ /* XXX: currently we cannot deal with other AF */
+ g_assert (0);
+ }
+
+ return addr;
+}
+
+void
+rspamd_inet_address_apply_mask (rspamd_inet_addr_t *addr, guint mask)
+{
+ guint32 umsk, *p;
+
+ if (mask > 0 && addr != NULL) {
+ if (addr->af == AF_INET && mask <= 32) {
+ umsk = htonl (G_MAXUINT32 << (32 - mask));
+ addr->u.in.addr.s4.sin_addr.s_addr &= umsk;
+ }
+ else if (addr->af == AF_INET && mask <= 128) {
+ p = (uint32_t *)&addr->u.in.addr.s6.sin6_addr;
+ p += 3;
+ while (mask > 0) {
+ umsk = htonl (G_MAXUINT32 << (32 - (mask > 32 ? 32 : mask)));
+ *p &= umsk;
+ p --;
+ mask -= 32;
+ }
+ }
+ }
+}
+
+static gint
+rspamd_inet_address_af_order (const rspamd_inet_addr_t *addr)
+{
+ int ret;
+
+ switch (addr->af) {
+ case AF_UNIX:
+ ret = 2;
+ break;
+ case AF_INET:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+gint
+rspamd_inet_address_compare (const rspamd_inet_addr_t *a1,
+ const rspamd_inet_addr_t *a2)
+{
+ g_assert (a1 != NULL);
+ g_assert (a2 != NULL);
+
+ if (a1->af != a2->af) {
+ return (rspamd_inet_address_af_order (a2) -
+ rspamd_inet_address_af_order (a1));
+ }
+ else {
+ switch (a1->af) {
+ case AF_INET:
+ return memcmp (&a1->u.in.addr.s4.sin_addr,
+ &a2->u.in.addr.s4.sin_addr, sizeof (struct in_addr));
+ case AF_INET6:
+ return memcmp (&a1->u.in.addr.s6.sin6_addr,
+ &a2->u.in.addr.s6.sin6_addr, sizeof (struct in6_addr));
+ case AF_UNIX:
+ return strncmp (a1->u.un->addr.sun_path,
+ a2->u.un->addr.sun_path, sizeof (a1->u.un->addr.sun_path));
+ default:
+ return memcmp (&a1->u.in, &a2->u.in, sizeof (a1->u.in));
+ }
+ }
+
+ return 0;
+}
+
+gint
+rspamd_inet_address_compare_ptr (const gpointer a1,
+ const gpointer a2)
+{
+ const rspamd_inet_addr_t **i1 = a1, **i2 = a2;
+
+ return rspamd_inet_address_compare (*i1, *i2);
+}
+
+rspamd_inet_addr_t *
+rspamd_inet_address_copy (const rspamd_inet_addr_t *addr)
+{
+ rspamd_inet_addr_t *n;
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ n = rspamd_inet_addr_create (addr->af);
+
+ if (n->af == AF_UNIX) {
+ memcpy (n->u.un, addr->u.un, sizeof (*addr->u.un));
+ }
+ else {
+ memcpy (&n->u.in, &addr->u.in, sizeof (addr->u.in));
+ }
+
+ return n;
+}
+
+gint
+rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr)
+{
+ g_assert (addr != NULL);
+
+ return addr->af;
+}
diff --git a/src/libutil/addr.h b/src/libutil/addr.h
index b5282e34c..1ea0ab8b5 100644
--- a/src/libutil/addr.h
+++ b/src/libutil/addr.h
@@ -27,25 +27,26 @@
#include "mem_pool.h"
/**
- * Union that is used for storing sockaddrs
- */
-union sa_union {
- struct sockaddr_storage ss;
- struct sockaddr sa;
- struct sockaddr_in s4;
- struct sockaddr_in6 s6;
- struct sockaddr_un su;
-};
-
-typedef struct _rspamd_inet_addr_s {
- union sa_union addr;
- socklen_t slen;
- gint af;
- /* Unix socket specific */
- gint mode;
- uid_t owner;
- gid_t group;
-} rspamd_inet_addr_t;
+ * Opaque structure
+ */
+typedef struct rspamd_inet_addr_s rspamd_inet_addr_t;
+
+/**
+ * Create new inet address structure based on the address familiy and opaque init pointer
+ * @param af
+ * @param init
+ * @return new inet addr
+ */
+rspamd_inet_addr_t * rspamd_inet_address_new (int af, const void *init);
+
+/**
+ * Create new inet address structure from struct sockaddr
+ * @param sa
+ * @param slen
+ * @return
+ */
+rspamd_inet_addr_t * rspamd_inet_address_from_sa (const struct sockaddr *sa,
+ socklen_t slen);
/**
* Try to parse address from string
@@ -53,7 +54,7 @@ typedef struct _rspamd_inet_addr_s {
* @param src IP string representation
* @return TRUE if addr has been parsed
*/
-gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
+gboolean rspamd_parse_inet_address (rspamd_inet_addr_t **target,
const char *src);
/**
@@ -61,14 +62,52 @@ gboolean rspamd_parse_inet_address (rspamd_inet_addr_t *target,
* @param addr
* @return statically allocated string pointer (not thread safe)
*/
-const char * rspamd_inet_address_to_string (rspamd_inet_addr_t *addr);
+const char * rspamd_inet_address_to_string (const rspamd_inet_addr_t *addr);
/**
* Returns port number for the specified inet address in host byte order
* @param addr
* @return
*/
-uint16_t rspamd_inet_address_get_port (rspamd_inet_addr_t *addr);
+uint16_t rspamd_inet_address_get_port (const rspamd_inet_addr_t *addr);
+
+/**
+ * Returns address family of inet address
+ * @param addr
+ * @return
+ */
+gint rspamd_inet_address_get_af (const rspamd_inet_addr_t *addr);
+
+
+/**
+ * Makes a radix key from inet address
+ * @param addr
+ * @param klen
+ * @return
+ */
+guchar * rspamd_inet_address_get_radix_key (const rspamd_inet_addr_t *addr, guint *klen);
+
+/**
+ * Receive data from an unconnected socket and fill the inet_addr structure if needed
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return same as recvfrom(2)
+ */
+gssize rspamd_inet_address_recvfrom (gint fd, void *buf, gsize len, gint fl,
+ rspamd_inet_addr_t **target);
+
+/**
+ * Send data via unconnected socket using the specified inet_addr structure
+ * @param fd
+ * @param buf
+ * @param len
+ * @param target
+ * @return
+ */
+gssize rspamd_inet_address_sendto (gint fd, const void *buf, gsize len, gint fl,
+ const rspamd_inet_addr_t *addr);
/**
* Set port for inet address
@@ -81,7 +120,7 @@ void rspamd_inet_address_set_port (rspamd_inet_addr_t *addr, uint16_t port);
* @param async perform operations asynchronously
* @return newly created and connected socket
*/
-int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_connect (const rspamd_inet_addr_t *addr, gint type,
gboolean async);
/**
@@ -91,7 +130,7 @@ int rspamd_inet_address_connect (rspamd_inet_addr_t *addr, gint type,
* @param async
* @return
*/
-int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
+int rspamd_inet_address_listen (const rspamd_inet_addr_t *addr, gint type,
gboolean async);
/**
* Check whether specified ip is valid (not INADDR_ANY or INADDR_NONE) for ipv4 or ipv6
@@ -99,18 +138,18 @@ int rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
* @param af address family (AF_INET or AF_INET6)
* @return TRUE if the address is valid
*/
-gboolean rspamd_ip_is_valid (rspamd_inet_addr_t *addr);
+gboolean rspamd_ip_is_valid (const rspamd_inet_addr_t *addr);
/**
* Accept from listening socket filling addr structure
* @param sock listening socket
- * @param addr
+ * @param addr allocated inet addr structur
* @return
*/
-gint rspamd_accept_from_socket (gint sock, 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,
- rspamd_inet_addr_t **addr, guint *max_addrs, guint *priority,
+ GPtrArray **addrs, guint *priority,
gchar **name, guint default_port, rspamd_mempool_t *pool);
/**
@@ -121,7 +160,7 @@ gboolean rspamd_parse_host_port_priority_strv (gchar **tokens,
* @return TRUE if string was parsed
*/
gboolean rspamd_parse_host_port_priority (const gchar *str,
- rspamd_inet_addr_t **addr, guint *max_addrs,
+ GPtrArray **addrs,
guint *priority, gchar **name, guint default_port,
rspamd_mempool_t *pool);
@@ -132,8 +171,44 @@ gboolean rspamd_parse_host_port_priority (const gchar *str,
* @return TRUE if string was parsed
*/
gboolean rspamd_parse_host_port (const gchar *str,
- rspamd_inet_addr_t **addr, guint *max_addrs,
+ GPtrArray **addrs,
gchar **name, guint default_port, rspamd_mempool_t *pool);
+/**
+ * Destroy the specified IP address
+ * @param addr
+ */
+void rspamd_inet_address_destroy (rspamd_inet_addr_t *addr);
+
+/**
+ * Apply the specified mask to an address (ignored for AF_UNIX)
+ * @param addr
+ * @param mask
+ */
+void rspamd_inet_address_apply_mask (rspamd_inet_addr_t *addr, guint mask);
+
+/**
+ * Compare a1 and a2 and return value >0, ==0 and <0 if a1 is more, equal or less than a2 correspondingly
+ * @param a1
+ * @param a2
+ * @return
+ */
+gint rspamd_inet_address_compare (const rspamd_inet_addr_t *a1,
+ const rspamd_inet_addr_t *a2);
+
+/**
+ * Utility function to compare addresses by in g_ptr_array
+ * @param a1
+ * @param a2
+ * @return
+ */
+gint rspamd_inet_address_compare_ptr (const gpointer a1,
+ const gpointer a2);
+/**
+ * Performs deep copy of rspamd inet addr
+ * @param addr
+ * @return
+ */
+rspamd_inet_addr_t *rspamd_inet_address_copy (const rspamd_inet_addr_t *addr);
#endif /* ADDR_H_ */
diff --git a/src/libutil/http.c b/src/libutil/http.c
index 615f21de6..ba759baf1 100644
--- a/src/libutil/http.c
+++ b/src/libutil/http.c
@@ -558,6 +558,10 @@ rspamd_http_on_headers_complete (http_parser * parser)
priv->msg->body = g_string_sized_new (BUFSIZ);
}
+ if (parser->flags & F_SPAMC) {
+ priv->msg->flags |= RSPAMD_HTTP_FLAG_SPAMC;
+ }
+
priv->msg->body_buf.str = priv->msg->body->str;
priv->msg->method = parser->method;
priv->msg->code = parser->status_code;
@@ -1117,7 +1121,12 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
}
else {
/* Legacy spamd reply */
- rspamd_printf_gstring (buf, "RSPAMD/1.3 0 EX_OK\r\n");
+ if (msg->flags & RSPAMD_HTTP_FLAG_SPAMC) {
+ rspamd_printf_gstring (buf, "SPAMD/1.1 0 EX_OK\r\n");
+ }
+ else {
+ rspamd_printf_gstring (buf, "RSPAMD/1.3 0 EX_OK\r\n");
+ }
}
}
else {
@@ -1250,6 +1259,7 @@ rspamd_http_new_message (enum http_parser_type type)
new->type = type;
new->method = HTTP_GET;
new->peer_key = NULL;
+ new->flags = 0;
return new;
}
diff --git a/src/libutil/http.h b/src/libutil/http.h
index c581cb6f6..eef963f9d 100644
--- a/src/libutil/http.h
+++ b/src/libutil/http.h
@@ -50,6 +50,11 @@ struct rspamd_http_header {
};
/**
+ * Legacy spamc protocol
+ */
+#define RSPAMD_HTTP_FLAG_SPAMC 1 << 1
+
+/**
* HTTP message structure, used for requests and replies
*/
struct rspamd_http_message {
@@ -65,6 +70,7 @@ struct rspamd_http_message {
time_t date;
gint code;
enum http_method method;
+ gint flags;
};
diff --git a/src/libutil/logger.h b/src/libutil/logger.h
index 4b200c83d..14ffa45f0 100644
--- a/src/libutil/logger.h
+++ b/src/libutil/logger.h
@@ -129,7 +129,7 @@ void rspamd_log_nodebug (rspamd_logger_t *logger);
__FUNCTION__, \
__VA_ARGS__)
#define debug_task(...) rspamd_conditional_debug (rspamd_main->logger, \
- &task->from_addr, \
+ task->from_addr, \
__FUNCTION__, \
__VA_ARGS__)
#else
diff --git a/src/libutil/radix.c b/src/libutil/radix.c
index a7ef12375..17b73b6cc 100644
--- a/src/libutil/radix.c
+++ b/src/libutil/radix.c
@@ -870,17 +870,17 @@ radix_destroy_compressed (radix_compressed_t *tree)
uintptr_t
radix_find_compressed_addr (radix_compressed_t *tree, rspamd_inet_addr_t *addr)
{
+ guchar *key;
+ guint klen = 0;
+
if (addr == NULL) {
return RADIX_NO_VALUE;
}
- if (addr->af == AF_INET) {
- return radix_find_compressed (tree, (guint8 *)&addr->addr.s4.sin_addr,
- sizeof (addr->addr.s4.sin_addr));
- }
- else if (addr->af == AF_INET6) {
- return radix_find_compressed (tree, (guint8 *)&addr->addr.s6.sin6_addr,
- sizeof (addr->addr.s6.sin6_addr));
+ key = rspamd_inet_address_get_radix_key (addr, &klen);
+
+ if (key && klen) {
+ return radix_find_compressed (tree, key, klen);
}
return RADIX_NO_VALUE;
diff --git a/src/libutil/upstream.c b/src/libutil/upstream.c
index 61f40d419..6aa447042 100644
--- a/src/libutil/upstream.c
+++ b/src/libutil/upstream.c
@@ -32,7 +32,7 @@
#include "utlist.h"
struct upstream_inet_addr_entry {
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
struct upstream_inet_addr_entry *next;
};
@@ -48,8 +48,7 @@ struct upstream {
struct upstream_list *ls;
struct {
- rspamd_inet_addr_t *addr;
- guint count;
+ GPtrArray *addr;
guint cur;
} addrs;
@@ -76,7 +75,6 @@ static gdouble default_revive_jitter = 0.4;
static gdouble default_error_time = 10;
static gdouble default_dns_timeout = 1.0;
static guint default_dns_retransmits = 2;
-static guint default_max_addresses = 1024;
void
rspamd_upstreams_library_config (struct rspamd_config *cfg)
@@ -111,7 +109,7 @@ rspamd_upstream_af_to_weight (const rspamd_inet_addr_t *addr)
{
int ret;
- switch (addr->af) {
+ switch (rspamd_inet_address_get_af (addr)) {
case AF_UNIX:
ret = 2;
break;
@@ -132,12 +130,12 @@ rspamd_upstream_af_to_weight (const rspamd_inet_addr_t *addr)
static gint
rspamd_upstream_addr_sort_func (gconstpointer a, gconstpointer b)
{
- const rspamd_inet_addr_t *ip1 = (const rspamd_inet_addr_t *)a,
- *ip2 = (const rspamd_inet_addr_t *)b;
+ const rspamd_inet_addr_t **ip1 = (const rspamd_inet_addr_t **)a,
+ **ip2 = (const rspamd_inet_addr_t **)b;
gint w1, w2;
- w1 = rspamd_upstream_af_to_weight (ip1);
- w2 = rspamd_upstream_af_to_weight (ip2);
+ w1 = rspamd_upstream_af_to_weight (*ip1);
+ w2 = rspamd_upstream_af_to_weight (*ip2);
return w2 - w1;
}
@@ -166,21 +164,14 @@ rspamd_upstream_dns_cb (struct rdns_reply *reply, void *arg)
if (entry->type == RDNS_REQUEST_A) {
up_ent = g_malloc0 (sizeof (*up_ent));
-
- up_ent->addr.addr.s4.sin_addr = entry->content.a.addr;
- up_ent->addr.af = AF_INET;
- up_ent->addr.addr.sa.sa_family = AF_INET;
- up_ent->addr.slen = sizeof (up_ent->addr.addr.s4);
+ up_ent->addr = rspamd_inet_address_new (AF_INET,
+ &entry->content.a.addr);
LL_PREPEND (up->new_addrs, up_ent);
}
else if (entry->type == RDNS_REQUEST_AAAA) {
up_ent = g_malloc0 (sizeof (*up_ent));
-
- memcpy (&up_ent->addr.addr.s6.sin6_addr,
- &entry->content.aaa.addr, sizeof (struct in6_addr));
- up_ent->addr.af = AF_INET6;
- up_ent->addr.addr.sa.sa_family = AF_INET6;
- up_ent->addr.slen = sizeof (up_ent->addr.addr.s6);
+ up_ent->addr = rspamd_inet_address_new (AF_INET6,
+ &entry->content.aaa.addr);
LL_PREPEND (up->new_addrs, up_ent);
}
entry = entry->next;
@@ -197,40 +188,39 @@ rspamd_upstream_update_addrs (struct upstream *up)
guint16 port;
guint addr_cnt;
struct upstream_inet_addr_entry *cur, *tmp;
- rspamd_inet_addr_t *new_addrs, *old;
+ GPtrArray *new_addrs;
/*
* We need first of all get the saved port, since DNS gives us no
* idea about what port has been used previously
*/
- if (up->addrs.count > 0 && up->new_addrs) {
- port = rspamd_inet_address_get_port (&up->addrs.addr[0]);
+ if (up->addrs.addr->len > 0 && up->new_addrs) {
+ port = rspamd_inet_address_get_port (g_ptr_array_index (up->addrs.addr, 0));
+
+ /* Free old addresses */
+ g_ptr_array_free (up->addrs.addr, TRUE);
/* Now calculate new addrs count */
addr_cnt = 0;
LL_FOREACH (up->new_addrs, cur) {
addr_cnt ++;
}
- new_addrs = g_new (rspamd_inet_addr_t, addr_cnt);
+ new_addrs = g_ptr_array_new_full (addr_cnt,
+ (GDestroyNotify)rspamd_inet_address_destroy);
/* Copy addrs back */
- addr_cnt = 0;
LL_FOREACH (up->new_addrs, cur) {
- memcpy (&new_addrs[addr_cnt], cur, sizeof (rspamd_inet_addr_t));
- rspamd_inet_address_set_port (&new_addrs[addr_cnt], port);
- addr_cnt ++;
+ rspamd_inet_address_set_port (cur->addr, port);
+ g_ptr_array_add (new_addrs, cur->addr);
}
- old = up->addrs.addr;
up->addrs.cur = 0;
- up->addrs.count = addr_cnt;
up->addrs.addr = new_addrs;
- qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
- rspamd_upstream_addr_sort_func);
- g_free (old);
+ g_ptr_array_sort (up->addrs.addr, rspamd_upstream_addr_sort_func);
}
LL_FOREACH_SAFE (up->new_addrs, cur, tmp) {
+ /* Do not free inet address pointer since it has been transferred to up */
g_free (cur);
}
up->new_addrs = NULL;
@@ -379,13 +369,18 @@ rspamd_upstream_dtor (struct upstream *up)
if (up->new_addrs) {
LL_FOREACH_SAFE(up->new_addrs, cur, tmp) {
+ /* Here we need to free pointer as well */
+ rspamd_inet_address_destroy (cur->addr);
g_free (cur);
}
}
+ if (up->addrs.addr) {
+ g_ptr_array_free (up->addrs.addr, TRUE);
+ }
+
rspamd_mutex_free (up->lock);
g_free (up->name);
- g_free (up->addrs.addr);
g_slice_free1 (sizeof (*up), up);
}
@@ -399,9 +394,10 @@ rspamd_upstream_addr (struct upstream *up)
* many systems now has poorly supported ipv6
*/
idx = up->addrs.cur;
- next_idx = (idx + 1) % up->addrs.count;
- w1 = rspamd_upstream_af_to_weight (&up->addrs.addr[idx]);
- w2 = rspamd_upstream_af_to_weight (&up->addrs.addr[next_idx]);
+ next_idx = (idx + 1) % up->addrs.addr->len;
+ w1 = rspamd_upstream_af_to_weight (g_ptr_array_index (up->addrs.addr, idx));
+ w2 = rspamd_upstream_af_to_weight (g_ptr_array_index (up->addrs.addr,
+ next_idx));
/*
* We don't care about the exact priorities, but we prefer ipv4/unix
@@ -414,7 +410,7 @@ rspamd_upstream_addr (struct upstream *up)
up->addrs.cur = 0;
}
- return &up->addrs.addr[up->addrs.cur];
+ return g_ptr_array_index (up->addrs.addr, up->addrs.cur);
}
const gchar*
@@ -431,9 +427,8 @@ rspamd_upstreams_add_upstream (struct upstream_list *ups,
up = g_slice_alloc0 (sizeof (*up));
- up->addrs.count = default_max_addresses;
if (!rspamd_parse_host_port_priority (str, &up->addrs.addr,
- &up->addrs.count, &up->weight,
+ &up->weight,
&up->name, def_port, NULL)) {
g_slice_free1 (sizeof (*up), up);
return FALSE;
@@ -445,8 +440,7 @@ rspamd_upstreams_add_upstream (struct upstream_list *ups,
up->ls = ups;
REF_INIT_RETAIN (up, rspamd_upstream_dtor);
up->lock = rspamd_mutex_new ();
- qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
- rspamd_upstream_addr_sort_func);
+ g_ptr_array_sort (up->addrs.addr, rspamd_upstream_addr_sort_func);
rspamd_upstream_set_active (ups, up);
@@ -454,19 +448,13 @@ rspamd_upstreams_add_upstream (struct upstream_list *ups,
}
gboolean
-rspamd_upstream_add_addr (struct upstream *up, const rspamd_inet_addr_t *addr)
+rspamd_upstream_add_addr (struct upstream *up, rspamd_inet_addr_t *addr)
{
- gint nsz;
-
/*
* XXX: slow and inefficient
*/
- nsz = ++up->addrs.count;
- up->addrs.addr = g_realloc (up->addrs.addr,
- nsz * sizeof (up->addrs.addr[0]));
- memcpy (&up->addrs.addr[nsz - 1], addr, sizeof (*addr));
- qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
- rspamd_upstream_addr_sort_func);
+ g_ptr_array_add (up->addrs.addr, addr);
+ g_ptr_array_sort (up->addrs.addr, rspamd_upstream_addr_sort_func);
return TRUE;
}
diff --git a/src/libutil/upstream.h b/src/libutil/upstream.h
index 8c399ab03..3fb5d24a5 100644
--- a/src/libutil/upstream.h
+++ b/src/libutil/upstream.h
@@ -118,12 +118,12 @@ gboolean rspamd_upstreams_from_ucl (struct upstream_list *ups,
rspamd_inet_addr_t* rspamd_upstream_addr (struct upstream *up);
/**
- * Add custom address for an upstream
+ * Add custom address for an upstream (ownership of addr is transferred to upstream)
* @param up
* @return
*/
gboolean rspamd_upstream_add_addr (struct upstream *up,
- const rspamd_inet_addr_t *addr);
+ rspamd_inet_addr_t *addr);
/**
* Returns the symbolic name of the upstream
diff --git a/src/libutil/util.c b/src/libutil/util.c
index 4a125c560..9967a18ef 100644
--- a/src/libutil/util.c
+++ b/src/libutil/util.c
@@ -2260,3 +2260,12 @@ randombytes (guchar *buf, guint64 len)
{
ottery_rand_bytes (buf, (size_t)len);
}
+
+
+void
+rspamd_ptr_array_free_hard (gpointer p)
+{
+ GPtrArray *ar = (GPtrArray *)p;
+
+ g_ptr_array_free (ar, TRUE);
+}
diff --git a/src/libutil/util.h b/src/libutil/util.h
index 8e3fe090f..b0825bfbf 100644
--- a/src/libutil/util.h
+++ b/src/libutil/util.h
@@ -441,4 +441,10 @@ guchar* rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen);
*/
gdouble rspamd_get_ticks (void);
+/**
+ * Special utility to help array freeing in rspamd_mempool
+ * @param p
+ */
+void rspamd_ptr_array_free_hard (gpointer p);
+
#endif
diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h
index c9ce21178..ce817d1e1 100644
--- a/src/lua/lua_common.h
+++ b/src/lua/lua_common.h
@@ -146,8 +146,7 @@ int rspamd_lua_typerror (lua_State *L, int narg, const char *tname);
* Lua IP address structure
*/
struct rspamd_lua_ip {
- rspamd_inet_addr_t addr;
- gboolean is_valid;
+ rspamd_inet_addr_t *addr;
};
/**
diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c
index d535f0a1e..5116fff93 100644
--- a/src/lua/lua_config.c
+++ b/src/lua/lua_config.c
@@ -1508,7 +1508,7 @@ lua_radix_get_key (lua_State * L)
ud = luaL_checkudata (L, 2, "rspamd{ip}");
if (ud != NULL) {
addr = *((struct rspamd_lua_ip **)ud);
- if (!addr->is_valid) {
+ if (addr->addr == NULL) {
msg_err ("rspamd{ip} is not valid");
addr = NULL;
}
@@ -1519,7 +1519,7 @@ lua_radix_get_key (lua_State * L)
}
if (addr != NULL) {
- if (radix_find_compressed_addr (radix, &addr->addr)
+ if (radix_find_compressed_addr (radix, addr->addr)
!= RADIX_NO_VALUE) {
ret = TRUE;
}
diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c
index d06dc46fa..31d17b103 100644
--- a/src/lua/lua_dns.c
+++ b/src/lua/lua_dns.c
@@ -91,7 +91,7 @@ lua_dns_callback (struct rdns_reply *reply, gpointer arg)
gint i = 0;
struct rspamd_dns_resolver **presolver;
struct rdns_reply_entry *elt;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->cbref);
presolver = lua_newuserdata (cd->L, sizeof (gpointer));
@@ -109,19 +109,13 @@ lua_dns_callback (struct rdns_reply *reply, gpointer arg)
{
switch (elt->type) {
case RDNS_REQUEST_A:
- addr.af = AF_INET;
- addr.slen = sizeof (addr.addr.s4);
- memcpy (&addr.addr.s4.sin_addr, &elt->content.a.addr,
- sizeof (addr.addr.s4.sin_addr));
- rspamd_lua_ip_push (cd->L, &addr);
+ addr = rspamd_inet_address_new (AF_INET, &elt->content.a.addr);
+ rspamd_lua_ip_push (cd->L, addr);
lua_rawseti (cd->L, -2, ++i);
break;
case RDNS_REQUEST_AAAA:
- addr.af = AF_INET6;
- addr.slen = sizeof (addr.addr.s6);
- memcpy (&addr.addr.s6.sin6_addr, &elt->content.aaa.addr,
- sizeof (addr.addr.s6.sin6_addr));
- rspamd_lua_ip_push (cd->L, &addr);
+ addr = rspamd_inet_address_new (AF_INET6, &elt->content.aaa.addr);
+ rspamd_lua_ip_push (cd->L, addr);
lua_rawseti (cd->L, -2, ++i);
break;
case RDNS_REQUEST_PTR:
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index ae7682b05..07c0d7d98 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -44,7 +44,7 @@ struct lua_http_cbdata {
struct rspamd_http_message *msg;
struct event_base *ev_base;
struct timeval tv;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gint fd;
gint cbref;
};
@@ -82,6 +82,10 @@ lua_http_fin (gpointer arg)
close (cbd->fd);
}
+ if (cbd->addr) {
+ rspamd_inet_address_destroy (cbd->addr);
+ }
+
g_slice_free1 (sizeof (struct lua_http_cbdata), cbd);
}
@@ -149,8 +153,8 @@ lua_http_make_connection (struct lua_http_cbdata *cbd)
{
int fd;
- rspamd_inet_address_set_port (&cbd->addr, cbd->msg->port);
- fd = rspamd_inet_address_connect (&cbd->addr, SOCK_STREAM, TRUE);
+ rspamd_inet_address_set_port (cbd->addr, cbd->msg->port);
+ fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE);
if (fd == -1) {
msg_info ("cannot connect to %v", cbd->msg->host);
@@ -179,10 +183,15 @@ lua_http_dns_handler (struct rdns_reply *reply, gpointer ud)
lua_http_maybe_free (cbd);
}
else {
- /* XXX: support ipv6 some day */
- cbd->addr.af = AF_INET;
- memcpy (&cbd->addr.addr.s4.sin_addr, &reply->entries->content.a.addr,
- sizeof (struct in_addr));
+ if (reply->entries->type == RDNS_REQUEST_A) {
+ cbd->addr = rspamd_inet_address_new (AF_INET,
+ &reply->entries->content.a.addr);
+ }
+ else if (reply->entries->type == RDNS_REQUEST_AAAA) {
+ cbd->addr = rspamd_inet_address_new (AF_INET6,
+ &reply->entries->content.aaa.addr);
+ }
+
if (!lua_http_make_connection (cbd)) {
lua_http_push_error (cbd, "unable to make connection to the host");
lua_http_maybe_free (cbd);
diff --git a/src/lua/lua_ip.c b/src/lua/lua_ip.c
index 7cd74c734..a43cbca66 100644
--- a/src/lua/lua_ip.c
+++ b/src/lua/lua_ip.c
@@ -70,12 +70,7 @@ LUA_FUNCTION_DEF (ip, to_string);
* @return {integer(s) or nil} numeric representation of IP in *host* byte order or `nil` if IP is invalid
*/
LUA_FUNCTION_DEF (ip, to_number);
-/***
- * @function rspamd_ip.from_number(num[, num, num, num])
- * @param {integer} num one or four numbers that represents IPv4 and IPv6 accordingly (in *host* byte order)
- * @return {ip} new ip object
- */
-LUA_FUNCTION_DEF (ip, from_number);
+
/***
* @method ip:to_table()
* Converts valid IP address to the table of numeric octets
@@ -189,7 +184,6 @@ static const struct luaL_reg iplib_m[] = {
static const struct luaL_reg iplib_f[] = {
LUA_INTERFACE_DEF (ip, from_string),
- LUA_INTERFACE_DEF (ip, from_number),
{"from_ip", lua_ip_copy},
{NULL, NULL}
};
@@ -201,9 +195,10 @@ lua_ip_new (lua_State *L, struct rspamd_lua_ip *old)
ip = g_slice_alloc (sizeof (*ip));
- if (old != NULL) {
- memcpy (ip, old, sizeof (*ip));
+ if (old != NULL && old->addr != NULL) {
+ ip->addr = rspamd_inet_address_copy (old->addr);
}
+
pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *));
rspamd_lua_setclass (L, "rspamd{ip}", -1);
*pip = ip;
@@ -225,19 +220,12 @@ static gint
lua_ip_to_table (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- int max, i;
+ guint max, i;
guint8 *ptr;
- if (ip != NULL && ip->is_valid) {
+ if (ip != NULL && ip->addr) {
lua_newtable (L);
- if (ip->addr.af == AF_INET) {
- max = 32 / 8;
- ptr = (guint8 *)&ip->addr.addr.s4.sin_addr;
- }
- else {
- max = 128 / 8;
- ptr = (guint8 *)&ip->addr.addr.s6.sin6_addr;
- }
+ ptr = rspamd_inet_address_get_radix_key (ip->addr, &max);
for (i = 1; i <= max; i++, ptr++) {
lua_pushnumber (L, *ptr);
@@ -255,23 +243,18 @@ static gint
lua_ip_str_octets (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- int max, i;
+ guint max, i;
guint8 *ptr;
+ gint af;
char numbuf[8];
- if (ip != NULL && ip->is_valid) {
+ if (ip != NULL && ip->addr) {
lua_newtable (L);
- if (ip->addr.af == AF_INET) {
- ptr = (guint8 *)&ip->addr.addr.s4.sin_addr;
- max = 32 / 8;
- }
- else {
- max = 128 / 8;
- ptr = (guint8 *)&ip->addr.addr.s6.sin6_addr;
- }
+ af = rspamd_inet_address_get_af (ip->addr);
+ ptr = rspamd_inet_address_get_radix_key (ip->addr, &max);
for (i = 1; i <= max; i++, ptr++) {
- if (ip->addr.af == AF_INET) {
+ if (af == AF_INET) {
rspamd_snprintf (numbuf, sizeof (numbuf), "%d", *ptr);
lua_pushstring (L, numbuf);
lua_rawseti (L, -2, i);
@@ -300,24 +283,19 @@ static gint
lua_ip_inversed_str_octets (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- int max, i;
+ guint max, i;
guint8 *ptr;
char numbuf[4];
+ gint af;
- if (ip != NULL && ip->is_valid) {
+ if (ip != NULL && ip->addr) {
lua_newtable (L);
- if (ip->addr.af == AF_INET) {
- max = 32 / 8;
- ptr = (guint8 *)&ip->addr.addr.s4.sin_addr;
- }
- else {
- max = 128 / 8;
- ptr = (guint8 *)&ip->addr.addr.s6.sin6_addr;
- }
+ ptr = rspamd_inet_address_get_radix_key (ip->addr, &max);
+ af = rspamd_inet_address_get_af (ip->addr);
ptr += max - 1;
for (i = 1; i <= max; i++, ptr--) {
- if (ip->addr.af == AF_INET) {
+ if (af == AF_INET) {
rspamd_snprintf (numbuf, sizeof (numbuf), "%d", *ptr);
lua_pushstring (L, numbuf);
lua_rawseti (L, -2, i);
@@ -347,8 +325,8 @@ lua_ip_to_string (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- if (ip != NULL && ip->is_valid) {
- lua_pushstring (L, rspamd_inet_address_to_string (&ip->addr));
+ if (ip != NULL && ip->addr) {
+ lua_pushstring (L, rspamd_inet_address_to_string (ip->addr));
}
else {
lua_pushnil (L);
@@ -362,8 +340,8 @@ lua_ip_get_port (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- if (ip != NULL && ip->is_valid) {
- lua_pushnumber (L, rspamd_inet_address_get_port (&ip->addr));
+ if (ip != NULL && ip->addr) {
+ lua_pushnumber (L, rspamd_inet_address_get_port (ip->addr));
}
else {
lua_pushnil (L);
@@ -381,7 +359,7 @@ lua_ip_from_string (lua_State *L)
ip_str = luaL_checkstring (L, 1);
if (ip_str) {
ip = lua_ip_new (L, NULL);
- ip->is_valid = rspamd_parse_inet_address (&ip->addr, ip_str);
+ rspamd_parse_inet_address (&ip->addr, ip_str);
}
else {
lua_pushnil (L);
@@ -394,55 +372,19 @@ static gint
lua_ip_to_number (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- guint32 dst[4], i;
-
- if (ip != NULL && ip->is_valid) {
- if (ip->addr.af == AF_INET) {
- /* One integer in host byte order */
- lua_pushinteger (L, ntohl (ip->addr.addr.s4.sin_addr.s_addr));
- }
- else {
- /* 4 integers in host byte order */
- G_STATIC_ASSERT (sizeof (ip->addr.addr.s6.sin6_addr) >=
- sizeof (dst));
- memcpy (dst, &ip->addr.addr.s6.sin6_addr, sizeof (dst));
- for (i = 0; i < G_N_ELEMENTS (dst); i++) {
- lua_pushinteger (L, ntohl (dst[i]));
- }
- return 4;
- }
- }
- else {
- lua_pushnil (L);
- }
-
- return 1;
-}
+ guint32 c;
+ guint max, i;
+ guchar *ptr;
-static gint
-lua_ip_from_number (lua_State *L)
-{
- guint32 src[4], i;
- struct rspamd_lua_ip *ip;
+ if (ip != NULL && ip->addr) {
+ ptr = rspamd_inet_address_get_radix_key (ip->addr, &max);
- if (lua_gettop (L) == 1 && lua_isnumber (L, 1)) {
- /* Ipv4 version */
- ip = lua_ip_new (L, NULL);
- src[0] = lua_tointeger (L, 1);
- ip->addr.af = AF_INET;
- ip->is_valid = TRUE;
- ip->addr.addr.s4.sin_addr.s_addr = htonl (src[0]);
- }
- else if (lua_gettop (L) == 4 && lua_isnumber (L, 1)) {
- /* Ipv6 version */
- for (i = 0; i < 4; i++) {
- src[i] = htonl (lua_tonumber (L, i + 1));
+ for (i = 0; i < max / sizeof (c); i ++) {
+ memcpy (&c, ptr + i * sizeof (c), sizeof (c));
+ lua_pushinteger (L, ntohl (c));
}
- G_STATIC_ASSERT (sizeof (ip->addr.addr.s6.sin6_addr) >= sizeof (src));
- ip = lua_ip_new (L, NULL);
- ip->addr.af = AF_INET6;
- ip->is_valid = TRUE;
- memcpy (&ip->addr.addr.s6.sin6_addr, src, sizeof (src));
+
+ return max;
}
else {
lua_pushnil (L);
@@ -451,12 +393,16 @@ lua_ip_from_number (lua_State *L)
return 1;
}
+
static gint
lua_ip_destroy (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
if (ip) {
+ if (ip->addr) {
+ rspamd_inet_address_destroy (ip->addr);
+ }
g_slice_free1 (sizeof (struct rspamd_lua_ip), ip);
}
@@ -468,8 +414,9 @@ lua_ip_get_version (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
- if (ip && ip->is_valid) {
- lua_pushnumber (L, ip->addr.af == AF_INET6 ? 6 : 4);
+ if (ip && ip->addr) {
+ lua_pushnumber (L, rspamd_inet_address_get_af (ip->addr) == AF_INET6 ?
+ 6 : 4);
}
else {
lua_pushnil (L);
@@ -484,7 +431,7 @@ lua_ip_is_valid (lua_State *L)
struct rspamd_lua_ip *ip = lua_check_ip (L, 1);
if (ip) {
- lua_pushboolean (L, ip->is_valid);
+ lua_pushboolean (L, ip->addr != NULL);
}
else {
lua_pushnil (L);
@@ -498,29 +445,11 @@ lua_ip_apply_mask (lua_State *L)
{
struct rspamd_lua_ip *ip = lua_check_ip (L, 1), *nip;
gint mask;
- guint32 umsk, *p;
mask = lua_tonumber (L, 2);
- if (mask > 0 && ip != NULL && ip->is_valid) {
- if (ip->addr.af == AF_INET && mask <= 32) {
- nip = lua_ip_new (L, ip);
- umsk = htonl (G_MAXUINT32 << (32 - mask));
- nip->addr.addr.s4.sin_addr.s_addr &= umsk;
- }
- else if (ip->addr.af == AF_INET && mask <= 128) {
- nip = lua_ip_new (L, ip);
- p = (uint32_t *)&nip->addr.addr.s6.sin6_addr;
- p += 3;
- while (mask > 0) {
- umsk = htonl (G_MAXUINT32 << (32 - (mask > 32 ? 32 : mask)));
- *p &= umsk;
- p --;
- mask -= 32;
- }
- }
- else {
- lua_pushnil (L);
- }
+ if (mask > 0 && ip != NULL && ip->addr) {
+ nip = lua_ip_new (L, ip);
+ rspamd_inet_address_apply_mask (nip->addr, mask);
}
else {
lua_pushnil (L);
@@ -536,22 +465,10 @@ lua_ip_equal (lua_State *L)
*ip2 = lua_check_ip (L, 2);
gboolean res = FALSE;
- if (ip1 && ip2 && ip1->is_valid && ip2->is_valid) {
- if (ip1->addr.af == ip2->addr.af) {
- if (ip1->addr.af == AF_INET) {
- if (memcmp(&ip1->addr.addr.s4.sin_addr,
- &ip2->addr.addr.s4.sin_addr, sizeof (struct in_addr)) == 0) {
- res = TRUE;
- }
- }
- else if (ip1->addr.af == AF_INET6) {
- if (memcmp(&ip1->addr.addr.s6.sin6_addr,
- &ip2->addr.addr.s6.sin6_addr, sizeof (struct in6_addr)) == 0) {
- res = TRUE;
- }
- }
- }
+ if (ip1 && ip2 && ip1->addr && ip2->addr) {
+ res = rspamd_inet_address_compare (ip1->addr, ip2->addr);
}
+
lua_pushboolean (L, res);
return 1;
@@ -578,14 +495,7 @@ rspamd_lua_ip_push (lua_State *L, rspamd_inet_addr_t *addr)
struct rspamd_lua_ip *ip, **pip;
ip = g_slice_alloc (sizeof (struct rspamd_lua_ip));
-
- if (!rspamd_ip_is_valid (addr)) {
- ip->is_valid = FALSE;
- }
- else {
- ip->is_valid = TRUE;
- memcpy (&ip->addr, addr, sizeof (ip->addr));
- }
+ ip->addr = rspamd_inet_address_copy (addr);
pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *));
rspamd_lua_setclass (L, "rspamd{ip}", -1);
*pip = ip;
@@ -601,7 +511,7 @@ rspamd_lua_ip_push_fromstring (lua_State *L, const gchar *ip_str)
}
else {
ip = g_slice_alloc (sizeof (struct rspamd_lua_ip));
- ip->is_valid = rspamd_parse_inet_address (&ip->addr, ip_str);
+ rspamd_parse_inet_address (&ip->addr, ip_str);
pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *));
rspamd_lua_setclass (L, "rspamd{ip}", -1);
diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c
index d9d9702dd..1989b2044 100644
--- a/src/lua/lua_redis.c
+++ b/src/lua/lua_redis.c
@@ -49,7 +49,6 @@ struct lua_redis_userdata {
struct rspamd_task *task;
gint cbref;
gchar *server;
- struct in_addr ina;
gchar *reqline;
guint16 port;
};
@@ -213,15 +212,15 @@ lua_redis_make_request (lua_State *L)
addr = lua_check_ip (L, 2);
top = lua_gettop (L);
/* Now get callback */
- if (lua_isfunction (L, 3) && addr != NULL && addr->is_valid && top >= 4) {
+ if (lua_isfunction (L, 3) && addr != NULL && addr->addr && top >= 4) {
/* Create userdata */
ud =
rspamd_mempool_alloc (task->task_pool,
sizeof (struct lua_redis_userdata));
ud->task = task;
ud->L = L;
- ud->ctx = redisAsyncConnect (rspamd_inet_address_to_string (&addr->addr),
- rspamd_inet_address_get_port (&addr->addr));
+ ud->ctx = redisAsyncConnect (rspamd_inet_address_to_string (addr->addr),
+ rspamd_inet_address_get_port (addr->addr));
if (ud->ctx == NULL || ud->ctx->err) {
redisAsyncFree (ud->ctx);
diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c
index 60dfb7cf7..e74d7e71c 100644
--- a/src/lua/lua_task.c
+++ b/src/lua/lua_task.c
@@ -1503,7 +1503,7 @@ lua_task_get_from_ip (lua_State *L)
struct rspamd_task *task = lua_check_task (L, 1);
if (task) {
- rspamd_lua_ip_push (L, &task->from_addr);
+ rspamd_lua_ip_push (L, task->from_addr);
}
else {
lua_pushnil (L);
@@ -1533,7 +1533,7 @@ lua_task_get_client_ip (lua_State *L)
struct rspamd_task *task = lua_check_task (L, 1);
if (task) {
- rspamd_lua_ip_push (L, &task->client_addr);
+ rspamd_lua_ip_push (L, task->client_addr);
}
else {
lua_pushnil (L);
diff --git a/src/lua_worker.c b/src/lua_worker.c
index 95c3be719..a93a2c2fa 100644
--- a/src/lua_worker.c
+++ b/src/lua_worker.c
@@ -262,7 +262,7 @@ lua_accept_socket (gint fd, short what, void *arg)
struct rspamd_lua_worker_ctx *ctx, **pctx;
gint nfd;
lua_State *L;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
ctx = worker->ctx;
L = ctx->L;
@@ -278,8 +278,8 @@ lua_accept_socket (gint fd, short what, void *arg)
}
msg_info ("accepted connection from %s port %d",
- rspamd_inet_address_to_string (&addr),
- rspamd_inet_address_get_port (&addr));
+ rspamd_inet_address_to_string (addr),
+ rspamd_inet_address_get_port (addr));
/* Call finalizer function */
lua_rawgeti (L, LUA_REGISTRYINDEX, ctx->cbref_accept);
@@ -287,13 +287,15 @@ lua_accept_socket (gint fd, short what, void *arg)
rspamd_lua_setclass (L, "rspamd{worker}", -1);
*pctx = ctx;
lua_pushinteger (L, nfd);
- lua_pushstring (L, rspamd_inet_address_to_string (&addr));
+ lua_pushstring (L, rspamd_inet_address_to_string (addr));
lua_pushinteger (L, 0);
if (lua_pcall (L, 4, 0, 0) != 0) {
msg_info ("call to worker accept failed: %s", lua_tostring (L, -1));
}
+
+ rspamd_inet_address_destroy (addr);
}
static gboolean
diff --git a/src/main.c b/src/main.c
index 0f2ceb360..373c01695 100644
--- a/src/main.c
+++ b/src/main.c
@@ -569,26 +569,17 @@ delay_fork (struct rspamd_worker_conf *cf)
set_alarm (SOFT_FORK_TIME);
}
-static int
-af_cmp_workaround (const void *a, const void *b)
-{
- rspamd_inet_addr_t *a1 = (rspamd_inet_addr_t *)a,
- *a2 = (rspamd_inet_addr_t *)b;
-
- return a2->af - a1->af;
-}
-
static GList *
-create_listen_socket (rspamd_inet_addr_t *addrs, guint cnt, gint listen_type)
+create_listen_socket (GPtrArray *addrs, guint cnt, gint listen_type)
{
GList *result = NULL;
gint fd;
guint i;
- /* Fuck morons that have invented ipv6/v4 sockets */
- qsort (addrs, cnt, sizeof (*addrs), af_cmp_workaround);
+ g_ptr_array_sort (addrs, rspamd_inet_address_compare_ptr);
for (i = 0; i < cnt; i ++) {
- fd = rspamd_inet_address_listen (&addrs[i], listen_type, TRUE);
+ fd = rspamd_inet_address_listen (g_ptr_array_index (addrs, i),
+ listen_type, TRUE);
if (fd != -1) {
result = g_list_prepend (result, GINT_TO_POINTER (fd));
}
@@ -615,9 +606,11 @@ systemd_get_socket (gint number)
if ((err == NULL || *err == '\0') && num_passed > number) {
sock = number + sd_listen_fds_start;
if (fstat (sock, &st) == -1) {
+ msg_warn ("cannot stat systemd descriptor %d", sock);
return NULL;
}
if (!S_ISSOCK (st.st_mode)) {
+ msg_warn ("systemd descriptor %d is not a socket", sock);
errno = EINVAL;
return NULL;
}
@@ -628,10 +621,13 @@ systemd_get_socket (gint number)
result = g_list_prepend (result, GINT_TO_POINTER (sock));
}
else if (num_passed <= number) {
+ msg_warn ("systemd LISTEN_FDS does not contain the expected fd: %d",
+ num_passed);
errno = EOVERFLOW;
}
}
else {
+ msg_warn ("cannot get systemd variable 'LISTEN_FDS'");
errno = ENOENT;
}
@@ -658,7 +654,8 @@ static inline uintptr_t
make_listen_key (struct rspamd_worker_bind_conf *cf)
{
gpointer xxh;
- guint i;
+ guint i, keylen;
+ guint8 *key;
xxh = XXH32_init (0xdeadbeef);
if (cf->is_systemd) {
@@ -668,7 +665,9 @@ make_listen_key (struct rspamd_worker_bind_conf *cf)
else {
XXH32_update (xxh, cf->name, strlen (cf->name));
for (i = 0; i < cf->cnt; i ++) {
- XXH32_update (xxh, &cf->addrs[i].addr, cf->addrs[i].slen);
+ key = rspamd_inet_address_get_radix_key (
+ g_ptr_array_index (cf->addrs, i), &keylen);
+ XXH32_update (xxh, key, keylen);
}
}
diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c
index 545e3e28d..f37a465a1 100644
--- a/src/plugins/dkim_check.c
+++ b/src/plugins/dkim_check.c
@@ -369,7 +369,7 @@ dkim_symbol_callback (struct rspamd_task *task, void *unused)
/* Check whitelist */
msg_debug ("dkim signature found");
if (radix_find_compressed_addr (dkim_module_ctx->whitelist_ip,
- &task->from_addr) == RADIX_NO_VALUE) {
+ task->from_addr) == RADIX_NO_VALUE) {
/* Parse signature */
msg_debug ("create dkim signature");
/*
diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c
index b1c24c6b8..9fb62187f 100644
--- a/src/plugins/fuzzy_check.c
+++ b/src/plugins/fuzzy_check.c
@@ -1142,10 +1142,10 @@ fuzzy_symbol_callback (struct rspamd_task *task, void *unused)
/* Check whitelist */
if (fuzzy_module_ctx->whitelist) {
if (radix_find_compressed_addr (fuzzy_module_ctx->whitelist,
- &task->from_addr) != RADIX_NO_VALUE) {
+ task->from_addr) != RADIX_NO_VALUE) {
msg_info ("<%s>, address %s is whitelisted, skip fuzzy check",
task->message_id,
- rspamd_inet_address_to_string (&task->from_addr));
+ rspamd_inet_address_to_string (task->from_addr));
return;
}
}
diff --git a/src/plugins/regexp.c b/src/plugins/regexp.c
index 09725c7c7..b96fcca31 100644
--- a/src/plugins/regexp.c
+++ b/src/plugins/regexp.c
@@ -503,13 +503,14 @@ process_regexp (struct rspamd_regexp_element *re,
rh = cur->data;
debug_task ("found header \"%s\" with value \"%s\"",
re->header, rh->decoded);
+ regexp = re->regexp;
+
if (re->type == REGEXP_RAW_HEADER) {
in = rh->value;
raw = TRUE;
}
else {
in = rh->decoded;
- regexp = re->regexp;
/* Validate input */
if (!in || !g_utf8_validate (in, -1, NULL)) {
cur = g_list_next (cur);
@@ -572,14 +573,13 @@ process_regexp (struct rspamd_regexp_element *re,
cur = g_list_next (cur);
continue;
}
+
+ regexp = re->regexp;
+
/* Check raw flags */
if (part->is_raw) {
raw = TRUE;
}
- else {
- /* This time there is no need to validate anything as conversion succeed only for valid characters */
- regexp = re->regexp;
- }
/* Select data for regexp */
if (raw) {
ct = part->orig->data;
diff --git a/src/plugins/spf.c b/src/plugins/spf.c
index bbb9b8a76..d74f481c2 100644
--- a/src/plugins/spf.c
+++ b/src/plugins/spf.c
@@ -188,35 +188,39 @@ static gboolean
spf_check_element (struct spf_addr *addr, struct rspamd_task *task)
{
gboolean res = FALSE;
- guint8 *s, *d, t;
+ guint8 *s, *d, t, *buf;
gchar *spf_result;
+ gint af;
const gchar *spf_message, *spf_symbol;
guint nbits, addrlen;
- struct in_addr in4s, in4d;
- struct in6_addr in6s, in6d;
+ struct in_addr in4s;
+ struct in6_addr in6s;
GList *opts = NULL;
+ if (task->from_addr == NULL) {
+ return FALSE;
+ }
+
+ af = rspamd_inet_address_get_af (task->from_addr);
/* Basic comparing algorithm */
- if ((addr->data.normal.ipv6 && task->from_addr.af == AF_INET6) ||
- (!addr->data.normal.ipv6 && task->from_addr.af == AF_INET)) {
+ if ((addr->data.normal.ipv6 && af == AF_INET6) ||
+ (!addr->data.normal.ipv6 && af == AF_INET)) {
+ d = rspamd_inet_address_get_radix_key (task->from_addr, &addrlen);
+ buf = g_alloca (addrlen);
+ memcpy (buf, d, addrlen);
+ d = buf;
+
if (addr->data.normal.ipv6) {
- addrlen = sizeof (struct in6_addr);
memcpy (&in6s, &addr->data.normal.d.in6,
sizeof (struct in6_addr));
- memcpy (&in6d, &task->from_addr.addr.s6.sin6_addr,
- sizeof (struct in6_addr));
s = (guint8 *)&in6s;
- d = (guint8 *)&in6d;
}
else {
- addrlen = sizeof (struct in_addr);
memcpy (&in4s, &addr->data.normal.d.in4,
sizeof (struct in_addr));
- memcpy (&in4d, &task->from_addr.addr.s4.sin_addr,
- sizeof (struct in_addr));
s = (guint8 *)&in4s;
- d = (guint8 *)&in4d;
}
+
/* Move pointers to the less significant byte */
t = 0x1;
s += addrlen - 1;
@@ -236,12 +240,8 @@ spf_check_element (struct spf_addr *addr, struct rspamd_task *task)
*d |= t;
t <<= 1;
}
- if (addr->data.normal.ipv6) {
- res = memcmp (&in6d, &in6s, sizeof (struct in6_addr)) == 0;
- }
- else {
- res = memcmp (&in4d, &in4s, sizeof (struct in_addr)) == 0;
- }
+
+ res = memcmp (d, s, addrlen);
}
else {
if (addr->data.normal.addr_any) {
@@ -338,7 +338,7 @@ spf_symbol_callback (struct rspamd_task *task, void *unused)
GList *l;
if (radix_find_compressed_addr (spf_module_ctx->whitelist_ip,
- &task->from_addr) == RADIX_NO_VALUE) {
+ task->from_addr) == RADIX_NO_VALUE) {
domain = get_spf_domain (task);
if (domain) {
if ((l =
diff --git a/src/smtp_proxy.c b/src/smtp_proxy.c
index efec0926e..a86c828c0 100644
--- a/src/smtp_proxy.c
+++ b/src/smtp_proxy.c
@@ -905,7 +905,7 @@ accept_socket (gint fd, short what, void *arg)
struct rspamd_worker *worker = (struct rspamd_worker *)arg;
struct smtp_proxy_session *session;
struct smtp_proxy_ctx *ctx;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gint nfd;
ctx = worker->ctx;
@@ -921,8 +921,8 @@ accept_socket (gint fd, short what, void *arg)
}
msg_info ("accepted connection from %s port %d",
- rspamd_inet_address_to_string (&addr),
- rspamd_inet_address_get_port (&addr));
+ rspamd_inet_address_to_string (addr),
+ rspamd_inet_address_get_port (addr));
ctx = worker->ctx;
session = g_slice_alloc0 (sizeof (struct smtp_proxy_session));
@@ -936,7 +936,7 @@ accept_socket (gint fd, short what, void *arg)
session->ev_base = ctx->ev_base;
session->upstream_sock = -1;
session->ptr_str = rdns_generate_ptr_from_str (rspamd_inet_address_to_string (
- &addr));
+ addr));
worker->srv->stat->connections_count++;
/* Resolve client's addr */
@@ -946,6 +946,7 @@ accept_socket (gint fd, short what, void *arg)
NULL,
free_smtp_proxy_session,
session);
+ rspamd_inet_address_destroy (addr);
session->state = SMTP_PROXY_STATE_RESOLVE_REVERSE;
if (!make_dns_request (session->resolver, session->s, session->pool,
smtp_dns_cb, session, RDNS_REQUEST_PTR, session->ptr_str)) {
diff --git a/src/worker.c b/src/worker.c
index 7a94ee77e..2598fed58 100644
--- a/src/worker.c
+++ b/src/worker.c
@@ -149,7 +149,7 @@ rspamd_worker_error_handler (struct rspamd_http_connection *conn, GError *err)
struct rspamd_task *task = (struct rspamd_task *) conn->ud;
msg_info ("abnormally closing connection from: %s, error: %s",
- rspamd_inet_address_to_string (&task->client_addr), err->message);
+ rspamd_inet_address_to_string (task->client_addr), err->message);
/* Terminate session immediately */
destroy_session (task->s);
}
@@ -163,7 +163,7 @@ rspamd_worker_finish_handler (struct rspamd_http_connection *conn,
if (task->state == CLOSING_CONNECTION || task->state == WRITING_REPLY) {
/* We are done here */
msg_debug ("normally closing connection from: %s",
- rspamd_inet_address_to_string (&task->client_addr));
+ rspamd_inet_address_to_string (task->client_addr));
destroy_session (task->s);
}
else if (task->state == WRITE_REPLY) {
@@ -173,7 +173,7 @@ rspamd_worker_finish_handler (struct rspamd_http_connection *conn,
* is read
*/
msg_debug ("want write message to the wire: %s",
- rspamd_inet_address_to_string (&task->client_addr));
+ rspamd_inet_address_to_string (task->client_addr));
rspamd_protocol_write_reply (task);
/* Forcefully set the state */
task->state = CLOSING_CONNECTION;
@@ -199,7 +199,7 @@ accept_socket (gint fd, short what, void *arg)
struct rspamd_worker *worker = (struct rspamd_worker *) arg;
struct rspamd_worker_ctx *ctx;
struct rspamd_task *new_task;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gint nfd;
ctx = worker->ctx;
@@ -224,13 +224,19 @@ accept_socket (gint fd, short what, void *arg)
new_task = rspamd_task_new (worker);
msg_info ("accepted connection from %s port %d",
- rspamd_inet_address_to_string (&addr),
- rspamd_inet_address_get_port (&addr));
+ rspamd_inet_address_to_string (addr),
+ rspamd_inet_address_get_port (addr));
/* Copy some variables */
+ if (ctx->is_mime) {
+ new_task->flags |= RSPAMD_TASK_FLAG_MIME;
+ }
+ else {
+ new_task->flags &= ~RSPAMD_TASK_FLAG_MIME;
+ }
+
new_task->sock = nfd;
- new_task->is_mime = ctx->is_mime;
- memcpy (&new_task->client_addr, &addr, sizeof (addr));
+ new_task->client_addr = addr;
worker->srv->stat->connections_count++;
new_task->resolver = ctx->resolver;
diff --git a/test/lua/unit/regxep.lua b/test/lua/unit/regxep.lua
index 1277cce11..e33d20d43 100644
--- a/test/lua/unit/regxep.lua
+++ b/test/lua/unit/regxep.lua
@@ -15,6 +15,10 @@ context("Regexp unit tests", function()
{'m,test,', 'test123', false},
{'/test/i', 'TeSt123', true},
{'/тест/i', 'ТесТ', true},
+ -- Raw regexp
+ {'/\\S<[-\\w\\.]+\\@[-\\w\\.]+>/r', 'some<example@example.com>', true},
+ -- Cyrillic utf8 letter
+ {'/\\S<[-\\w\\.]+\\@[-\\w\\.]+>/r', 'some<example@exаmple.com>', false},
}
for _,c in ipairs(cases) do
diff --git a/test/rspamd_http_test.c b/test/rspamd_http_test.c
index ab465638c..324ad8e44 100644
--- a/test/rspamd_http_test.c
+++ b/test/rspamd_http_test.c
@@ -51,7 +51,7 @@ static void
rspamd_server_accept (gint fd, short what, void *arg)
{
struct rspamd_http_connection_router *rt = arg;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gint nfd;
if ((nfd =
@@ -64,6 +64,7 @@ rspamd_server_accept (gint fd, short what, void *arg)
return;
}
+ rspamd_inet_address_destroy (addr);
rspamd_http_router_handle_socket (rt, nfd, NULL);
}
@@ -206,7 +207,7 @@ rspamd_http_test_func (void)
gpointer serv_key, client_key, peer_key;
struct rspamd_keypair_cache *c;
rspamd_mempool_mutex_t *mtx;
- rspamd_inet_addr_t addr;
+ rspamd_inet_addr_t *addr;
gdouble ts1, ts2;
gchar filepath[PATH_MAX], buf[512];
gint fd, i, j;
@@ -226,7 +227,7 @@ rspamd_http_test_func (void)
mtx = rspamd_mempool_get_mutex (pool);
rspamd_parse_inet_address (&addr, "127.0.0.1");
- rspamd_inet_address_set_port (&addr, ottery_rand_range (30000) + 32768);
+ rspamd_inet_address_set_port (addr, ottery_rand_range (30000) + 32768);
serv_key = rspamd_http_connection_gen_key ();
client_key = rspamd_http_connection_gen_key ();
c = rspamd_keypair_cache_new (16);
@@ -236,7 +237,7 @@ rspamd_http_test_func (void)
g_assert (sfd != -1);
if (sfd == 0) {
- rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, c);
+ rspamd_http_server_func ("/tmp/", addr, mtx, serv_key, c);
exit (EXIT_SUCCESS);
}
@@ -245,7 +246,7 @@ rspamd_http_test_func (void)
/* Do client stuff */
for (i = 0; i < ntests; i ++) {
for (j = 0; j < pconns; j ++) {
- rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
+ rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, addr,
NULL, NULL, c, ev_base, &latency[i * pconns + j]);
}
ts1 = rspamd_get_ticks ();
@@ -273,7 +274,7 @@ rspamd_http_test_func (void)
for (i = 0; i < ntests; i ++) {
for (j = 0; j < pconns; j ++) {
- rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
+ rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, addr,
client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
}
ts1 = rspamd_get_ticks ();
@@ -298,7 +299,7 @@ rspamd_http_test_func (void)
g_assert (sfd != -1);
if (sfd == 0) {
- rspamd_http_server_func ("/tmp/", &addr, mtx, serv_key, NULL);
+ rspamd_http_server_func ("/tmp/", addr, mtx, serv_key, NULL);
exit (EXIT_SUCCESS);
}
@@ -307,7 +308,7 @@ rspamd_http_test_func (void)
for (i = 0; i < ntests; i ++) {
for (j = 0; j < pconns; j ++) {
- rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, &addr,
+ rspamd_http_client_func (filepath + sizeof ("/tmp") - 1, addr,
client_key, peer_key, c, ev_base, &latency[i * pconns + j]);
}
ts1 = rspamd_get_ticks ();
diff --git a/test/rspamd_upstream_test.c b/test/rspamd_upstream_test.c
index 23a450ec4..69e744853 100644
--- a/test/rspamd_upstream_test.c
+++ b/test/rspamd_upstream_test.c
@@ -72,7 +72,7 @@ rspamd_upstream_test_func (void)
gdouble p;
struct event ev;
struct timeval tv;
- rspamd_inet_addr_t *addr, *next_addr, paddr;
+ rspamd_inet_addr_t *addr, *next_addr, *paddr;
cfg = (struct rspamd_config *)g_malloc (sizeof (struct rspamd_config));
bzero (cfg, sizeof (struct rspamd_config));
@@ -98,11 +98,11 @@ rspamd_upstream_test_func (void)
/* Test round-robin rotation */
rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
- rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
- rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "microsoft.com");
rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
+ rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
+ rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "microsoft.com");
/* Test stable hashing */
nls = rspamd_upstreams_create ();
@@ -138,17 +138,16 @@ rspamd_upstream_test_func (void)
nls = rspamd_upstreams_create ();
g_assert (rspamd_upstreams_add_upstream (nls, "127.0.0.1", 0, NULL));
up = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_RANDOM);
- addr = g_malloc (sizeof (*addr));
rspamd_parse_inet_address(&paddr, "127.0.0.2");
- g_assert (rspamd_upstream_add_addr (up, &paddr));
+ g_assert (rspamd_upstream_add_addr (up, paddr));
rspamd_parse_inet_address(&paddr, "::1");
- g_assert (rspamd_upstream_add_addr (up, &paddr));
+ g_assert (rspamd_upstream_add_addr (up, paddr));
addr = rspamd_upstream_addr (up);
for (i = 0; i < 256; i ++) {
next_addr = rspamd_upstream_addr (up);
- g_assert (addr->af == AF_INET);
- g_assert (next_addr->af == AF_INET);
- g_assert (addr != next_addr);
+ g_assert (rspamd_inet_address_get_af (addr) == AF_INET);
+ g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET);
+ g_assert (rspamd_inet_address_compare (addr, next_addr) != 0);
addr = next_addr;
}
rspamd_upstreams_destroy (nls);