aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-11-27 16:32:14 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-11-27 16:32:14 +0000
commit79828e25c87118012b2ff432f29ba5a4a6b7ebe3 (patch)
tree50361b8902f30ad35dc5d586c9d50da37054d778
parentbb0fd1296a55f390ec622f64b45fe7e7c3595113 (diff)
downloadrspamd-79828e25c87118012b2ff432f29ba5a4a6b7ebe3.tar.gz
rspamd-79828e25c87118012b2ff432f29ba5a4a6b7ebe3.zip
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)
-rw-r--r--src/lua/lua_dns.c2
-rw-r--r--src/plugins/surbl.c126
-rw-r--r--src/plugins/surbl.h3
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 <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;
@@ -958,6 +1010,56 @@ dns_callback (struct rdns_reply *reply, gpointer arg)
}
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)
{
struct redirector_param *param = (struct redirector_param *)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 {