Просмотр исходного кода

* Make SURBL module to use rspamd dns module

* Several fixes to DNS logic
tags/0.3.1
Vsevolod Stakhov 14 лет назад
Родитель
Сommit
5e458871b3
5 измененных файлов: 130 добавлений и 122 удалений
  1. 25
    8
      src/dns.c
  2. 1
    0
      src/dns.h
  3. 9
    10
      src/plugins/surbl.c
  4. 94
    103
      src/spf.c
  5. 1
    1
      test/rspamd_dns_test.c

+ 25
- 8
src/dns.c Просмотреть файл

@@ -409,8 +409,8 @@ format_dns_name (struct rspamd_dns_request *req, const char *name, guint namelen
}
}
/* Termination label */
*(++pos) = '\0';
req->pos += pos - (req->packet + req->pos);
*pos = '\0';
req->pos += pos - (req->packet + req->pos) + 1;
if (table != NULL) {
g_list_free (table);
}
@@ -601,6 +601,7 @@ dns_request_reply_cmp (struct rspamd_dns_request *req, guint8 *in, int len)
}
/* This may be compressed, so we need to decompress it */
if (len1 & DNS_COMPRESSION_BITS) {
memcpy (&len1, p, sizeof (guint16));
l1 = decompress_label (in, &len1);
decompressed ++;
l1 ++;
@@ -611,6 +612,7 @@ dns_request_reply_cmp (struct rspamd_dns_request *req, guint8 *in, int len)
p += len1;
}
if (len2 & DNS_COMPRESSION_BITS) {
memcpy (&len2, p, sizeof (guint16));
l2 = decompress_label (req->packet, &len2);
decompressed ++;
l2 ++;
@@ -796,8 +798,8 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct
p += datalen;
}
else {
elt->txt.data = memory_pool_alloc (rep->request->pool, datalen + 1);
memcpy (elt->txt.data, p, datalen);
elt->txt.data = memory_pool_alloc (rep->request->pool, datalen);
memcpy (elt->txt.data, p + 1, datalen - 1);
*(elt->txt.data + datalen) = '\0';
}
break;
@@ -806,8 +808,8 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct
p += datalen;
}
else {
elt->spf.data = memory_pool_alloc (rep->request->pool, datalen + 1);
memcpy (elt->spf.data, p, datalen);
elt->spf.data = memory_pool_alloc (rep->request->pool, datalen);
memcpy (elt->spf.data, p + 1, datalen - 1);
*(elt->spf.data + datalen) = '\0';
}
break;
@@ -924,7 +926,7 @@ dns_timer_cb (int fd, short what, void *arg)
/* Retransmit dns request */
req->retransmits ++;
if (req->retransmits >= req->resolver->max_retransmits) {
msg_err ("maximum number of retransmits expired");
msg_err ("maximum number of retransmits expired for resolving %s of type %s", req->requested_name, dns_strtype (req->type));
event_del (&req->timer_event);
rep = memory_pool_alloc0 (req->pool, sizeof (struct rspamd_dns_reply));
rep->request = req;
@@ -985,7 +987,7 @@ dns_retransmit_handler (int fd, short what, void *arg)
/* Retransmit dns request */
req->retransmits ++;
if (req->retransmits >= req->resolver->max_retransmits) {
msg_err ("maximum number of retransmits expired");
msg_err ("maximum number of retransmits expired for %s", req->requested_name);
event_del (&req->io_event);
rep = memory_pool_alloc0 (req->pool, sizeof (struct rspamd_dns_reply));
rep->request = req;
@@ -1258,3 +1260,18 @@ dns_strerror (enum dns_rcode rcode)
}
return dns_rcodes[rcode];
}

static char dns_types[6][16] = {
[DNS_REQUEST_A] = "A request",
[DNS_REQUEST_PTR] = "PTR request",
[DNS_REQUEST_MX] = "MX request",
[DNS_REQUEST_TXT] = "TXT request",
[DNS_REQUEST_SRV] = "SRV request",
[DNS_REQUEST_SPF] = "SPF request"
};

