]> source.dussan.org Git - rspamd.git/commitdiff
Support IP DNS black lists for URIBL
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 27 Nov 2015 16:32:14 +0000 (16:32 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 27 Nov 2015 16:32:14 +0000 (16:32 +0000)
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
src/plugins/surbl.c
src/plugins/surbl.h

index 713ec81b5660c6cc6fc755d6c2a2a83c02050716..6f141fb7dbebe5082589231d2785d59009cd2cb1 100644 (file)
@@ -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 */
index efb61fd892cdcda2c21f9a11a9b179836db91a4f..d0424238dc3331c8259fa1fb8240c6d5922f50a2 100644 (file)
@@ -41,6 +41,7 @@
  * - bit (string): describes a prefix for a single bit
  */
 
+#include <rdns.h>
 #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)
 {
index 320423698dc0f1d8906a73c7cc3fcbc0656b092a..2477032b91708db99e9fd1a6e3deedccfc620937 100644 (file)
@@ -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 {