Browse Source

Rework resolver library.

tags/0.7.0
Vsevolod Stakhov 10 years ago
parent
commit
9bb4dccead
11 changed files with 516 additions and 579 deletions
  1. 1
    2
      CMakeLists.txt
  2. 7
    9
      src/dkim.c
  3. 97
    209
      src/dns.c
  4. 12
    145
      src/dns.h
  5. 222
    0
      src/dns_private.h
  6. 32
    60
      src/lua/lua_dns.c
  7. 3
    3
      src/lua/lua_http.c
  8. 3
    3
      src/lua/lua_redis.c
  9. 6
    4
      src/plugins/surbl.c
  10. 6
    8
      src/smtp_proxy.c
  11. 127
    136
      src/spf.c

+ 1
- 2
CMakeLists.txt View File

@@ -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)


+ 7
- 9
src/dkim.c View File

@@ -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 */

+ 97
- 209
src/dns.c View File

@@ -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)
{

+ 12
- 145
src/dns.h View File

@@ -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 */


+ 222
- 0
src/dns_private.h View File

@@ -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_ */

+ 32
- 60
src/lua/lua_dns.c View File

@@ -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);

+ 3
- 3
src/lua/lua_http.c View File

@@ -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);


+ 3
- 3
src/lua/lua_redis.c View File

@@ -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);
}

+ 6
- 4
src/plugins/surbl.c View File

@@ -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);

+ 6
- 8
src/smtp_proxy.c View File

@@ -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;

+ 127
- 136
src/spf.c View File

@@ -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);
}
}


Loading…
Cancel
Save