const char *
dns_strtype (enum rspamd_request_type type)
{
return dns_types[type];
}

+ 1
- 0
src/dns.h Просмотреть файл

@@ -226,5 +226,6 @@ gboolean make_dns_request (struct rspamd_dns_resolver *resolver,
struct rspamd_async_session *session, memory_pool_t *pool, dns_callback_type cb,
gpointer ud, enum rspamd_request_type type, ...);
const char *dns_strerror (enum dns_rcode rcode);
const char *dns_strtype (enum rspamd_request_type type);

#endif

+ 9
- 10
src/plugins/surbl.c Просмотреть файл

@@ -46,7 +46,7 @@
#include "../message.h"
#include "../view.h"
#include "../map.h"
#include "../evdns/evdns.h"
#include "../dns.h"

#include "surbl.h"

@@ -54,7 +54,7 @@ static struct surbl_ctx *surbl_module_ctx = NULL;

static int surbl_filter (struct worker_task *task);
static void surbl_test_url (struct worker_task *task, void *user_data);
static void dns_callback (int result, char type, int count, int ttl, void *addresses, void *data);
static void dns_callback (struct rspamd_dns_reply *reply, gpointer arg);
static void process_dns_results (struct worker_task *task, struct suffix_item *suffix, char *url, uint32_t addr);
static int urls_command_handler (struct worker_task *task);

