diff options
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); |