@@ -885,7 +885,6 @@ SET(RSPAMDSRC src/modules.c | |||
src/lua_worker.c | |||
src/main.c | |||
src/map.c | |||
src/smtp.c | |||
src/smtp_proxy.c | |||
src/webui.c | |||
src/worker.c) | |||
@@ -898,7 +897,7 @@ SET(PLUGINSSRC src/plugins/surbl.c | |||
src/plugins/dkim_check.c) | |||
SET(MODULES_LIST surbl regexp chartable fuzzy_check spf dkim) | |||
SET(WORKERS_LIST normal controller smtp smtp_proxy fuzzy lua webui) | |||
SET(WORKERS_LIST normal controller smtp_proxy fuzzy lua webui) | |||
AddModules(MODULES_LIST WORKERS_LIST) | |||
@@ -754,8 +754,7 @@ rspamd_dkim_dns_cb (struct rspamd_dns_reply *reply, gpointer arg) | |||
struct rspamd_dkim_key_cbdata *cbdata = arg; | |||
rspamd_dkim_key_t *key = NULL; | |||
GError *err = NULL; | |||
GList *cur; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
gsize keylen = 0; | |||
if (reply->code != DNS_RC_NOERROR) { | |||
@@ -764,14 +763,13 @@ rspamd_dkim_dns_cb (struct rspamd_dns_reply *reply, gpointer arg) | |||
cbdata->handler (NULL, 0, cbdata->ctx, cbdata->ud, err); | |||
} | |||
else { | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
key = rspamd_dkim_parse_key (elt->txt.data, &keylen, &err); | |||
if (key) { | |||
break; | |||
LL_FOREACH (reply->entries, elt) { | |||
if (elt->type == DNS_REQUEST_TXT) { | |||
key = rspamd_dkim_parse_key (elt->content.txt.data, &keylen, &err); | |||
if (key) { | |||
break; | |||
} | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
if (key != NULL && err != NULL) { | |||
/* Free error as it is insignificant */ |
@@ -25,48 +25,21 @@ | |||
#include "config.h" | |||
#include "dns.h" | |||
#include "dns_private.h" | |||
#include "main.h" | |||
#include "utlist.h" | |||
#include "chacha_private.h" | |||
#include "uthash.h" | |||
#ifdef HAVE_OPENSSL | |||
#include <openssl/rand.h> | |||
#endif | |||
/* Upstream timeouts */ | |||
#define DEFAULT_UPSTREAM_ERROR_TIME 10 | |||
#define DEFAULT_UPSTREAM_DEAD_TIME 300 | |||
#define DEFAULT_UPSTREAM_MAXERRORS 10 | |||
static const unsigned base = 36; | |||
static const unsigned t_min = 1; | |||
static const unsigned t_max = 26; | |||
static const unsigned skew = 38; | |||
static const unsigned damp = 700; | |||
static const unsigned initial_n = 128; | |||
static const unsigned initial_bias = 72; | |||
static const gint dns_port = 53; | |||
#define UDP_PACKET_SIZE 4096 | |||
#define DNS_COMPRESSION_BITS 0xC0 | |||
static void dns_retransmit_handler (gint fd, short what, void *arg); | |||
/* | |||
* DNS permutor utilities | |||
*/ | |||
#define PERMUTOR_BUF_SIZE 32768 | |||
#define PERMUTOR_KSIZE 32 | |||
#define PERMUTOR_IVSIZE 8 | |||
struct dns_permutor { | |||
chacha_ctx ctx; | |||
guchar perm_buf[PERMUTOR_BUF_SIZE]; | |||
guint pos; | |||
}; | |||
/** | |||
* Init chacha20 context | |||
* @param p | |||
@@ -87,11 +60,11 @@ dns_permutor_init (struct dns_permutor *p) | |||
} | |||
static struct dns_permutor * | |||
dns_permutor_new (memory_pool_t *pool) | |||
dns_permutor_new (void) | |||
{ | |||
struct dns_permutor *new; | |||
new = memory_pool_alloc0 (pool, sizeof (struct dns_permutor)); | |||
new = g_slice_alloc0 (sizeof (struct dns_permutor)); | |||
dns_permutor_init (new); | |||
return new; | |||
@@ -112,12 +85,14 @@ dns_permutor_generate_id (struct dns_permutor *p) | |||
} | |||
/* Punycode utility */ | |||
static guint digit(unsigned n) | |||
static guint | |||
digit (unsigned n) | |||
{ | |||
return "abcdefghijklmnopqrstuvwxyz0123456789"[n]; | |||
} | |||
static guint adapt(guint delta, guint numpoints, gint first) | |||
static guint | |||
adapt (guint delta, guint numpoints, gint first) | |||
{ | |||
guint k; | |||
@@ -256,34 +231,30 @@ struct dns_name_table { | |||
guint8 off; | |||
guint8 *label; | |||
guint8 len; | |||
UT_hash_handle hh; | |||
}; | |||
static gboolean | |||
try_compress_label (memory_pool_t *pool, guint8 *target, guint8 *start, guint8 len, guint8 *label, GList **table) | |||
try_compress_label (memory_pool_t *pool, guint8 *target, guint8 *start, guint8 len, | |||
guint8 *label, struct dns_name_table **table) | |||
{ | |||
GList *cur; | |||
struct dns_name_table *tbl; | |||
struct dns_name_table *found = NULL; | |||
guint16 pointer; | |||
cur = *table; | |||
while (cur) { | |||
tbl = cur->data; | |||
if (tbl->len == len) { | |||
if (memcmp (label, tbl->label, len) == 0) { | |||
pointer = htons ((guint16)tbl->off | 0xC0); | |||
memcpy (target, &pointer, sizeof (pointer)); | |||
return TRUE; | |||
} | |||
} | |||
cur = g_list_next (cur); | |||
HASH_FIND (hh, *table, label, len, found); | |||
if (found != NULL) { | |||
pointer = htons ((guint16)found->off | 0xC0); | |||
memcpy (target, &pointer, sizeof (pointer)); | |||
return TRUE; | |||
} | |||
else { | |||
/* Insert label to list */ | |||
found = memory_pool_alloc (pool, sizeof (struct dns_name_table)); | |||
found->off = target - start; | |||
found->label = label; | |||
found->len = len; | |||
HASH_ADD_KEYPTR (hh, *table, found->label, len, found); | |||
} | |||
/* Insert label to list */ | |||
tbl = memory_pool_alloc (pool, sizeof (struct dns_name_table)); | |||
tbl->off = target - start; | |||
tbl->label = label; | |||
tbl->len = len; | |||
*table = g_list_prepend (*table, tbl); | |||
return FALSE; | |||
} | |||
@@ -353,7 +324,7 @@ format_dns_name (struct rspamd_dns_request *req, const gchar *name, guint namele | |||
{ | |||
guint8 *pos = req->packet + req->pos, *end, *dot, *name_pos, *begin; | |||
guint remain = req->packet_len - req->pos - 5, label_len; | |||
GList *table = NULL; | |||
struct dns_name_table *table = NULL; | |||
gunichar *uclabel; | |||
glong uclabel_len; | |||
gsize punylabel_len; | |||
@@ -448,7 +419,7 @@ format_dns_name (struct rspamd_dns_request *req, const gchar *name, guint namele | |||
*pos = '\0'; | |||
req->pos += pos - (req->packet + req->pos) + 1; | |||
if (table != NULL) { | |||
g_list_free (table); | |||
HASH_CLEAR (hh, table); | |||
} | |||
} | |||
@@ -849,12 +820,13 @@ end: | |||
#define GET16(x) do {(x) = ((*p) << 8) + *(p + 1); p += sizeof (guint16); *remain -= sizeof (guint16); } while(0) | |||
#define GET32(x) do {(x) = ((*p) << 24) + ((*(p + 1)) << 16) + ((*(p + 2)) << 8) + *(p + 3); p += sizeof (guint32); *remain -= sizeof (guint32); } while(0) | |||
#define SKIP(type) do { p += sizeof(type); *remain -= sizeof(type); } while (0) | |||
static gint | |||
dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct rspamd_dns_reply *rep, gint *remain) | |||
dns_parse_rr (guint8 *in, struct rspamd_reply_entry *elt, guint8 **pos, struct rspamd_dns_reply *rep, gint *remain) | |||
{ | |||
guint8 *p = *pos, parts; | |||
guint16 type, datalen, txtlen, copied; | |||
guint16 type, datalen, txtlen, copied, ttl; | |||
gboolean parsed = FALSE; | |||
/* Skip the whole name */ | |||
@@ -867,146 +839,94 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct | |||
return -1; | |||
} | |||
GET16 (type); | |||
/* Skip ttl and class */ | |||
p += sizeof (guint16) + sizeof (guint32); | |||
*remain -= sizeof (guint16) + sizeof (guint32); | |||
GET16 (ttl); | |||
/* Skip class */ | |||
SKIP (guint32); | |||
GET16 (datalen); | |||
/* Now p points to RR data */ | |||
switch (type) { | |||
case DNS_T_A: | |||
if (rep->request->type != DNS_REQUEST_A) { | |||
if (!(datalen & 0x3) && datalen <= *remain) { | |||
memcpy (&elt->content.a.addr, p, sizeof (struct in_addr)); | |||
p += datalen; | |||
*remain -= datalen; | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_A; | |||
} | |||
else { | |||
if (!(datalen & 0x3) && datalen <= *remain) { | |||
memcpy (&elt->a.addr[0], p, sizeof (struct in_addr)); | |||
p += datalen; | |||
*remain -= datalen; | |||
parsed = TRUE; | |||
} | |||
else { | |||
msg_info ("corrupted A record"); | |||
return -1; | |||
} | |||
msg_info ("corrupted A record"); | |||
return -1; | |||
} | |||
break; | |||
#ifdef HAVE_INET_PTON | |||
case DNS_T_AAAA: | |||
if (rep->request->type != DNS_REQUEST_AAA) { | |||
if (datalen == sizeof (struct in6_addr) && datalen <= *remain) { | |||
memcpy (&elt->content.aaa.addr, p, sizeof (struct in6_addr)); | |||
p += datalen; | |||
*remain -= datalen; | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_AAA; | |||
} | |||
else { | |||
if (datalen == sizeof (struct in6_addr) && datalen <= *remain) { | |||
memcpy (&elt->aaa.addr, p, sizeof (struct in6_addr)); | |||
p += datalen; | |||
*remain -= datalen; | |||
parsed = TRUE; | |||
} | |||
else { | |||
msg_info ("corrupted AAAA record"); | |||
return -1; | |||
} | |||
msg_info ("corrupted AAAA record"); | |||
return -1; | |||
} | |||
break; | |||
#endif | |||
case DNS_T_PTR: | |||
if (rep->request->type != DNS_REQUEST_PTR) { | |||
p += datalen; | |||
*remain -= datalen; | |||
} | |||
else { | |||
if (! dns_parse_labels (in, &elt->ptr.name, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in PTR record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
if (! dns_parse_labels (in, &elt->content.ptr.name, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in PTR record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_PTR; | |||
break; | |||
case DNS_T_MX: | |||
if (rep->request->type != DNS_REQUEST_MX) { | |||
p += datalen; | |||
*remain -= datalen; | |||
} | |||
else { | |||
GET16 (elt->mx.priority); | |||
if (! dns_parse_labels (in, &elt->mx.name, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in MX record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
GET16 (elt->content.mx.priority); | |||
if (! dns_parse_labels (in, &elt->content.mx.name, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in MX record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_MX; | |||
break; | |||
case DNS_T_TXT: | |||
if (rep->request->type != DNS_REQUEST_TXT) { | |||
p += datalen; | |||
*remain -= datalen; | |||
} | |||
else { | |||
elt->txt.data = memory_pool_alloc (rep->request->pool, datalen + 1); | |||
/* Now we should compose data from parts */ | |||
copied = 0; | |||
parts = 0; | |||
while (copied + parts < datalen) { | |||
txtlen = *p; | |||
if (txtlen + copied + parts <= datalen) { | |||
parts ++; | |||
memcpy (elt->txt.data + copied, p + 1, txtlen); | |||
copied += txtlen; | |||
p += txtlen + 1; | |||
*remain -= txtlen + 1; | |||
} | |||
else { | |||
break; | |||
} | |||
} | |||
*(elt->txt.data + copied) = '\0'; | |||
parsed = TRUE; | |||
} | |||
break; | |||
case DNS_T_SPF: | |||
if (rep->request->type != DNS_REQUEST_SPF) { | |||
p += datalen; | |||
*remain -= datalen; | |||
} | |||
else { | |||
copied = 0; | |||
elt->txt.data = memory_pool_alloc (rep->request->pool, datalen + 1); | |||
while (copied < datalen) { | |||
txtlen = *p; | |||
if (txtlen + copied < datalen) { | |||
memcpy (elt->txt.data + copied, p + 1, txtlen); | |||
copied += txtlen; | |||
p += txtlen + 1; | |||
*remain -= txtlen + 1; | |||
} | |||
else { | |||
break; | |||
} | |||
elt->content.txt.data = memory_pool_alloc (rep->request->pool, datalen + 1); | |||
/* Now we should compose data from parts */ | |||
copied = 0; | |||
parts = 0; | |||
while (copied + parts < datalen) { | |||
txtlen = *p; | |||
if (txtlen + copied + parts <= datalen) { | |||
parts ++; | |||
memcpy (elt->content.txt.data + copied, p + 1, txtlen); | |||
copied += txtlen; | |||
p += txtlen + 1; | |||
*remain -= txtlen + 1; | |||
} | |||
else { | |||
break; | |||
} | |||
*(elt->spf.data + copied) = '\0'; | |||
parsed = TRUE; | |||
} | |||
*(elt->content.txt.data + copied) = '\0'; | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_TXT; | |||
break; | |||
case DNS_T_SRV: | |||
if (rep->request->type != DNS_REQUEST_SRV) { | |||
p += datalen; | |||
*remain -= datalen; | |||
if (p - *pos > (gint)(*remain - sizeof (guint16) * 3)) { | |||
msg_info ("stripped dns reply while reading SRV record"); | |||
return -1; | |||
} | |||
else { | |||
if (p - *pos > (gint)(*remain - sizeof (guint16) * 3)) { | |||
msg_info ("stripped dns reply while reading SRV record"); | |||
return -1; | |||
} | |||
GET16 (elt->srv.priority); | |||
GET16 (elt->srv.weight); | |||
GET16 (elt->srv.port); | |||
if (! dns_parse_labels (in, &elt->srv.target, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in SRV record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
GET16 (elt->content.srv.priority); | |||
GET16 (elt->content.srv.weight); | |||
GET16 (elt->content.srv.port); | |||
if (! dns_parse_labels (in, &elt->content.srv.target, &p, rep, remain, TRUE)) { | |||
msg_info ("invalid labels in SRV record"); | |||
return -1; | |||
} | |||
parsed = TRUE; | |||
elt->type = DNS_REQUEST_SRV; | |||
break; | |||
case DNS_T_CNAME: | |||
/* Skip cname records */ | |||
@@ -1022,6 +942,7 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct | |||
*pos = p; | |||
if (parsed) { | |||
elt->ttl = ttl; | |||
return 1; | |||
} | |||
return 0; | |||
@@ -1035,7 +956,7 @@ dns_parse_reply (gint sock, guint8 *in, gint r, struct rspamd_dns_resolver *reso | |||
struct rspamd_dns_request *req; | |||
struct rspamd_dns_reply *rep; | |||
struct rspamd_dns_io_channel *ioc; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
guint8 *pos; | |||
guint16 id; | |||
gint i, t; | |||
@@ -1074,27 +995,23 @@ dns_parse_reply (gint sock, guint8 *in, gint r, struct rspamd_dns_resolver *reso | |||
*/ | |||
rep = memory_pool_alloc (req->pool, sizeof (struct rspamd_dns_reply)); | |||
rep->request = req; | |||
rep->type = req->type; | |||
rep->elements = NULL; | |||
rep->entries = NULL; | |||
rep->code = header->rcode; | |||
if (rep->code == DNS_RC_NOERROR) { | |||
r -= pos - in; | |||
/* Extract RR records */ | |||
for (i = 0; i < ntohs (header->ancount); i ++) { | |||
elt = memory_pool_alloc (req->pool, sizeof (union rspamd_reply_element)); | |||
elt = memory_pool_alloc (req->pool, sizeof (struct rspamd_reply_entry)); | |||
t = dns_parse_rr (in, elt, &pos, rep, &r); | |||
if (t == -1) { | |||
msg_info ("incomplete reply"); | |||
break; | |||
} | |||
else if (t == 1) { | |||
rep->elements = g_list_prepend (rep->elements, elt); | |||
DL_APPEND (rep->entries, elt); | |||
} | |||
} | |||
if (rep->elements) { | |||
memory_pool_add_destructor (req->pool, (pool_destruct_func)g_list_free, rep->elements); | |||
} | |||
} | |||
*_rep = rep; | |||
@@ -1387,8 +1304,6 @@ make_dns_request (struct rspamd_dns_resolver *resolver, | |||
return TRUE; | |||
} | |||
#define RESOLV_CONF "/etc/resolv.conf" | |||
static gboolean | |||
parse_resolv_conf (struct rspamd_dns_resolver *resolver) | |||
{ | |||
@@ -1419,7 +1334,7 @@ parse_resolv_conf (struct rspamd_dns_resolver *resolver) | |||
if (inet_pton (AF_INET6, p, addr_holder) == 1 || | |||
inet_pton (AF_INET, p, addr_holder) == 1) { | |||
new = &resolver->servers[resolver->servers_num]; | |||
new->name = memory_pool_strdup (resolver->static_pool, p); | |||
new->name = strdup (p); | |||
resolver->servers_num ++; | |||
} | |||
else { | |||
@@ -1459,11 +1374,10 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) | |||
struct rspamd_dns_server *serv; | |||
struct rspamd_dns_io_channel *ioc; | |||
new = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_dns_resolver)); | |||
new = g_slice_alloc0 (sizeof (struct rspamd_dns_resolver)); | |||
new->ev_base = ev_base; | |||
new->permutor = dns_permutor_new (cfg->cfg_pool); | |||
new->permutor = dns_permutor_new (); | |||
new->io_channels = g_hash_table_new (g_direct_hash, g_direct_equal); | |||
new->static_pool = cfg->cfg_pool; | |||
new->request_timeout = cfg->dns_timeout; | |||
new->max_retransmits = cfg->dns_retransmits; | |||
new->max_errors = cfg->dns_throttling_errors; | |||
@@ -1512,7 +1426,7 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) | |||
serv = &new->servers[new->servers_num]; | |||
if (inet_pton (AF_INET6, p, addr_holder) == 1 || | |||
inet_pton (AF_INET, p, addr_holder) == 1) { | |||
serv->name = memory_pool_strdup (new->static_pool, begin); | |||
serv->name = strdup (begin); | |||
serv->up.priority = priority; | |||
new->servers_num ++; | |||
} | |||
@@ -1537,15 +1451,13 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) | |||
for (i = 0; i < new->servers_num; i ++) { | |||
serv = &new->servers[i]; | |||
for (j = 0; j < (gint)cfg->dns_io_per_server; j ++) { | |||
ioc = memory_pool_alloc (new->static_pool, sizeof (struct rspamd_dns_io_channel)); | |||
ioc = g_slice_alloc0 (sizeof (struct rspamd_dns_io_channel)); | |||
ioc->sock = make_universal_socket (serv->name, dns_port, SOCK_DGRAM, TRUE, FALSE, FALSE); | |||
if (ioc->sock == -1) { | |||
msg_warn ("cannot create socket to server %s", serv->name); | |||
} | |||
else { | |||
ioc->requests = g_hash_table_new (dns_id_hash, dns_id_equal); | |||
memory_pool_add_destructor (new->static_pool, (pool_destruct_func)g_hash_table_unref, | |||
ioc->requests); | |||
ioc->srv = serv; | |||
ioc->resolver = new; | |||
event_set (&ioc->ev, ioc->sock, EV_READ | EV_PERSIST, dns_read_cb, new); | |||
@@ -1561,20 +1473,6 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) | |||
return new; | |||
} | |||
static gchar dns_rcodes[16][16] = { | |||
[DNS_RC_NOERROR] = "NOERROR", | |||
[DNS_RC_FORMERR] = "FORMERR", | |||
[DNS_RC_SERVFAIL] = "SERVFAIL", | |||
[DNS_RC_NXDOMAIN] = "NXDOMAIN", | |||
[DNS_RC_NOTIMP] = "NOTIMP", | |||
[DNS_RC_REFUSED] = "REFUSED", | |||
[DNS_RC_YXDOMAIN] = "YXDOMAIN", | |||
[DNS_RC_YXRRSET] = "YXRRSET", | |||
[DNS_RC_NXRRSET] = "NXRRSET", | |||
[DNS_RC_NOTAUTH] = "NOTAUTH", | |||
[DNS_RC_NOTZONE] = "NOTZONE", | |||
}; | |||
const gchar * | |||
dns_strerror (enum dns_rcode rcode) | |||
{ | |||
@@ -1588,16 +1486,6 @@ dns_strerror (enum dns_rcode rcode) | |||
return dns_rcodes[rcode]; | |||
} | |||
static gchar dns_types[7][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", | |||
[DNS_REQUEST_AAA] = "AAA request" | |||
}; | |||
const gchar * | |||
dns_strtype (enum rspamd_request_type type) | |||
{ |
@@ -31,62 +31,11 @@ | |||
#include "events.h" | |||
#include "upstream.h" | |||
#define MAX_SERVERS 16 | |||
#define DNS_D_MAXLABEL 63 /* + 1 '\0' */ | |||
#define DNS_D_MAXNAME 255 /* + 1 '\0' */ | |||
#define MAX_ADDRS 10 | |||
struct rspamd_dns_reply; | |||
struct config_file; | |||
typedef void (*dns_callback_type) (struct rspamd_dns_reply *reply, gpointer arg); | |||
/** | |||
* Represents DNS server | |||
*/ | |||
struct rspamd_dns_server { | |||
struct upstream up; /**< upstream structure */ | |||
gchar *name; /**< name of DNS server */ | |||
struct rspamd_dns_io_channel *io_channels; | |||
struct rspamd_dns_io_channel *cur_io_channel; | |||
}; | |||
/** | |||
* IO channel for a specific DNS server | |||
*/ | |||
struct rspamd_dns_io_channel { | |||
struct rspamd_dns_server *srv; | |||
struct rspamd_dns_resolver *resolver; | |||
gint sock; /**< persistent socket */ | |||
struct event ev; | |||
GHashTable *requests; /**< requests in flight */ | |||
struct rspamd_dns_io_channel *prev, *next; | |||
}; | |||
struct dns_permutor; | |||
struct rspamd_dns_resolver { | |||
struct rspamd_dns_server servers[MAX_SERVERS]; | |||
gint servers_num; /**< number of DNS servers registered */ | |||
struct dns_permutor *permutor; /**< permutor for randomizing request id */ | |||
guint request_timeout; | |||
guint max_retransmits; | |||
guint max_errors; | |||
GHashTable *io_channels; /**< hash of io chains indexed by socket */ | |||
memory_pool_t *static_pool; /**< permament pool (cfg_pool) */ | |||
gboolean throttling; /**< dns servers are busy */ | |||
gboolean is_master_slave; /**< if this is true, then select upstreams as master/slave */ | |||
guint errors; /**< resolver errors */ | |||
struct timeval throttling_time; /**< throttling time */ | |||
struct event throttling_event; /**< throttling event */ | |||
struct event_base *ev_base; /**< base for event ops */ | |||
}; | |||
struct dns_header; | |||
struct dns_query; | |||
enum rspamd_request_type { | |||
DNS_REQUEST_A = 0, | |||
DNS_REQUEST_PTR, | |||
@@ -117,13 +66,12 @@ struct rspamd_dns_request { | |||
gint sock; | |||
enum rspamd_request_type type; | |||
time_t time; | |||
struct rspamd_dns_request *next; | |||
}; | |||
union rspamd_reply_element { | |||
union rspamd_reply_element_un { | |||
struct { | |||
struct in_addr addr[MAX_ADDRS]; | |||
struct in_addr addr; | |||
guint16 addrcount; | |||
} a; | |||
#ifdef HAVE_INET_PTON | |||
@@ -141,9 +89,6 @@ union rspamd_reply_element { | |||
struct { | |||
gchar *data; | |||
} txt; | |||
struct { | |||
gchar *data; | |||
} spf; | |||
struct { | |||
guint16 priority; | |||
guint16 weight; | |||
@@ -152,6 +97,14 @@ union rspamd_reply_element { | |||
} srv; | |||
}; | |||
struct rspamd_reply_entry { | |||
union rspamd_reply_element_un content; | |||
guint16 type; | |||
guint16 ttl; | |||
struct rspamd_reply_entry *prev, *next; | |||
}; | |||
enum dns_rcode { | |||
DNS_RC_NOERROR = 0, | |||
DNS_RC_FORMERR = 1, | |||
@@ -167,97 +120,11 @@ enum dns_rcode { | |||
}; | |||
struct rspamd_dns_reply { | |||
enum rspamd_request_type type; | |||
struct rspamd_dns_request *request; | |||
enum dns_rcode code; | |||
GList *elements; | |||
struct rspamd_reply_entry *entries; | |||
}; | |||
/* Internal DNS structs */ | |||
struct dns_header { | |||
guint qid:16; | |||
#if BYTE_ORDER == BIG_ENDIAN | |||
guint qr:1; | |||
guint opcode:4; | |||
guint aa:1; | |||
guint tc:1; | |||
guint rd:1; | |||
guint ra:1; | |||
guint unused:3; | |||
guint rcode:4; | |||
#else | |||
guint rd:1; | |||
guint tc:1; | |||
guint aa:1; | |||
guint opcode:4; | |||
guint qr:1; | |||
guint rcode:4; | |||
guint unused:3; | |||
guint ra:1; | |||
#endif | |||
guint qdcount:16; | |||
guint ancount:16; | |||
guint nscount:16; | |||
guint arcount:16; | |||
}; | |||
enum dns_section { | |||
DNS_S_QD = 0x01, | |||
#define DNS_S_QUESTION DNS_S_QD | |||
DNS_S_AN = 0x02, | |||
#define DNS_S_ANSWER DNS_S_AN | |||
DNS_S_NS = 0x04, | |||
#define DNS_S_AUTHORITY DNS_S_NS | |||
DNS_S_AR = 0x08, | |||
#define DNS_S_ADDITIONAL DNS_S_AR | |||
DNS_S_ALL = 0x0f | |||
}; /* enum dns_section */ | |||
enum dns_opcode { | |||
DNS_OP_QUERY = 0, | |||
DNS_OP_IQUERY = 1, | |||
DNS_OP_STATUS = 2, | |||
DNS_OP_NOTIFY = 4, | |||
DNS_OP_UPDATE = 5, | |||
}; /* dns_opcode */ | |||
enum dns_type { | |||
DNS_T_A = 1, | |||
DNS_T_NS = 2, | |||
DNS_T_CNAME = 5, | |||
DNS_T_SOA = 6, | |||
DNS_T_PTR = 12, | |||
DNS_T_MX = 15, | |||
DNS_T_TXT = 16, | |||
DNS_T_AAAA = 28, | |||
DNS_T_SRV = 33, | |||
DNS_T_OPT = 41, | |||
DNS_T_SSHFP = 44, | |||
DNS_T_SPF = 99, | |||
DNS_T_ALL = 255 | |||
}; /* enum dns_type */ | |||
enum dns_class { | |||
DNS_C_IN = 1, | |||
DNS_C_ANY = 255 | |||
}; /* enum dns_class */ | |||
struct dns_query { | |||
gchar *qname; | |||
guint qtype:16; | |||
guint qclass:16; | |||
}; | |||
/* Rspamd DNS API */ | |||
@@ -0,0 +1,222 @@ | |||
/* Copyright (c) 2014, Vsevolod Stakhov | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright | |||
* notice, this list of conditions and the following disclaimer in the | |||
* documentation and/or other materials provided with the distribution. | |||
* | |||
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY | |||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY | |||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#ifndef DNS_PRIVATE_H_ | |||
#define DNS_PRIVATE_H_ | |||
#include "config.h" | |||
#include "chacha_private.h" | |||
#define MAX_SERVERS 16 | |||
/* Upstream timeouts */ | |||
#define DEFAULT_UPSTREAM_ERROR_TIME 10 | |||
#define DEFAULT_UPSTREAM_DEAD_TIME 300 | |||
#define DEFAULT_UPSTREAM_MAXERRORS 10 | |||
static const unsigned base = 36; | |||
static const unsigned t_min = 1; | |||
static const unsigned t_max = 26; | |||
static const unsigned skew = 38; | |||
static const unsigned damp = 700; | |||
static const unsigned initial_n = 128; | |||
static const unsigned initial_bias = 72; | |||
static const gint dns_port = 53; | |||
#define UDP_PACKET_SIZE 4096 | |||
#define DNS_COMPRESSION_BITS 0xC0 | |||
#define DNS_D_MAXLABEL 63 /* + 1 '\0' */ | |||
#define DNS_D_MAXNAME 255 /* + 1 '\0' */ | |||
#define PERMUTOR_BUF_SIZE 32768 | |||
#define PERMUTOR_KSIZE 32 | |||
#define PERMUTOR_IVSIZE 8 | |||
#define RESOLV_CONF "/etc/resolv.conf" | |||
/** | |||
* Represents DNS server | |||
*/ | |||
struct rspamd_dns_server { | |||
struct upstream up; /**< upstream structure */ | |||
gchar *name; /**< name of DNS server */ | |||
struct rspamd_dns_io_channel *io_channels; | |||
struct rspamd_dns_io_channel *cur_io_channel; | |||
}; | |||
/** | |||
* IO channel for a specific DNS server | |||
*/ | |||
struct rspamd_dns_io_channel { | |||
struct rspamd_dns_server *srv; | |||
struct rspamd_dns_resolver *resolver; | |||
gint sock; /**< persistent socket */ | |||
struct event ev; | |||
GHashTable *requests; /**< requests in flight */ | |||
struct rspamd_dns_io_channel *prev, *next; | |||
}; | |||
struct dns_permutor; | |||
struct rspamd_dns_resolver { | |||
struct rspamd_dns_server servers[MAX_SERVERS]; | |||
gint servers_num; /**< number of DNS servers registered */ | |||
struct dns_permutor *permutor; /**< permutor for randomizing request id */ | |||
guint request_timeout; | |||
guint max_retransmits; | |||
guint max_errors; | |||
GHashTable *io_channels; /**< hash of io chains indexed by socket */ | |||
gboolean throttling; /**< dns servers are busy */ | |||
gboolean is_master_slave; /**< if this is true, then select upstreams as master/slave */ | |||
guint errors; /**< resolver errors */ | |||
struct timeval throttling_time; /**< throttling time */ | |||
struct event throttling_event; /**< throttling event */ | |||
struct event_base *ev_base; /**< base for event ops */ | |||
}; | |||
struct dns_header; | |||
struct dns_query; | |||
/* Internal DNS structs */ | |||
struct dns_header { | |||
guint qid :16; | |||
#if BYTE_ORDER == BIG_ENDIAN | |||
guint qr:1; | |||
guint opcode:4; | |||
guint aa:1; | |||
guint tc:1; | |||
guint rd:1; | |||
guint ra:1; | |||
guint unused:3; | |||
guint rcode:4; | |||
#else | |||
guint rd :1; | |||
guint tc :1; | |||
guint aa :1; | |||
guint opcode :4; | |||
guint qr :1; | |||
guint rcode :4; | |||
guint unused :3; | |||
guint ra :1; | |||
#endif | |||
guint qdcount :16; | |||
guint ancount :16; | |||
guint nscount :16; | |||
guint arcount :16; | |||
}; | |||
enum dns_section { | |||
DNS_S_QD = 0x01, | |||
#define DNS_S_QUESTION DNS_S_QD | |||
DNS_S_AN = 0x02, | |||
#define DNS_S_ANSWER DNS_S_AN | |||
DNS_S_NS = 0x04, | |||
#define DNS_S_AUTHORITY DNS_S_NS | |||
DNS_S_AR = 0x08, | |||
#define DNS_S_ADDITIONAL DNS_S_AR | |||
DNS_S_ALL = 0x0f | |||
}; | |||
/* enum dns_section */ | |||
enum dns_opcode { | |||
DNS_OP_QUERY = 0, | |||
DNS_OP_IQUERY = 1, | |||
DNS_OP_STATUS = 2, | |||
DNS_OP_NOTIFY = 4, | |||
DNS_OP_UPDATE = 5, | |||
}; | |||
/* dns_opcode */ | |||
enum dns_class { | |||
DNS_C_IN = 1, | |||
DNS_C_ANY = 255 | |||
}; | |||
/* enum dns_class */ | |||
struct dns_query { | |||
gchar *qname; | |||
guint qtype :16; | |||
guint qclass :16; | |||
}; | |||
enum dns_type { | |||
DNS_T_A = 1, | |||
DNS_T_NS = 2, | |||
DNS_T_CNAME = 5, | |||
DNS_T_SOA = 6, | |||
DNS_T_PTR = 12, | |||
DNS_T_MX = 15, | |||
DNS_T_TXT = 16, | |||
DNS_T_AAAA = 28, | |||
DNS_T_SRV = 33, | |||
DNS_T_OPT = 41, | |||
DNS_T_SSHFP = 44, | |||
DNS_T_SPF = 99, | |||
DNS_T_ALL = 255 | |||
}; | |||
/* enum dns_type */ | |||
struct dns_permutor { | |||
chacha_ctx ctx; | |||
guchar perm_buf[PERMUTOR_BUF_SIZE]; | |||
guint pos; | |||
}; | |||
static const gchar dns_rcodes[16][16] = { | |||
[DNS_RC_NOERROR] = "NOERROR", | |||
[DNS_RC_FORMERR] = "FORMERR", | |||
[DNS_RC_SERVFAIL] = "SERVFAIL", | |||
[DNS_RC_NXDOMAIN] = "NXDOMAIN", | |||
[DNS_RC_NOTIMP] = "NOTIMP", | |||
[DNS_RC_REFUSED] = "REFUSED", | |||
[DNS_RC_YXDOMAIN] = "YXDOMAIN", | |||
[DNS_RC_YXRRSET] = "YXRRSET", | |||
[DNS_RC_NXRRSET] = "NXRRSET", | |||
[DNS_RC_NOTAUTH] = "NOTAUTH", | |||
[DNS_RC_NOTZONE] = "NOTZONE", | |||
}; | |||
static const gchar dns_types[7][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", | |||
[DNS_REQUEST_AAA] = "AAA request" | |||
}; | |||
#endif /* DNS_PRIVATE_H_ */ |
@@ -71,8 +71,7 @@ lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
struct lua_dns_cbdata *cd = arg; | |||
gint i = 0; | |||
struct rspamd_dns_resolver **presolver; | |||
union rspamd_reply_element *elt; | |||
GList *cur; | |||
struct rspamd_reply_entry *elt; | |||
lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->cbref); | |||
presolver = lua_newuserdata (cd->L, sizeof (gpointer)); | |||
@@ -81,77 +80,50 @@ lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
*presolver = cd->resolver; | |||
lua_pushstring (cd->L, cd->to_resolve); | |||
/* | |||
* XXX: rework to handle different request types | |||
*/ | |||
if (reply->code == DNS_RC_NOERROR) { | |||
if (reply->type == DNS_REQUEST_A) { | |||
lua_newtable (cd->L); | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
lua_ip_push (cd->L, AF_INET, &elt->a.addr); | |||
lua_rawseti (cd->L, -2, ++i); | |||
cur = g_list_next (cur); | |||
lua_newtable (cd->L); | |||
LL_FOREACH (reply->entries, elt) { | |||
if (elt->type != reply->request->type) { | |||
/* | |||
* XXX: Skip additional record here to be compatible | |||
* with the existing plugins | |||
*/ | |||
continue; | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else if (reply->type == DNS_REQUEST_AAA) { | |||
lua_newtable (cd->L); | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
lua_ip_push (cd->L, AF_INET6, &elt->aaa.addr); | |||
switch (elt->type) { | |||
case DNS_REQUEST_A: | |||
lua_ip_push (cd->L, AF_INET, &elt->content.a.addr); | |||
lua_rawseti (cd->L, -2, ++i); | |||
cur = g_list_next (cur); | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else if (reply->type == DNS_REQUEST_PTR) { | |||
lua_newtable (cd->L); | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
lua_pushstring (cd->L, elt->ptr.name); | |||
break; | |||
case DNS_REQUEST_AAA: | |||
lua_ip_push (cd->L, AF_INET6, &elt->content.aaa.addr); | |||
lua_rawseti (cd->L, -2, ++i); | |||
cur = g_list_next (cur); | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else if (reply->type == DNS_REQUEST_TXT) { | |||
lua_newtable (cd->L); | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
lua_pushstring (cd->L, elt->txt.data); | |||
break; | |||
case DNS_REQUEST_PTR: | |||
lua_pushstring (cd->L, elt->content.ptr.name); | |||
lua_rawseti (cd->L, -2, ++i); | |||
cur = g_list_next (cur); | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else if (reply->type == DNS_REQUEST_MX) { | |||
lua_newtable (cd->L); | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
break; | |||
case DNS_REQUEST_TXT: | |||
case DNS_REQUEST_SPF: | |||
lua_pushstring (cd->L, elt->content.txt.data); | |||
lua_rawseti (cd->L, -2, ++i); | |||
break; | |||
case DNS_REQUEST_MX: | |||
/* mx['name'], mx['priority'] */ | |||
lua_newtable (cd->L); | |||
lua_set_table_index (cd->L, "name", elt->mx.name); | |||
lua_set_table_index (cd->L, "name", elt->content.mx.name); | |||
lua_pushstring (cd->L, "priority"); | |||
lua_pushnumber (cd->L, elt->mx.priority); | |||
lua_pushnumber (cd->L, elt->content.mx.priority); | |||
lua_settable (cd->L, -3); | |||
lua_rawseti (cd->L, -2, ++i); | |||
cur = g_list_next (cur); | |||
break; | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else { | |||
lua_pushnil (cd->L); | |||
lua_pushstring (cd->L, "Unknown reply type"); | |||
} | |||
lua_pushnil (cd->L); | |||
} | |||
else { | |||
lua_pushnil (cd->L); |
@@ -302,7 +302,7 @@ static void | |||
lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
{ | |||
struct lua_http_ud *ud = arg; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
struct in_addr ina; | |||
struct timeval tv; | |||
@@ -312,8 +312,8 @@ lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
} | |||
/* Create socket to server */ | |||
elt = reply->elements->data; | |||
memcpy (&ina, &elt->a.addr[0], sizeof (struct in_addr)); | |||
elt = reply->entries; | |||
memcpy (&ina, &elt->content.a.addr, sizeof (struct in_addr)); | |||
ud->fd = make_universal_socket (inet_ntoa (ina), ud->port, SOCK_STREAM, TRUE, FALSE, FALSE); | |||
@@ -243,7 +243,7 @@ static void | |||
lua_redis_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
{ | |||
struct lua_redis_userdata *ud = arg; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
if (reply->code != DNS_RC_NOERROR) { | |||
@@ -251,8 +251,8 @@ lua_redis_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
return; | |||
} | |||
else { | |||
elt = reply->elements->data; | |||
memcpy (&ud->ina, &elt->a.addr[0], sizeof (struct in_addr)); | |||
elt = reply->entries; | |||
memcpy (&ud->ina, &elt->content.a.addr, sizeof (struct in_addr)); | |||
/* Make real request */ | |||
lua_redis_make_request_real (ud); | |||
} |
@@ -674,14 +674,16 @@ dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
{ | |||
struct dns_param *param = (struct dns_param *)arg; | |||
struct worker_task *task = param->task; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
debug_task ("in surbl request callback"); | |||
/* If we have result from DNS server, this url exists in SURBL, so increase score */ | |||
if (reply->code == DNS_RC_NOERROR && reply->elements) { | |||
if (reply->code == DNS_RC_NOERROR && reply->entries) { | |||
msg_info ("<%s> domain [%s] is in surbl %s", param->task->message_id, param->host_resolve, param->suffix->suffix); | |||
elt = reply->elements->data; | |||
process_dns_results (param->task, param->suffix, param->host_resolve, (guint32)elt->a.addr[0].s_addr); | |||
elt = reply->entries; | |||
if (elt->type == DNS_REQUEST_A) { | |||
process_dns_results (param->task, param->suffix, param->host_resolve, (guint32)elt->content.a.addr.s_addr); | |||
} | |||
} | |||
else { | |||
debug_task ("<%s> domain [%s] is not in surbl %s", param->task->message_id, param->host_resolve, param->suffix->suffix); |
@@ -652,7 +652,7 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg) | |||
{ | |||
struct smtp_proxy_session *session = arg; | |||
gint res = 0; | |||
union rspamd_reply_element *elt; | |||
struct rspamd_reply_entry *elt; | |||
GList *cur; | |||
switch (session->state) | |||
@@ -676,10 +676,10 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg) | |||
smtp_make_delay (session); | |||
} | |||
else { | |||
if (reply->elements) { | |||
elt = reply->elements->data; | |||
if (reply->entries) { | |||
elt = reply->entries; | |||
session->hostname = memory_pool_strdup (session->pool, | |||
elt->ptr.name); | |||
elt->content.ptr.name); | |||
session->state = SMTP_PROXY_STATE_RESOLVE_NORMAL; | |||
make_dns_request (session->resolver, session->s, session->pool, | |||
smtp_dns_cb, session, DNS_REQUEST_A, session->hostname); | |||
@@ -706,10 +706,8 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg) | |||
} | |||
else { | |||
res = 0; | |||
cur = reply->elements; | |||
while (cur) { | |||
elt = cur->data; | |||
if (memcmp (&session->client_addr, &elt->a.addr[0], | |||
LL_FOREACH (reply->entries, elt) { | |||
if (memcmp (&session->client_addr, &elt->content.a.addr, | |||
sizeof(struct in_addr)) == 0) { | |||
res = 1; | |||
session->resolved = TRUE; |
@@ -391,8 +391,8 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
{ | |||
struct spf_dns_cb *cb = arg; | |||
gchar *begin; | |||
union rspamd_reply_element *elt_data; | |||
GList *tmp = NULL, *elt; | |||
struct rspamd_reply_entry *elt_data; | |||
GList *tmp = NULL; | |||
struct worker_task *task; | |||
struct spf_addr *new_addr; | |||
@@ -401,165 +401,160 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
cb->rec->requests_inflight --; | |||
if (reply->code == DNS_RC_NOERROR) { | |||
if (reply->elements != NULL) { | |||
/* Add all logic for all DNS states here */ | |||
elt = reply->elements; | |||
while (elt) { | |||
elt_data = elt->data; | |||
switch (cb->cur_action) { | |||
case SPF_RESOLVE_MX: | |||
if (reply->type == DNS_REQUEST_MX) { | |||
/* Now resolve A record for this MX */ | |||
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->dns_requests ++; | |||
cb->rec->requests_inflight ++; | |||
} | |||
/* Add all logic for all DNS states here */ | |||
LL_FOREACH (reply->entries, elt_data) { | |||
switch (cb->cur_action) { | |||
case SPF_RESOLVE_MX: | |||
if (elt_data->type == DNS_REQUEST_MX) { | |||
/* Now resolve A record for this MX */ | |||
if (make_dns_request (task->resolver, task->s, task->task_pool, | |||
spf_record_dns_callback, (void *)cb, DNS_REQUEST_A, elt_data->content.mx.name)) { | |||
task->dns_requests ++; | |||
cb->rec->requests_inflight ++; | |||
} | |||
} | |||
else if (elt_data->type == DNS_REQUEST_A) { | |||
if (!cb->addr->data.normal.parsed) { | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
} | |||
else if (reply->type == DNS_REQUEST_A) { | |||
if (!cb->addr->data.normal.parsed) { | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
else { | |||
/* Insert one more address */ | |||
tmp = spf_addr_find (cb->rec->addrs, cb->addr); | |||
if (tmp) { | |||
new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); | |||
memcpy (new_addr, cb->addr, sizeof (struct spf_addr)); | |||
new_addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr; | |||
new_addr->data.normal.parsed = TRUE; | |||
cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr); | |||
} | |||
else { | |||
/* Insert one more address */ | |||
tmp = spf_addr_find (cb->rec->addrs, cb->addr); | |||
if (tmp) { | |||
new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); | |||
memcpy (new_addr, cb->addr, sizeof (struct spf_addr)); | |||
new_addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr; | |||
new_addr->data.normal.parsed = TRUE; | |||
cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr); | |||
} | |||
else { | |||
msg_info ("<%s>: spf error for domain %s: addresses mismatch", | |||
task->message_id, cb->rec->sender_domain); | |||
} | |||
msg_info ("<%s>: spf error for domain %s: addresses mismatch", | |||
task->message_id, cb->rec->sender_domain); | |||
} | |||
} | |||
} | |||
#ifdef HAVE_INET_PTON | |||
else if (reply->type == DNS_REQUEST_AAA) { | |||
if (!cb->addr->data.normal.parsed) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
else if (elt_data->type == DNS_REQUEST_AAA) { | |||
if (!cb->addr->data.normal.parsed) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
} | |||
else { | |||
/* Insert one more address */ | |||
tmp = spf_addr_find (cb->rec->addrs, cb->addr); | |||
if (tmp) { | |||
new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); | |||
memcpy (new_addr, cb->addr, sizeof (struct spf_addr)); | |||
memcpy (&new_addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr)); | |||
new_addr->data.normal.parsed = TRUE; | |||
new_addr->data.normal.ipv6 = TRUE; | |||
cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr); | |||
} | |||
else { | |||
/* Insert one more address */ | |||
tmp = spf_addr_find (cb->rec->addrs, cb->addr); | |||
if (tmp) { | |||
new_addr = memory_pool_alloc (task->task_pool, sizeof (struct spf_addr)); | |||
memcpy (new_addr, cb->addr, sizeof (struct spf_addr)); | |||
memcpy (&new_addr->data.normal.d.in6, &elt_data->aaa.addr, sizeof (struct in6_addr)); | |||
new_addr->data.normal.parsed = TRUE; | |||
new_addr->data.normal.ipv6 = TRUE; | |||
cb->rec->addrs = g_list_insert_before (cb->rec->addrs, tmp, new_addr); | |||
} | |||
else { | |||
msg_info ("<%s>: spf error for domain %s: addresses mismatch", | |||
task->message_id, cb->rec->sender_domain); | |||
} | |||
msg_info ("<%s>: spf error for domain %s: addresses mismatch", | |||
task->message_id, cb->rec->sender_domain); | |||
} | |||
} | |||
} | |||
#endif | |||
break; | |||
case SPF_RESOLVE_A: | |||
if (reply->type == DNS_REQUEST_A) { | |||
/* XXX: process only one record */ | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
} | |||
break; | |||
case SPF_RESOLVE_A: | |||
if (elt_data->type == DNS_REQUEST_A) { | |||
/* XXX: process only one record */ | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
} | |||
#ifdef HAVE_INET_PTON | |||
else if (reply->type == DNS_REQUEST_AAA) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
} | |||
else if (elt_data->type == DNS_REQUEST_AAA) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
} | |||
#endif | |||
break; | |||
break; | |||
#ifdef HAVE_INET_PTON | |||
case SPF_RESOLVE_AAA: | |||
if (reply->type == DNS_REQUEST_A) { | |||
/* XXX: process only one record */ | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->a.addr[0].s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
} | |||
else if (reply->type == DNS_REQUEST_AAA) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
} | |||
case SPF_RESOLVE_AAA: | |||
if (elt_data->type == DNS_REQUEST_A) { | |||
/* XXX: process only one record */ | |||
cb->addr->data.normal.d.in4.s_addr = elt_data->content.a.addr.s_addr; | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
} | |||
else if (elt_data->type == DNS_REQUEST_AAA) { | |||
memcpy (&cb->addr->data.normal.d.in6, &elt_data->content.aaa.addr, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
cb->addr->data.normal.parsed = TRUE; | |||
cb->addr->data.normal.ipv6 = TRUE; | |||
} | |||
#endif | |||
break; | |||
case SPF_RESOLVE_PTR: | |||
break; | |||
case SPF_RESOLVE_REDIRECT: | |||
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); | |||
break; | |||
case SPF_RESOLVE_PTR: | |||
break; | |||
case SPF_RESOLVE_REDIRECT: | |||
if (elt_data->type == DNS_REQUEST_TXT) { | |||
begin = elt_data->content.txt.data; | |||
if (!cb->in_include && cb->rec->addrs) { | |||
g_list_free (cb->rec->addrs); | |||
cb->rec->addrs = NULL; | |||
} | |||
break; | |||
case SPF_RESOLVE_INCLUDE: | |||
if (reply->type == DNS_REQUEST_TXT) { | |||
begin = elt_data->txt.data; | |||
start_spf_parse (cb->rec, begin); | |||
} | |||
break; | |||
case SPF_RESOLVE_INCLUDE: | |||
if (elt_data->type == DNS_REQUEST_TXT) { | |||
begin = elt_data->content.txt.data; | |||
#ifdef SPF_DEBUG | |||
msg_info ("before include"); | |||
dump_spf_record (cb->rec->addrs); | |||
msg_info ("before include"); | |||
dump_spf_record (cb->rec->addrs); | |||
#endif | |||
tmp = cb->rec->addrs; | |||
cb->rec->addrs = NULL; | |||
cb->rec->in_include = TRUE; | |||
start_spf_parse (cb->rec, begin); | |||
cb->rec->in_include = FALSE; | |||
tmp = cb->rec->addrs; | |||
cb->rec->addrs = NULL; | |||
cb->rec->in_include = TRUE; | |||
start_spf_parse (cb->rec, begin); | |||
cb->rec->in_include = FALSE; | |||
#ifdef SPF_DEBUG | |||
msg_info ("after include"); | |||
dump_spf_record (cb->rec->addrs); | |||
msg_info ("after include"); | |||
dump_spf_record (cb->rec->addrs); | |||
#endif | |||
/* Insert new list */ | |||
cb->addr->is_list = TRUE; | |||
cb->addr->data.list = cb->rec->addrs; | |||
cb->rec->addrs = tmp; | |||
} | |||
break; | |||
case SPF_RESOLVE_EXP: | |||
break; | |||
case SPF_RESOLVE_EXISTS: | |||
if (reply->type == DNS_REQUEST_A) { | |||
/* If specified address resolves, we can accept connection from every IP */ | |||
cb->addr->data.normal.d.in4.s_addr = INADDR_NONE; | |||
cb->addr->data.normal.mask = 0; | |||
} | |||
break; | |||
/* Insert new list */ | |||
cb->addr->is_list = TRUE; | |||
cb->addr->data.list = cb->rec->addrs; | |||
cb->rec->addrs = tmp; | |||
} | |||
break; | |||
case SPF_RESOLVE_EXP: | |||
break; | |||
case SPF_RESOLVE_EXISTS: | |||
if (elt_data->type == DNS_REQUEST_A) { | |||
/* If specified address resolves, we can accept connection from every IP */ | |||
cb->addr->data.normal.d.in4.s_addr = INADDR_NONE; | |||
cb->addr->data.normal.mask = 0; | |||
} | |||
elt = g_list_next (elt); | |||
break; | |||
} | |||
} | |||
} | |||
else if (reply->code == DNS_RC_NXDOMAIN) { | |||
switch (cb->cur_action) { | |||
case SPF_RESOLVE_MX: | |||
if (reply->type == DNS_REQUEST_MX) { | |||
if (reply->request->type == DNS_REQUEST_MX) { | |||
msg_info ("<%s>: spf error for domain %s: cannot find MX record for %s", | |||
task->message_id, cb->rec->sender_domain, cb->rec->cur_domain); | |||
cb->addr->data.normal.d.in4.s_addr = INADDR_NONE; | |||
cb->addr->data.normal.mask = 32; | |||
} | |||
else if (reply->type != DNS_REQUEST_MX) { | |||
else if (reply->request->type != DNS_REQUEST_MX) { | |||
msg_info ("<%s>: spf error for domain %s: cannot resolve MX record for %s", | |||
task->message_id, cb->rec->sender_domain, cb->rec->cur_domain); | |||
cb->addr->data.normal.d.in4.s_addr = INADDR_NONE; | |||
@@ -567,7 +562,7 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
} | |||
break; | |||
case SPF_RESOLVE_A: | |||
if (reply->type == DNS_REQUEST_A) { | |||
if (reply->request->type == DNS_REQUEST_A) { | |||
/* XXX: process only one record */ | |||
cb->addr->data.normal.d.in4.s_addr = INADDR_NONE; | |||
cb->addr->data.normal.mask = 32; | |||
@@ -575,7 +570,7 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
break; | |||
#ifdef HAVE_INET_PTON | |||
case SPF_RESOLVE_AAA: | |||
if (reply->type == DNS_REQUEST_AAA) { | |||
if (reply->request->type == DNS_REQUEST_AAA) { | |||
/* XXX: process only one record */ | |||
memset (&cb->addr->data.normal.d.in6, 0xff, sizeof (struct in6_addr)); | |||
cb->addr->data.normal.mask = 32; | |||
@@ -1345,16 +1340,12 @@ static void | |||
spf_dns_callback (struct rspamd_dns_reply *reply, gpointer arg) | |||
{ | |||
struct spf_record *rec = arg; | |||
union rspamd_reply_element *elt; | |||
GList *cur; | |||
struct rspamd_reply_entry *elt; | |||
rec->requests_inflight --; | |||
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); | |||
LL_FOREACH (reply->entries, elt) { | |||
start_spf_parse (rec, elt->content.txt.data); | |||
} | |||
} | |||