@@ -449,9 +449,8 @@ make_surbl_requests (struct uri *url, struct worker_task *task, GTree * tree, st
param->suffix = suffix;
param->host_resolve = memory_pool_strdup (task->task_pool, surbl_req);
debug_task ("send surbl dns request %s", surbl_req);
if (evdns_resolve_ipv4 (surbl_req, DNS_QUERY_NO_SEARCH, dns_callback, (void *)param) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, dns_callback, (void *)param, DNS_REQUEST_A, surbl_req)) {
param->task->save.saved++;
register_async_event (task->s, (event_finalizer_t) dns_callback, NULL, TRUE);
}
}
else {
@@ -508,16 +507,18 @@ process_dns_results (struct worker_task *task, struct suffix_item *suffix, char
}

static void
dns_callback (int result, char type, int count, int ttl, void *addresses, void *data)
dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
{
struct dns_param *param = (struct dns_param *)data;
struct dns_param *param = (struct dns_param *)arg;
struct worker_task *task = param->task;
union rspamd_reply_element *elt;

debug_task ("in surbl request callback");
/* If we have result from DNS server, this url exists in SURBL, so increase score */
if (result == DNS_ERR_NONE && type == DNS_IPv4_A) {
if (reply->code == DNS_RC_NOERROR && reply->elements) {
msg_info ("<%s> domain [%s] is in surbl %s", param->task->message_id, param->host_resolve, param->suffix->suffix);
process_dns_results (param->task, param->suffix, param->host_resolve, (uint32_t) (((in_addr_t *) addresses)[0]));
elt = reply->elements->data;
process_dns_results (param->task, param->suffix, param->host_resolve, (uint32_t)elt->a.addr[0].s_addr);
}
else {
debug_task ("<%s> domain [%s] is not in surbl %s", param->task->message_id, param->host_resolve, param->suffix->suffix);
@@ -529,8 +530,6 @@ dns_callback (int result, char type, int count, int ttl, void *addresses, void *
param->task->save.saved = 1;
process_filters (param->task);
}
remove_forced_event (param->task->s, (event_finalizer_t) dns_callback);

}

static void

+ 94
- 103
src/spf.c Просмотреть файл

@@ -23,7 +23,7 @@
*/

#include "config.h"
#include "evdns/evdns.h"
#include "dns.h"
#include "spf.h"
#include "main.h"
#include "message.h"
@@ -228,101 +228,103 @@ parse_spf_hostmask (struct worker_task *task, const char *begin, struct spf_addr
}

static void
spf_record_dns_callback (int result, char type, int count, int ttl, void *addresses, void *data)
spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
{
struct spf_dns_cb *cb = data;
struct spf_dns_cb *cb = arg;
char *begin;
struct evdns_mx *mx;
GList *tmp = NULL, *elt, *last;
union rspamd_reply_element *elt_data;
GList *tmp = NULL, *tmp1, *elt, *last;
struct worker_task *task;

if (result == DNS_ERR_NONE) {
if (addresses != NULL) {
task = cb->rec->task;

if (reply->code == DNS_RC_NOERROR) {
if (reply->elements != NULL) {
/* Add all logic for all DNS states here */
switch (cb->cur_action) {
elt = reply->elements;
while (elt) {
elt_data = elt->data;
switch (cb->cur_action) {
case SPF_RESOLVE_MX:
if (type == DNS_MX) {
mx = (struct evdns_mx *)addresses;
if (reply->type == DNS_REQUEST_MX) {
/* Now resolve A record for this MX */
if (evdns_resolve_ipv4 (mx->host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
return;
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, elt_data->mx.name)) {
task->save.saved++;
}
}
else if (type == DNS_IPv4_A) {
else if (reply->type == DNS_REQUEST_A) {
/* XXX: process only one record */
cb->addr->addr = ntohl (*((uint32_t *)addresses));
cb->addr->addr = ntohl (elt_data->a.addr[0].s_addr);
}
break;
case SPF_RESOLVE_A:
if (type == DNS_IPv4_A) {
if (reply->type == DNS_REQUEST_A) {
/* XXX: process only one record */
cb->addr->addr = ntohl (*((uint32_t *)addresses));
cb->addr->addr = ntohl (elt_data->a.addr[0].s_addr);
}
break;
case SPF_RESOLVE_PTR:
break;
case SPF_RESOLVE_REDIRECT:
if (type == DNS_TXT) {
if (addresses != NULL) {
begin = *(char **)addresses;
if (reply->type == DNS_REQUEST_TXT) {
begin = elt_data->txt.data;

if (!cb->in_include && cb->rec->addrs) {
g_list_free (cb->rec->addrs);
cb->rec->addrs = NULL;
}
start_spf_parse (cb->rec, begin);
if (!cb->in_include && cb->rec->addrs) {
g_list_free (cb->rec->addrs);
cb->rec->addrs = NULL;
}
start_spf_parse (cb->rec, begin);

}
break;
case SPF_RESOLVE_INCLUDE:
if (type == DNS_TXT) {
if (addresses != NULL) {
begin = *(char **)addresses;
if (cb->rec->addrs) {
tmp = cb->rec->addrs;
cb->rec->addrs = NULL;
}
cb->rec->in_include = TRUE;
start_spf_parse (cb->rec, begin);
cb->rec->in_include = FALSE;

if (tmp) {
elt = g_list_find (tmp, cb->addr);
if (elt) {
/* Insert new list in place of include element */
last = g_list_last (cb->rec->addrs);
if (reply->type == DNS_REQUEST_TXT) {
begin = elt_data->txt.data;
if (cb->rec->addrs) {
tmp = cb->rec->addrs;
cb->rec->addrs = NULL;
}
cb->rec->in_include = TRUE;
start_spf_parse (cb->rec, begin);
cb->rec->in_include = FALSE;

if (tmp) {
tmp1 = g_list_find (tmp, cb->addr);
if (tmp1) {
/* Insert new list in place of include element */
last = g_list_last (cb->rec->addrs);

if (tmp1->prev == NULL && tmp1->next == NULL) {
g_list_free1 (tmp1);
}
else {

if (elt->prev == NULL && elt->next == NULL) {
g_list_free1 (elt);
if (tmp1->prev) {
tmp1->prev->next = cb->rec->addrs;
}
else {

if (elt->prev) {
elt->prev->next = cb->rec->addrs;
}
else {
/* Elt is the first element, so we need to shift temporary list */
tmp = elt->next;
tmp->prev = NULL;
}
if (elt->next) {
elt->next->prev = last;
if (last != NULL) {
last->next = elt->next;
}
}
if (cb->rec->addrs != NULL) {
cb->rec->addrs->prev = elt->prev;
/* Elt is the first element, so we need to shift temporary list */
tmp = tmp1->next;
tmp->prev = NULL;
}
if (tmp1->next) {
tmp1->next->prev = last;
if (last != NULL) {
last->next = tmp1->next;
}
}

/* Shift temporary list */
while (tmp->prev) {
tmp = tmp->prev;
}
if (cb->rec->addrs != NULL) {
cb->rec->addrs->prev = tmp1->prev;
}

cb->rec->addrs = tmp;
g_list_free1 (elt);
/* Shift temporary list */
while (tmp->prev) {
tmp = tmp->prev;
}

cb->rec->addrs = tmp;
g_list_free1 (tmp1);
}
}
}
@@ -331,29 +333,31 @@ spf_record_dns_callback (int result, char type, int count, int ttl, void *addres
case SPF_RESOLVE_EXP:
break;
case SPF_RESOLVE_EXISTS:
if (type == DNS_IPv4_A) {
if (reply->type == DNS_REQUEST_A) {
/* If specified address resolves, we can accept connection from every IP */
cb->addr->addr = ntohl (INADDR_ANY);
cb->addr->mask = 0;
}
break;
}
elt = g_list_next (elt);
}
}
}
else if (result == DNS_ERR_NOTEXIST) {
else if (reply->code == DNS_RC_NXDOMAIN) {
switch (cb->cur_action) {
case SPF_RESOLVE_MX:
if (type == DNS_MX) {
if (reply->type == DNS_REQUEST_MX) {
msg_info ("cannot find MX record for %s", cb->rec->cur_domain);
cb->addr->addr = ntohl (INADDR_NONE);
}
else if (type == DNS_IPv4_A) {
else if (reply->type != DNS_REQUEST_MX) {
msg_info ("cannot resolve MX record for %s", cb->rec->cur_domain);
cb->addr->addr = ntohl (INADDR_NONE);
}
break;
case SPF_RESOLVE_A:
if (type == DNS_IPv4_A) {
if (reply->type == DNS_REQUEST_A) {
/* XXX: process only one record */
cb->addr->addr = ntohl (INADDR_NONE);
}
@@ -382,8 +386,6 @@ spf_record_dns_callback (int result, char type, int count, int ttl, void *addres
cb->rec->addrs = NULL;
}
}
remove_forced_event (cb->rec->task->s, (event_finalizer_t) spf_record_dns_callback);

}

static gboolean
@@ -411,10 +413,8 @@ parse_spf_a (struct worker_task *task, const char *begin, struct spf_record *rec
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_A;
cb->in_include = rec->in_include;

if (evdns_resolve_ipv4 (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, host)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_record_dns_callback, NULL, TRUE);
return TRUE;
}
@@ -459,10 +459,8 @@ parse_spf_mx (struct worker_task *task, const char *begin, struct spf_record *re
cb->addr = addr;
cb->cur_action = SPF_RESOLVE_MX;
cb->in_include = rec->in_include;

if (evdns_resolve_mx (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_MX, host)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_record_dns_callback, NULL, TRUE);
return TRUE;
}
@@ -516,14 +514,13 @@ parse_spf_include (struct worker_task *task, const char *begin, struct spf_recor
cb->cur_action = SPF_RESOLVE_INCLUDE;
cb->in_include = rec->in_include;
domain = memory_pool_strdup (task->task_pool, begin);

if (evdns_resolve_txt (domain, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_TXT, domain)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_record_dns_callback, NULL, TRUE);
return TRUE;
}


return FALSE;
}

@@ -556,10 +553,8 @@ parse_spf_redirect (struct worker_task *task, const char *begin, struct spf_reco
cb->cur_action = SPF_RESOLVE_REDIRECT;
cb->in_include = rec->in_include;
domain = memory_pool_strdup (task->task_pool, begin);

if (evdns_resolve_txt (domain, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_TXT, domain)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_record_dns_callback, NULL, TRUE);
return TRUE;
}
@@ -589,9 +584,8 @@ parse_spf_exists (struct worker_task *task, const char *begin, struct spf_record
cb->in_include = rec->in_include;
host = memory_pool_strdup (task->task_pool, begin);

if (evdns_resolve_ipv4 (host, DNS_QUERY_NO_SEARCH, spf_record_dns_callback, (void *)cb) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, host)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_record_dns_callback, NULL, TRUE);
return TRUE;
}
@@ -1062,15 +1056,18 @@ start_spf_parse (struct spf_record *rec, char *begin)
}

static void
spf_dns_callback (int result, char type, int count, int ttl, void *addresses, void *data)
spf_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
{
struct spf_record *rec = data;
char *begin;

if (result == DNS_ERR_NONE && type == DNS_TXT) {
if (addresses != NULL) {
begin = *(char **)addresses;
start_spf_parse (rec, begin);
struct spf_record *rec = arg;
union rspamd_reply_element *elt;
GList *cur;

if (reply->code == DNS_RC_NOERROR) {
cur = reply->elements;
while (cur) {
elt = cur->data;
start_spf_parse (rec, elt->txt.data);
cur = g_list_next (cur);
}
}

@@ -1078,8 +1075,6 @@ spf_dns_callback (int result, char type, int count, int ttl, void *addresses, vo
if (rec->task->save.saved == 0 && rec->callback) {
rec->callback (rec, rec->task);
}
remove_forced_event (rec->task->s, (event_finalizer_t) spf_dns_callback);

}


@@ -1108,10 +1103,8 @@ resolve_spf (struct worker_task *task, spf_cb_t callback)
}
rec->sender_domain = rec->cur_domain;

if (evdns_resolve_txt (rec->cur_domain, DNS_QUERY_NO_SEARCH, spf_dns_callback, (void *)rec) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_dns_callback, (void *)rec, DNS_REQUEST_TXT, rec->cur_domain)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_dns_callback, NULL, TRUE);

return TRUE;
}
}
@@ -1138,10 +1131,8 @@ resolve_spf (struct worker_task *task, spf_cb_t callback)
*domain = '\0';
}
rec->sender_domain = rec->cur_domain;
if (evdns_resolve_txt (rec->cur_domain, DNS_QUERY_NO_SEARCH, spf_dns_callback, (void *)rec) == 0) {
if (make_dns_request (task->resolver, task->s, task->task_pool, spf_dns_callback, (void *)rec, DNS_REQUEST_TXT, rec->cur_domain)) {
task->save.saved++;
register_async_event (task->s, (event_finalizer_t) spf_dns_callback, NULL, TRUE);
return TRUE;
}
}

+ 1
- 1
test/rspamd_dns_test.c Просмотреть файл

@@ -33,7 +33,7 @@ test_dns_cb (struct rspamd_dns_reply *reply, gpointer arg)
msg_debug ("got spf %s", elt->spf.data);
break;
case DNS_REQUEST_SRV:
msg_debug ("got srv pri:%d, weight:%d, port: %d, target: %s", elt->srv.weight,
msg_debug ("got srv pri: %d, weight: %d, port: %d, target: %s", elt->srv.weight,
elt->srv.priority, elt->srv.port, elt->srv.target);
break;
case DNS_REQUEST_MX:

Загрузка…
Отмена
Сохранить