From 79828e25c87118012b2ff432f29ba5a4a6b7ebe3 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 27 Nov 2015 16:32:14 +0000 Subject: [PATCH] Support IP DNS black lists for URIBL Rspamd now can resolve URL's IP address and check it via the standard DNS IP blacklist (such as spamhaus SBL, for example) --- src/lua/lua_dns.c | 2 +- src/plugins/surbl.c | 126 +++++++++++++++++++++++++++++++++++++++----- src/plugins/surbl.h | 3 +- 3 files changed, 117 insertions(+), 14 deletions(-) diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c index 713ec81b5..6f141fb7d 100644 --- a/src/lua/lua_dns.c +++ b/src/lua/lua_dns.c @@ -207,7 +207,7 @@ lua_dns_callback (struct rdns_reply *reply, gpointer arg) } if (lua_pcall (cd->L, 5, 0, 0) != 0) { - msg_info ("call to dns_callback failed: %s", lua_tostring (cd->L, -1)); + msg_info ("call to dns callback failed: %s", lua_tostring (cd->L, -1)); } /* Unref function */ diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c index efb61fd89..d0424238d 100644 --- a/src/plugins/surbl.c +++ b/src/plugins/surbl.c @@ -41,6 +41,7 @@ * - bit (string): describes a prefix for a single bit */ +#include #include "config.h" #include "libmime/message.h" #include "libutil/map.h" @@ -52,7 +53,8 @@ static struct surbl_ctx *surbl_module_ctx = NULL; static void surbl_test_url (struct rspamd_task *task, void *user_data); -static void dns_callback (struct rdns_reply *reply, gpointer arg); +static void surbl_dns_callback (struct rdns_reply *reply, gpointer arg); +static void surbl_dns_ip_callback (struct rdns_reply *reply, gpointer arg); static void process_dns_results (struct rspamd_task *task, struct suffix_item *suffix, gchar *url, guint32 addr); @@ -484,6 +486,19 @@ surbl_module_config (struct rspamd_config *cfg) new_suffix->options |= SURBL_OPTION_NOIP; } } + cur = ucl_obj_get_key (cur_rule, "resolve_ip"); + if (cur != NULL && cur->type == UCL_BOOLEAN) { + if (ucl_object_toboolean (cur)) { + new_suffix->options |= SURBL_OPTION_RESOLVEIP; + } + } + + if ((new_suffix->options & (SURBL_OPTION_RESOLVEIP|SURBL_OPTION_NOIP)) == + (SURBL_OPTION_NOIP|SURBL_OPTION_RESOLVEIP)) { + /* Mutually exclusive options */ + msg_err_config ("options noip and resolve_ip are " + "mutually exclusive for suffix %s", new_suffix->suffix); + } cb_id = rspamd_symbols_cache_add_symbol (cfg->cache, "SURBL_CALLBACK", @@ -859,7 +874,46 @@ make_surbl_requests (struct rspamd_url *url, struct rspamd_task *task, f.begin = url->host; f.len = url->hostlen; - if ((surbl_req = format_surbl_request (task->task_pool, &f, suffix, TRUE, + if (suffix->options & SURBL_OPTION_RESOLVEIP) { + /* + * We need to get url real TLD, resolve it with no suffix and then + * check against surbl using reverse octets printing + */ + surbl_req = format_surbl_request (task->task_pool, &f, suffix, FALSE, + &err, forced, tree, url); + + if (surbl_req == NULL) { + if (err != NULL) { + if (err->code != WHITELIST_ERROR && err->code != DUPLICATE_ERROR) { + msg_info_task ("cannot format url string for surbl %s, %e", + struri (url), + err); + } + g_error_free (err); + return; + } + } + else { + /* XXX: We make merely A request here */ + param = + rspamd_mempool_alloc (task->task_pool, + sizeof (struct dns_param)); + param->url = url; + param->task = task; + param->suffix = suffix; + param->host_resolve = + rspamd_mempool_strdup (task->task_pool, surbl_req); + debug_task ("send surbl dns ip request %s", surbl_req); + + if (make_dns_request_task (task, + surbl_dns_ip_callback, + (void *) param, RDNS_REQUEST_A, surbl_req)) { + param->w = rspamd_session_get_watcher (task->s); + rspamd_session_watcher_push (task->s); + } + } + } + else if ((surbl_req = format_surbl_request (task->task_pool, &f, suffix, TRUE, &err, forced, tree, url)) != NULL) { param = rspamd_mempool_alloc (task->task_pool, sizeof (struct dns_param)); @@ -871,21 +925,19 @@ make_surbl_requests (struct rspamd_url *url, struct rspamd_task *task, debug_task ("send surbl dns request %s", surbl_req); if (make_dns_request_task (task, - dns_callback, - (void *)param, RDNS_REQUEST_A, surbl_req)) { + surbl_dns_callback, + (void *) param, RDNS_REQUEST_A, surbl_req)) { param->w = rspamd_session_get_watcher (task->s); rspamd_session_watcher_push (task->s); } } - else if (err != NULL && err->code != WHITELIST_ERROR && err->code != - DUPLICATE_ERROR) { - msg_info_task ("cannot format url string for surbl %s, %e", struri ( - url), err); - g_error_free (err); - return; - } else if (err != NULL) { + if (err->code != WHITELIST_ERROR && err->code != DUPLICATE_ERROR) { + msg_info_task ("cannot format url string for surbl %s, %e", struri ( + url), err); + } g_error_free (err); + return; } } @@ -930,7 +982,7 @@ process_dns_results (struct rspamd_task *task, } static void -dns_callback (struct rdns_reply *reply, gpointer arg) +surbl_dns_callback (struct rdns_reply *reply, gpointer arg) { struct dns_param *param = (struct dns_param *)arg; struct rspamd_task *task; @@ -957,6 +1009,56 @@ dns_callback (struct rdns_reply *reply, gpointer arg) rspamd_session_watcher_pop (param->task->s, param->w); } +static void +surbl_dns_ip_callback (struct rdns_reply *reply, gpointer arg) +{ + struct dns_param *param = (struct dns_param *) arg; + struct rspamd_task *task; + struct rdns_reply_entry *elt; + GString *to_resolve; + guint32 ip_addr; + + task = param->task; + /* If we have result from DNS server, this url exists in SURBL, so increase score */ + if (reply->code == RDNS_RC_NOERROR && reply->entries) { + + LL_FOREACH (reply->entries, elt) { + elt = reply->entries; + + if (elt->type == RDNS_REQUEST_A) { + to_resolve = g_string_sized_new ( + strlen (param->suffix->suffix) + + sizeof ("255.255.255.255.")); + ip_addr = elt->content.a.addr.s_addr; + + /* Big endian <4>.<3>.<2>.<1> */ + rspamd_printf_gstring (to_resolve, "%d.%d.%d.%d.%s", + ip_addr >> 24 & 0xff, + ip_addr >> 16 & 0xff, + ip_addr >> 8 & 0xff, + ip_addr & 0xff, param->suffix->suffix); + + if (make_dns_request_task (task, + surbl_dns_callback, + param, RDNS_REQUEST_A, to_resolve->str)) { + param->w = rspamd_session_get_watcher (task->s); + rspamd_session_watcher_push (task->s); + } + + g_string_free (to_resolve, TRUE); + } + } + } + else { + msg_debug_task ("<%s> domain [%s] cannot be resolved for SURBL check %s", + param->task->message_id, param->host_resolve, + param->suffix->suffix); + + } + + rspamd_session_watcher_pop (param->task->s, param->w); +} + static void free_redirector_session (void *ud) { diff --git a/src/plugins/surbl.h b/src/plugins/surbl.h index 320423698..2477032b9 100644 --- a/src/plugins/surbl.h +++ b/src/plugins/surbl.h @@ -12,7 +12,8 @@ #define DEFAULT_SURBL_URL_EXPIRE 86400 #define DEFAULT_SURBL_SYMBOL "SURBL_DNS" #define DEFAULT_SURBL_SUFFIX "multi.surbl.org" -#define SURBL_OPTION_NOIP 1 +#define SURBL_OPTION_NOIP (1 << 0) +#define SURBL_OPTION_RESOLVEIP (1 << 1) #define MAX_LEVELS 10 struct surbl_ctx { -- 2.39.5