From 1d3d68ae64048d4049f8f5cbe4aaea0ca8b134d8 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 27 Jan 2014 16:12:27 +0000 Subject: [PATCH] Rework resolver library. Conflicts: src/dns.c --- CMakeLists.txt | 3 +- src/dkim.c | 16 +-- src/dns.c | 306 ++++++++++++++------------------------------ src/dns.h | 157 ++--------------------- src/dns_private.h | 222 ++++++++++++++++++++++++++++++++ src/lua/lua_dns.c | 92 +++++-------- src/lua/lua_http.c | 6 +- src/lua/lua_redis.c | 6 +- src/plugins/surbl.c | 10 +- src/smtp_proxy.c | 14 +- src/spf.c | 263 ++++++++++++++++++------------------- 11 files changed, 516 insertions(+), 579 deletions(-) create mode 100644 src/dns_private.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d962997ba..e85e1febb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/dkim.c b/src/dkim.c index bd57cd232..72a14c179 100644 --- a/src/dkim.c +++ b/src/dkim.c @@ -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 */ diff --git a/src/dns.c b/src/dns.c index 5ec372f17..e5e69b71b 100644 --- a/src/dns.c +++ b/src/dns.c @@ -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 #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; @@ -1514,7 +1428,7 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) serv = &new->servers[new->servers_num]; if (inet_pton (AF_INET6, begin, addr_holder) == 1 || inet_pton (AF_INET, begin, addr_holder) == 1) { - serv->name = memory_pool_strdup (new->static_pool, begin); + serv->name = strdup (begin); serv->up.priority = priority; serv->up.weight = priority; new->servers_num ++; @@ -1540,15 +1454,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); @@ -1564,20 +1476,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) { @@ -1591,16 +1489,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) { diff --git a/src/dns.h b/src/dns.h index 1c88e5a18..ee52ba13c 100644 --- a/src/dns.h +++ b/src/dns.h @@ -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 */ diff --git a/src/dns_private.h b/src/dns_private.h new file mode 100644 index 000000000..46483918e --- /dev/null +++ b/src/dns_private.h @@ -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_ */ diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c index 540fc7713..2bfbe582f 100644 --- a/src/lua/lua_dns.c +++ b/src/lua/lua_dns.c @@ -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); diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c index 26f699b78..324807005 100644 --- a/src/lua/lua_http.c +++ b/src/lua/lua_http.c @@ -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); diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c index a9006b773..c0b5c7d52 100644 --- a/src/lua/lua_redis.c +++ b/src/lua/lua_redis.c @@ -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); } diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c index 397a26ba4..f42d0259d 100644 --- a/src/plugins/surbl.c +++ b/src/plugins/surbl.c @@ -679,14 +679,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); diff --git a/src/smtp_proxy.c b/src/smtp_proxy.c index e468086b4..423a9b0bd 100644 --- a/src/smtp_proxy.c +++ b/src/smtp_proxy.c @@ -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; diff --git a/src/spf.c b/src/spf.c index e394005b8..f04395da5 100644 --- a/src/spf.c +++ b/src/spf.c @@ -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); } } -- 2.39.5