src/lua_worker.c
src/main.c
src/map.c
- src/smtp.c
src/smtp_proxy.c
src/webui.c
src/worker.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)
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) {
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 */
#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
}
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;
}
/* 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;
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;
}
{
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;
*pos = '\0';
req->pos += pos - (req->packet + req->pos) + 1;
if (table != NULL) {
- g_list_free (table);
+ HASH_CLEAR (hh, table);
}
}
#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 */
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 */
*pos = p;
if (parsed) {
+ elt->ttl = ttl;
return 1;
}
return 0;
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;
*/
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;
return TRUE;
}
-#define RESOLV_CONF "/etc/resolv.conf"
-
static gboolean
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 {
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;
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 ++;
}
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);
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)
{
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)
{
#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,
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
struct {
gchar *data;
} txt;
- struct {
- gchar *data;
- } spf;
struct {
guint16 priority;
guint16 weight;
} 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,
};
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 */
--- /dev/null
+/* 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_ */
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));
*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);
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;
}
/* 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);
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) {
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);
}
{
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);
{
struct smtp_proxy_session *session = arg;
gint res = 0;
- union rspamd_reply_element *elt;
+ struct rspamd_reply_entry *elt;
GList *cur;
switch (session->state)
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);
}
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;
{
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;
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;
}
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;
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;
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);
}
}