]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
Integrate rspamd with librdns.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 19 Feb 2014 17:29:23 +0000 (17:29 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 19 Feb 2014 17:29:23 +0000 (17:29 +0000)
14 files changed:
CMakeLists.txt
src/CMakeLists.txt
src/cfg_file.h
src/cfg_rcl.c
src/dkim.c
src/dns.c
src/dns.h
src/lua/lua_dns.c
src/lua/lua_http.c
src/lua/lua_redis.c
src/plugins/surbl.c
src/rdns
src/smtp_proxy.c
src/spf.c

index 30583c86f6b6144ebbfb08b4955e900822009afe..14e2a0b58efd4a258092d5000b876758621bb609 100644 (file)
@@ -852,7 +852,8 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src"
                                        "${CMAKE_SOURCE_DIR}/contrib/uthash"
                                        "${CMAKE_SOURCE_DIR}/contrib/http-parser"
                                        "${CMAKE_SOURCE_DIR}/contrib/libottery"
-                                       "${CMAKE_SOURCE_DIR}/contrib/xxhash")
+                                       "${CMAKE_SOURCE_DIR}/contrib/xxhash"
+                                       "${CMAKE_SOURCE_DIR}/src/rdns/include")
 
 SET(RSPAMDSRC  src/modules.c
                                src/controller.c
index 84f9806558f9aeb28f6a44c712cddf20d36bebef..b6a0731dd2e5223968bbe0e187ced7a62930f132 100644 (file)
@@ -104,10 +104,8 @@ SET_TARGET_PROPERTIES(rspamd-server PROPERTIES LINKER_LANGUAGE C COMPILE_FLAGS "
 TARGET_LINK_LIBRARIES(rspamd-server rspamd-lua)
 TARGET_LINK_LIBRARIES(rspamd-server rspamd-json)
 TARGET_LINK_LIBRARIES(rspamd-server rspamd-cdb)
-TARGET_LINK_LIBRARIES(rspamd-server rspamd-util)   
-IF(LIBJUDY_LIBRARY)
-       TARGET_LINK_LIBRARIES(rspamd-server Judy)
-ENDIF(LIBJUDY_LIBRARY)   
+TARGET_LINK_LIBRARIES(rspamd-server rspamd-util)
+TARGET_LINK_LIBRARIES(rspamd-server rdns)   
 IF(CMAKE_COMPILER_IS_GNUCC)
 SET_TARGET_PROPERTIES(rspamd-server PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB -fno-strict-aliasing")
 ENDIF(CMAKE_COMPILER_IS_GNUCC)
index 6f3489455c004070d673f80a8b1acf14f9617dca..13acb158fba5773c97cf17688e2f701a8e14ed4a 100644 (file)
@@ -363,7 +363,7 @@ struct config_file {
 
        gchar* history_file;                                                    /**< file to save rolling history                                               */
 
-       guint32 dns_timeout;                                                    /**< timeout in milliseconds for waiting for dns reply  */
+       gdouble dns_timeout;                                                    /**< timeout in milliseconds for waiting for dns reply  */
        guint32 dns_retransmits;                                                /**< maximum retransmits count                                                  */
        guint32 dns_throttling_errors;                                  /**< maximum errors for starting resolver throttling    */
        guint32 dns_throttling_time;                                    /**< time in seconds for DNS throttling                                 */
index 5793b5010fc8d5ab032c2f53e89be9d0c8a589f9..2d0f9b186c51bf1076615a8c56d358df04134409 100644 (file)
@@ -1065,7 +1065,7 @@ rspamd_rcl_config_init (void)
        rspamd_rcl_add_default_handler (sub, "dns_nameserver", rspamd_rcl_parse_struct_string_list,
                        G_STRUCT_OFFSET (struct config_file, nameservers), 0);
        rspamd_rcl_add_default_handler (sub, "dns_timeout", rspamd_rcl_parse_struct_time,
-                       G_STRUCT_OFFSET (struct config_file, dns_timeout), RSPAMD_CL_FLAG_TIME_INTEGER);
+                       G_STRUCT_OFFSET (struct config_file, dns_timeout), RSPAMD_CL_FLAG_TIME_FLOAT);
        rspamd_rcl_add_default_handler (sub, "dns_retransmits", rspamd_rcl_parse_struct_integer,
                        G_STRUCT_OFFSET (struct config_file, dns_retransmits), RSPAMD_CL_FLAG_INT_32);
        rspamd_rcl_add_default_handler (sub, "dns_sockets", rspamd_rcl_parse_struct_integer,
index fe48668aadb186e01119144a74f9300322a516b4..2b74d53ce5964456452646b8b50b88d6b86c8647 100644 (file)
@@ -749,17 +749,17 @@ rspamd_dkim_parse_key (const gchar *txt, gsize *keylen, GError **err)
 
 /* Get TXT request data and parse it */
 static void
-rspamd_dkim_dns_cb (struct rspamd_dns_reply *reply, gpointer arg)
+rspamd_dkim_dns_cb (struct rdns_reply *reply, gpointer arg)
 {
        struct rspamd_dkim_key_cbdata                           *cbdata = arg;
        rspamd_dkim_key_t                                                       *key = NULL;
        GError                                                                          *err = NULL;
-       struct rspamd_reply_entry                                       *elt;
+       struct rdns_reply_entry                                 *elt;
        gsize                                                                            keylen = 0;
 
        if (reply->code != DNS_RC_NOERROR) {
                g_set_error (&err, DKIM_ERROR, DKIM_SIGERROR_NOKEY, "dns request to %s failed: %s", cbdata->ctx->dns_key,
-                               dns_strerror (reply->code));
+                               rdns_strerror (reply->code));
                cbdata->handler (NULL, 0, cbdata->ctx, cbdata->ud, err);
        }
        else {
index a74e5b692f57ee44f19b1c59d5cd22e9d9eb7cf9..5b2f928b2a4bd612dc4ba8d71089169f7d5219b5 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
 
 #include "config.h"
 #include "dns.h"
-#include "dns_private.h"
 #include "main.h"
 #include "utlist.h"
 #include "uthash.h"
-#include "ottery.h"
+#include "rdns_event.h"
 
-#ifdef HAVE_OPENSSL
-#include <openssl/rand.h>
-#endif
-
-static void dns_retransmit_handler (gint fd, short what, void *arg);
-
-static guint16
-dns_permutor_generate_id (void)
-{
-       guint16 id;
-
-       id = ottery_rand_unsigned ();
-
-       return id;
-}
-
-/* Punycode utility */
-static guint
-digit (unsigned n)
-{
-       return "abcdefghijklmnopqrstuvwxyz0123456789"[n];
-}
-
-static guint
-adapt (guint delta, guint numpoints, gint first)
-{
-       guint k;
-
-       if (first) {
-               delta = delta / damp;
-       }
-       else {
-               delta /= 2;
-       }
-       delta += delta / numpoints;
-       k = 0;
-       while (delta > ((base - t_min) * t_max) / 2) {
-               delta /= base - t_min;
-               k += base;
-       }
-       return k + (((base - t_min + 1) * delta) / (delta + skew));
-}
-
-/**
- * Convert an UCS4 string to a puny-coded DNS label string suitable
- * when combined with delimiters and other labels for DNS lookup.
- *
- * @param in an UCS4 string to convert
- * @param in_len the length of in.
- * @param out the resulting puny-coded string. The string is not NUL
- * terminatied.
- * @param out_len before processing out_len should be the length of
- * the out variable, after processing it will be the length of the out
- * string.
- *
- * @return returns 0 on success, an wind error code otherwise
- * @ingroup wind
- */
-
-gboolean
-punycode_label_toascii(const gunichar *in, gsize in_len, gchar *out,
-               gsize *out_len)
-{
-       guint n = initial_n;
-       guint delta = 0;
-       guint bias = initial_bias;
-       guint h = 0;
-       guint b;
-       guint i;
-       guint o = 0;
-       guint m;
-
-       for (i = 0; i < in_len; ++i) {
-               if (in[i] < 0x80) {
-                       ++h;
-                       if (o >= *out_len) {
-                               return FALSE;
-                       }
-                       out[o++] = in[i];
-               }
-       }
-       b = h;
-       if (b > 0) {
-               if (o >= *out_len) {
-                       return FALSE;
-               }
-               out[o++] = 0x2D;
-       }
-       /* is this string punycoded */
-       if (h < in_len) {
-               if (o + 4 >= *out_len) {
-                       return FALSE;
-               }
-               memmove (out + 4, out, o);
-               memcpy (out, "xn--", 4);
-               o += 4;
-       }
-
-       while (h < in_len) {
-               m = (guint) -1;
-               for (i = 0; i < in_len; ++i) {
-
-                       if (in[i] < m && in[i] >= n) {
-                               m = in[i];
-                       }
-               }
-               delta += (m - n) * (h + 1);
-               n = m;
-               for (i = 0; i < in_len; ++i) {
-                       if (in[i] < n) {
-                               ++delta;
-                       }
-                       else if (in[i] == n) {
-                               guint q = delta;
-                               guint k;
-                               for (k = base;; k += base) {
-                                       guint t;
-                                       if (k <= bias) {
-                                               t = t_min;
-                                       }
-                                       else if (k >= bias + t_max) {
-                                               t = t_max;
-                                       }
-                                       else {
-                                               t = k - bias;
-                                       }
-                                       if (q < t) {
-                                               break;
-                                       }
-                                       if (o >= *out_len) {
-                                               return -1;
-                                       }
-                                       out[o++] = digit (t + ((q - t) % (base - t)));
-                                       q = (q - t) / (base - t);
-                               }
-                               if (o >= *out_len) {
-                                       return -1;
-                               }
-                               out[o++] = digit (q);
-                               /* output */
-                               bias = adapt (delta, h + 1, h == b);
-                               delta = 0;
-                               ++h;
-                       }
-               }
-               ++delta;
-               ++n;
-       }
-
-       *out_len = o;
-       return TRUE;
-}
-
-struct dns_request_key {
-       guint16 id;
-       guint16 port;
+struct rspamd_dns_resolver {
+       struct rdns_resolver *r;
+       struct event_base *ev_base;
+       gdouble request_timeout;
+       guint max_retransmits;
 };
 
-/** Message compression */
-struct dns_name_table {
-       guint8 off;
-       guint8 *label;
-       guint8 len;
-       UT_hash_handle hh;
+struct rspamd_dns_request_ud {
+       struct rspamd_async_session *session;
+       dns_callback_type cb;
+       gpointer ud;
+       struct rdns_request *req;
 };
 
-static gboolean
-try_compress_label (memory_pool_t *pool, guint8 *target, guint8 *start, guint8 len,
-               guint8 *label, struct dns_name_table **table)
-{
-       struct dns_name_table *found = NULL;
-       guint16 pointer;
-
-       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);
-       }
-
-       return FALSE;
-}
-
-/** Packet creating functions */
-static void
-allocate_packet (struct rspamd_dns_request *req, guint namelen)
-{
-       namelen += 96 /* header */
-               + 2 /* Trailing label */
-               + 4 /* Resource type */
-               + 11; /* EDNS0 RR */
-       req->packet = memory_pool_alloc (req->pool, namelen);
-       req->pos = 0;
-       req->packet_len = namelen;
-}
-
 static void
-make_dns_header (struct rspamd_dns_request *req)
+rspamd_dns_fin_cb (gpointer arg)
 {
-       struct dns_header *header;
+       struct rdns_request *req = arg;
        
-       /* Set DNS header values */
-       header = (struct dns_header *)req->packet;
-       memset (header, 0 , sizeof (struct dns_header));
-       header->qid = dns_permutor_generate_id ();
-       header->rd = 1;
-       header->qdcount = htons (1);
-       header->arcount = htons (1);
-       req->pos += sizeof (struct dns_header);
-       req->id = header->qid;
-}
-
-static gboolean
-maybe_punycode_label (guint8 *begin, guint8 **res, guint8 **dot, guint *label_len)
-{
-       gboolean ret = FALSE;
-       guint8 *p = begin;
-
-       *dot = NULL;
-
-       while (*p) {
-               if (*p == '.') {
-                       *dot = p;
-                       break;
-               }
-               else if ((*p) & 0x80) {
-                       ret = TRUE;
-               }
-               p ++;
-       }
-
-       if (*p) {
-               *res = p - 1;
-               *label_len = p - begin;
-       }
-       else {
-               *res = p;
-               *label_len = p - begin;
-       }
-
-       return ret;
+       rdns_request_release (req);
 }
 
 static void
-format_dns_name (struct rspamd_dns_request *req, const gchar *name, guint namelen)
+rspamd_dns_callback (struct rdns_reply *reply, gpointer ud)
 {
-       guint8 *pos = req->packet + req->pos, *end, *dot, *name_pos, *begin;
-       guint remain = req->packet_len - req->pos - 5, label_len;
-       struct dns_name_table *table = NULL;
-       gunichar *uclabel;
-       glong uclabel_len;
-       gsize punylabel_len;
-       guint8 tmp_label[DNS_D_MAXLABEL];
+       struct rspamd_dns_request_ud *reqdata = ud;
 
-       if (namelen == 0) {
-               namelen = strlen (name);
-       }
-       
-       begin = (guint8 *)name;
-       end = (guint8 *)name + namelen;
-       for (;;) {
-               /* Check label for unicode characters */
-               if (maybe_punycode_label (begin, &name_pos, &dot, &label_len)) {
-                       /* Convert to ucs4 */
-                       uclabel = g_utf8_to_ucs4_fast ((gchar *)begin, label_len, &uclabel_len);
-                       memory_pool_add_destructor (req->pool, g_free, uclabel);
-                       punylabel_len = DNS_D_MAXLABEL;
+       reqdata->cb (reply, reqdata->ud);
 
-                       punycode_label_toascii (uclabel, uclabel_len, (gchar *)tmp_label, &punylabel_len);
-                       /* Try to compress name */
-                       if (! try_compress_label (req->pool, pos, req->packet, punylabel_len, tmp_label, &table)) {
-                               /* Copy punylabel */
-                               *pos++ = (guint8)punylabel_len;
-                               memcpy (pos, tmp_label, punylabel_len);
-                               pos += punylabel_len;
-                       }
-                       else {
-                               pos += 2;
-                       }
-                       if (dot) {
-                               remain -= label_len + 1;
-                               begin = dot + 1;
-                       }
-                       else {
-                               break;
-                       }
-               }
-               else {
-                       if (dot) {
-                               if (label_len > DNS_D_MAXLABEL) {
-                                       msg_err ("dns name component is longer than 63 bytes, should be stripped");
-                                       label_len = DNS_D_MAXLABEL;
-                               }
-                               if (remain < label_len + 1) {
-                                       label_len = remain - 1;
-                                       msg_err ("no buffer remain for constructing query, strip to %ud", label_len);
-                               }
-                               if (label_len == 0) {
-                                       /* Two dots in order, skip this */
-                                       msg_info ("name contains two or more dots in a row, replace it with one dot");
-                                       begin = dot + 1;
-                                       continue;
-                               }
-                               /* First try to compress name */
-                               if (! try_compress_label (req->pool, pos, req->packet, end - begin, begin, &table)) {
-                                       *pos++ = (guint8)label_len;
-                                       memcpy (pos, begin, label_len);
-                                       pos += label_len;
-                               }
-                               else {
-                                       pos += 2;
-                               }
-                               remain -= label_len + 1;
-                               begin = dot + 1;
-                       }
-                       else {
-                               if (label_len == 0) {
-                                       /* If name is ended with dot */
-                                       break;
-                               }
-                               if (label_len > DNS_D_MAXLABEL) {
-                                       msg_err ("dns name component is longer than 63 bytes, should be stripped");
-                                       label_len = DNS_D_MAXLABEL;
-                               }
-                               if (remain < label_len + 1) {
-                                       label_len = remain - 1;
-                                       msg_err ("no buffer remain for constructing query, strip to %ud", label_len);
-                               }
-                               *pos++ = (guint8)label_len;
-                               memcpy (pos, begin, label_len);
-                               pos += label_len;
-                               break;
-                       }
-               }
-               if (remain == 0) {
-                       msg_err ("no buffer space available, aborting");
-                       break;
-               }
-       }
-       /* Termination label */
-       *pos = '\0';
-       req->pos += pos - (req->packet + req->pos) + 1;
-       if (table != NULL) {
-               HASH_CLEAR (hh, table);
-       }
-}
-
-static void
-make_ptr_req (struct rspamd_dns_request *req, struct in_addr *addr)
-{
-       gchar                           ipbuf[sizeof("255.255.255.255.in-addr.arpa")];
-       guint32                         r;
-       guint16                        *p;
-       guint8                         *addr_p = (guint8 *)&addr->s_addr;
-
-       r = rspamd_snprintf (ipbuf, sizeof(ipbuf), "%d.%d.%d.%d.in-addr.arpa",
-                       addr_p[3], addr_p[2], addr_p[1], addr_p[0]);
-       allocate_packet (req, r);
-       make_dns_header (req);
-       format_dns_name (req, ipbuf, r);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_PTR);
-       *p = htons (DNS_C_IN);
-       req->requested_name = memory_pool_strdup (req->pool, ipbuf);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_PTR;
-}
-
-static void
-make_a_req (struct rspamd_dns_request *req, const gchar *name)
-{
-       guint16 *p;
-
-       allocate_packet (req, strlen (name));
-       make_dns_header (req);
-       format_dns_name (req, name, 0);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_A);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_A;
-       req->requested_name = name;
-}
-
-#ifdef HAVE_INET_PTON
-static void
-make_aaa_req (struct rspamd_dns_request *req, const gchar *name)
-{
-       guint16 *p;
-
-       allocate_packet (req, strlen (name));
-       make_dns_header (req);
-       format_dns_name (req, name, 0);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_AAAA);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_AAA;
-       req->requested_name = name;
-}
-#endif
-
-static void
-make_txt_req (struct rspamd_dns_request *req, const gchar *name)
-{
-       guint16 *p;
-
-       allocate_packet (req, strlen (name));
-       make_dns_header (req);
-       format_dns_name (req, name, 0);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_TXT);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_TXT;
-       req->requested_name = name;
-}
-
-static void
-make_mx_req (struct rspamd_dns_request *req, const gchar *name)
-{
-       guint16 *p;
-
-       allocate_packet (req, strlen (name));
-       make_dns_header (req);
-       format_dns_name (req, name, 0);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_MX);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_MX;
-       req->requested_name = name;
-}
-
-static void
-make_srv_req (struct rspamd_dns_request *req, const gchar *service, const gchar *proto, const gchar *name)
-{
-       guint16 *p;
-       guint len;
-       gchar *target;
-
-       len = strlen (service) + strlen (proto) + strlen (name) + 5;
-
-       allocate_packet (req, len);
-       make_dns_header (req);
-       target = memory_pool_alloc (req->pool, len);
-       len = rspamd_snprintf (target, len, "_%s._%s.%s", service, proto, name);
-       format_dns_name (req, target, len);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_SRV);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_SRV;
-       req->requested_name = name;
-}
-
-static void
-make_spf_req (struct rspamd_dns_request *req, const gchar *name)
-{
-       guint16 *p;
-
-       allocate_packet (req, strlen (name));
-       make_dns_header (req);
-       format_dns_name (req, name, 0);
-       p = (guint16 *)(req->packet + req->pos);
-       *p++ = htons (DNS_T_SPF);
-       *p = htons (DNS_C_IN);
-       req->pos += sizeof (guint16) * 2;
-       req->type = DNS_REQUEST_SPF;
-       req->requested_name = name;
-}
-
-static void
-rspamd_dns_add_edns0 (struct rspamd_dns_request *req)
-{
-       guint8 *p8;
-       guint16 *p16;
-
-       p8 = (guint8 *)(req->packet + req->pos);
-       *p8 = '\0'; /* Name is root */
-       p16 = (guint16 *)(req->packet + req->pos + 1);
-       *p16++ = htons (DNS_T_OPT);
-       /* UDP packet length */
-       *p16++ = htons (UDP_PACKET_SIZE);
-       /* Extended rcode 00 00 */
-       *p16++ = 0;
-       /* Z 10000000 00000000 to allow dnssec */
-       p8 = (guint8 *)p16++;
-       /* Not a good time for DNSSEC */
-       *p8 = 0x00;
-       /* Length */
-       *p16 = 0;
-       req->pos += sizeof (guint8) + sizeof (guint16) * 5;
-}
-
-static gint
-send_dns_request (struct rspamd_dns_request *req)
-{
-       gint r;
-       struct rspamd_dns_server *serv = req->io->srv;
-
-       r = send (req->sock, req->packet, req->pos, 0);
-       if (r == -1) {
-               if (errno == EAGAIN) {
-                       event_set (&req->io_event, req->sock, EV_WRITE, dns_retransmit_handler, req);
-                       event_base_set (req->resolver->ev_base, &req->io_event);
-                       event_add (&req->io_event, &req->tv);
-                       register_async_event (req->session, (event_finalizer_t)event_del, &req->io_event,
-                                       g_quark_from_static_string ("dns resolver"));
-                       return 0;
-               } 
-               else {
-                       msg_err ("send failed: %s for server %s", strerror (errno), serv->name);
-                       upstream_fail (&serv->up, req->time);
-                       return -1;
-               }
-       }
-       else if (r < req->pos) {
-               msg_err ("incomplete send over UDP socket, seems to be internal bug");
-               event_set (&req->io_event, req->sock, EV_WRITE, dns_retransmit_handler, req);
-               event_base_set (req->resolver->ev_base, &req->io_event);
-               event_add (&req->io_event, &req->tv);
-               register_async_event (req->session, (event_finalizer_t)event_del, &req->io_event,
-                               g_quark_from_static_string ("dns resolver"));
-               return 0;
-       }
-       
-       return 1;
-}
-
-static void
-dns_fin_cb (gpointer arg)
-{
-       struct rspamd_dns_request *req = arg;
-       
-       event_del (&req->timer_event);
-       g_hash_table_remove (req->io->requests, &req->id);
-}
-
-static guint8 *
-decompress_label (guint8 *begin, guint16 *len, guint16 max)
-{
-       guint16 offset = (*len);
-
-       if (offset > max) {
-               msg_info ("invalid DNS compression pointer: %d max is %d", (gint)offset, (gint)max);
-               return NULL;
-       }
-       *len = *(begin + offset);
-       return begin + offset;
-}
-
-#define UNCOMPRESS_DNS_OFFSET(p) (((*(p)) ^ DNS_COMPRESSION_BITS) << 8) + *((p) + 1)
-
-static guint8 *
-dns_request_reply_cmp (struct rspamd_dns_request *req, guint8 *in, gint len)
-{
-       guint8 *p, *c, *l1, *l2;
-       guint16 len1, len2;
-       gint decompressed = 0;
-
-       /* QR format:
-        * labels - len:octets
-        * null label - 0
-        * class - 2 octets
-        * type - 2 octets
-        */
-       
-       /* In p we would store current position in reply and in c - position in request */
-       p = in;
-       c = req->packet + sizeof (struct dns_header);
-
-       for (;;) {
-               /* Get current label */
-               len1 = *p;
-               len2 = *c;
-               if (p - in > len) {
-                       msg_info ("invalid dns reply");
-                       return NULL;
-               }
-               /* This may be compressed, so we need to decompress it */
-               if (len1 & DNS_COMPRESSION_BITS) {
-                       len1 = UNCOMPRESS_DNS_OFFSET(p);
-                       l1 = decompress_label (in, &len1, len);
-                       if (l1 == NULL) {
-                               return NULL;
-                       }
-                       decompressed ++;
-                       l1 ++;
-                       p += 2;
-               }
-               else {
-                       l1 = ++p;
-                       p += len1;
-               }
-               if (len2 & DNS_COMPRESSION_BITS) {
-                       len2 = UNCOMPRESS_DNS_OFFSET(p);
-                       l2 = decompress_label (req->packet, &len2, len);
-                       if (l2 == NULL) {
-                               msg_info ("invalid DNS pointer");
-                               return NULL;
-                       }
-                       decompressed ++;
-                       l2 ++;
-                       c += 2;
-               }
-               else {
-                       l2 = ++c;
-                       c += len2;
-               }
-               if (len1 != len2) {
-                       return NULL;
-               }
-               if (len1 == 0) {
-                       break;
-               }
-
-               if (memcmp (l1, l2, len1) != 0) {
-                       return NULL;
-               }
-               if (decompressed == 2) {
-                       break;
-               }
-       }
-
-       /* p now points to the end of QR section */
-       /* Compare class and type */
-       if (memcmp (p, c, sizeof (guint16) * 2) == 0) {
-               return p + sizeof (guint16) * 2;
-       }
-       return NULL;
-}
-
-#define MAX_RECURSION_LEVEL 10
-
-static gboolean
-dns_parse_labels (guint8 *in, gchar **target, guint8 **pos, struct rspamd_dns_reply *rep,
-               gint *remain, gboolean make_name)
-{
-       guint16 namelen = 0;
-       guint8 *p = *pos, *begin = *pos, *l, *t, *end = *pos + *remain, *new_pos = *pos;
-       guint16 llen;
-       gint length = *remain, new_remain = *remain;
-       gint ptrs = 0, labels = 0;
-       gboolean got_compression = FALSE;
-
-       /* First go through labels and calculate name length */
-       while (p - begin < length) {
-               if (ptrs > MAX_RECURSION_LEVEL) {
-                       msg_warn ("dns pointers are nested too much");
-                       return FALSE;
-               }
-               llen = *p;
-               if (llen == 0) {
-                       if (!got_compression) {
-                               /* In case of compression we have already decremented the processing position */
-                               new_remain -= sizeof (guint8);
-                               new_pos += sizeof (guint8);
-                       }
-                       break;
-               }
-               else if ((llen & DNS_COMPRESSION_BITS)) {
-                       if (end - p > 1) {
-                               ptrs ++;
-                               llen = UNCOMPRESS_DNS_OFFSET(p);
-                               l = decompress_label (in, &llen, end - in);
-                               if (l == NULL) {
-                                       msg_info ("invalid DNS pointer");
-                                       return FALSE;
-                               }
-                               if (!got_compression) {
-                                       /* Our label processing is finished actually */
-                                       new_remain -= sizeof (guint16);
-                                       new_pos += sizeof (guint16);
-                                       got_compression = TRUE;
-                               }
-                               if (l < in || l > begin + length) {
-                                       msg_warn  ("invalid pointer in DNS packet");
-                                       return FALSE;
-                               }
-                               begin = l;
-                               length = end - begin;
-                               p = l + *l + 1;
-                               namelen += *l;
-                               labels ++;
-                       }
-                       else {
-                               msg_warn ("DNS packet has incomplete compressed label, input length: %d bytes, remain: %d",
-                                               *remain, new_remain);
-                               return FALSE;
-                       }
-               }
-               else {
-                       namelen += llen;
-                       p += llen + 1;
-                       labels ++;
-                       if (!got_compression) {
-                               new_remain -= llen + 1;
-                               new_pos += llen + 1;
-                       }
-               }
-       }
-
-       if (!make_name) {
-               goto end;
-       }
-       *target = memory_pool_alloc (rep->request->pool, namelen + labels + 3);
-       t = (guint8 *)*target;
-       p = *pos;
-       begin = *pos;
-       length = *remain;
-       /* Now copy labels to name */
-       while (p - begin < length) {
-               llen = *p;
-               if (llen == 0) {
-                       break;
-               }
-               else if (llen & DNS_COMPRESSION_BITS) {
-                       llen = UNCOMPRESS_DNS_OFFSET(p);
-                       l = decompress_label (in, &llen, end - in);
-                       begin = l;
-                       length = end - begin;
-                       p = l + *l + 1;
-                       memcpy (t, l + 1, *l);
-                       t += *l;
-                       *t ++ = '.';
-               }
-               else {
-                       memcpy (t, p + 1, *p);
-                       t += *p;
-                       *t ++ = '.';
-                       p += *p + 1;
-               }
-       }
-       *(t - 1) = '\0';
-end:
-       *remain = new_remain;
-       *pos = new_pos;
-
-       return TRUE;
-}
-
-#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, struct rspamd_reply_entry *elt, guint8 **pos, struct rspamd_dns_reply *rep, gint *remain)
-{
-       guint8 *p = *pos, parts;
-       guint16 type, datalen, txtlen, copied, ttl;
-       gboolean parsed = FALSE;
-
-       /* Skip the whole name */
-       if (! dns_parse_labels (in, NULL, &p, rep, remain, FALSE)) {
-               msg_info ("bad RR name");
-               return -1;
-       }
-       if (*remain < (gint)sizeof (guint16) * 6) {
-               msg_info ("stripped dns reply: %d bytes remain", *remain);
-               return -1;
-       }
-       GET16 (type);
-       GET16 (ttl);
-       /* Skip class */
-       SKIP (guint32);
-       GET16 (datalen);
-       /* Now p points to RR data */
-       switch (type) {
-       case DNS_T_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 {
-                       msg_info ("corrupted A record");
-                       return -1;
-               }
-               break;
-#ifdef HAVE_INET_PTON
-       case DNS_T_AAAA:
-               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 {
-                       msg_info ("corrupted AAAA record");
-                       return -1;
-               }
-               break;
-#endif
-       case DNS_T_PTR:
-               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:
-               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:
-       case DNS_T_SPF:
-               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->content.txt.data + copied) = '\0';
-               parsed = TRUE;
-               elt->type = DNS_REQUEST_TXT;
-               break;
-       case DNS_T_SRV:
-               if (p - *pos > (gint)(*remain - sizeof (guint16) * 3)) {
-                       msg_info ("stripped dns reply while reading SRV record");
-                       return -1;
-               }
-               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 */
-               p += datalen;
-               *remain -= datalen;
-               break;
-       default:
-               msg_debug ("unexpected RR type: %d", type);
-               p += datalen;
-               *remain -= datalen;
-               break;
-       }
-       *pos = p;
-
-       if (parsed) {
-               elt->ttl = ttl;
-               return 1;
-       }
-       return 0;
-}
-
-static gboolean
-dns_parse_reply (gint sock, guint8 *in, gint r, struct rspamd_dns_resolver *resolver,
-               struct rspamd_dns_request **req_out, struct rspamd_dns_reply **_rep)
-{
-       struct dns_header *header = (struct dns_header *)in;
-       struct rspamd_dns_request      *req;
-       struct rspamd_dns_reply        *rep;
-       struct rspamd_dns_io_channel   *ioc;
-       struct rspamd_reply_entry      *elt;
-       guint8                         *pos;
-       guint16                         id;
-       gint                            i, t;
-       
-       /* First check header fields */
-       if (header->qr == 0) {
-               msg_info ("got request while waiting for reply");
-               return FALSE;
-       }
-
-       /* Find io channel */
-       if ((ioc = g_hash_table_lookup (resolver->io_channels, GINT_TO_POINTER (sock))) == NULL) {
-               msg_err ("io channel is not found for this resolver: %d", sock);
-               return FALSE;
-       }
-
-       /* Now try to find corresponding request */
-       id = header->qid;
-       if ((req = g_hash_table_lookup (ioc->requests, &id)) == NULL) {
-               /* No such requests found */
-               msg_debug ("DNS request with id %d has not been found for IO channel", (gint)id);
-               return FALSE;
-       }
-       *req_out = req;
-       /* 
-        * Now we have request and query data is now at the end of header, so compare
-        * request QR section and reply QR section
-        */
-       if ((pos = dns_request_reply_cmp (req, in + sizeof (struct dns_header),
-                       r - sizeof (struct dns_header))) == NULL) {
-               msg_debug ("DNS request with id %d is for different query, ignoring", (gint)id);
-               return FALSE;
-       }
-       /*
-        * Now pos is in answer section, so we should extract data and form reply
-        */
-       rep = memory_pool_alloc (req->pool, sizeof (struct rspamd_dns_reply));
-       rep->request = req;
-       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 (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) {
-                               DL_APPEND (rep->entries, elt);
-                       }
-               }
-       }
-       
-       *_rep = rep;
-       return TRUE;
-}
-
-static void
-dns_throttling_cb (gint fd, short what, void *arg)
-{
-       struct rspamd_dns_resolver *resolver = arg;
-
-       resolver->throttling = FALSE;
-       resolver->errors = 0;
-       msg_info ("stop DNS throttling after %d seconds", (int)resolver->throttling_time.tv_sec);
-       event_del (&resolver->throttling_event);
-}
-
-static void
-dns_check_throttling (struct rspamd_dns_resolver *resolver)
-{
-       if (resolver->errors > resolver->max_errors && !resolver->throttling) {
-               msg_info ("starting DNS throttling after %ud errors", resolver->errors);
-               /* Init throttling timeout */
-               resolver->throttling = TRUE;
-               evtimer_set (&resolver->throttling_event, dns_throttling_cb, resolver);
-               event_base_set (resolver->ev_base, &resolver->throttling_event);
-               event_add (&resolver->throttling_event, &resolver->throttling_time);
-       }
-}
-
-static void
-dns_read_cb (gint fd, short what, void *arg)
-{
-       struct rspamd_dns_resolver     *resolver = arg;
-       struct rspamd_dns_request      *req = NULL;
-       gint                            r;
-       struct rspamd_dns_reply        *rep;
-       guint8                          in[UDP_PACKET_SIZE];
-
-       /* This function is called each time when we have data on one of server's sockets */
-       
-       /* First read packet from socket */
-       r = read (fd, in, sizeof (in));
-       if (r > (gint)(sizeof (struct dns_header) + sizeof (struct dns_query))) {
-               if (dns_parse_reply (fd, in, r, resolver, &req, &rep)) {
-                       /* Decrease errors count */
-                       if (rep->request->resolver->errors > 0) {
-                               rep->request->resolver->errors --;
-                       }
-                       upstream_ok (&rep->request->io->srv->up, rep->request->time);
-                       rep->request->func (rep, rep->request->arg);
-                       remove_normal_event (req->session, dns_fin_cb, req);
-               }
-       }
-}
-
-static void
-dns_timer_cb (gint fd, short what, void *arg)
-{
-       struct rspamd_dns_request *req = arg;
-       struct rspamd_dns_reply *rep;
-       struct rspamd_dns_server *serv;
-       gint                            r;
-       
-       /* Retransmit dns request */
-       req->retransmits ++;
-       serv = req->io->srv;
-       if (req->retransmits >= req->resolver->max_retransmits) {
-               msg_err ("maximum number of retransmits expired for resolving %s of type %s",
-                               req->requested_name, dns_strtype (req->type));
-               dns_check_throttling (req->resolver);
-               req->resolver->errors ++;
-               goto err;
-       }
-
-       if (req->sock == -1) {
-               goto err;
-       }
-       /* Add other retransmit event */
-       r = send_dns_request (req);
-       if (r == -1) {
-               goto err;
-       }
-
-       msg_debug ("retransmit DNS request with ID %d", (int)req->id);
-       evtimer_add (&req->timer_event, &req->tv);
-
-       return;
-err:
-       msg_debug ("error on retransmitting DNS request with ID %d", (int)req->id);
-       rep = memory_pool_alloc0 (req->pool, sizeof (struct rspamd_dns_reply));
-       rep->request = req;
-       rep->code = DNS_RC_SERVFAIL;
-       if (serv) {
-               upstream_fail (&serv->up, rep->request->time);
-       }
-       req->func (rep, req->arg);
-       remove_normal_event (req->session, dns_fin_cb, req);
-       return;
-}
-
-static void
-dns_retransmit_handler (gint fd, short what, void *arg)
-{
-       struct rspamd_dns_request *req = arg;
-       struct rspamd_dns_reply *rep;
-       struct rspamd_dns_server *serv;
-       gint r;
-
-       remove_normal_event (req->session, (event_finalizer_t)event_del, &req->io_event);
-       serv = req->io->srv;
-
-       if (what == EV_WRITE) {
-               /* Retransmit dns request */
-               req->retransmits ++;
-               event_del (&req->io_event);
-               if (req->retransmits >= req->resolver->max_retransmits) {
-                       msg_err ("maximum number of retransmits expired for %s", req->requested_name);
-                       rep = memory_pool_alloc0 (req->pool, sizeof (struct rspamd_dns_reply));
-                       rep->request = req;
-                       rep->code = DNS_RC_SERVFAIL;
-                       upstream_fail (&serv->up, rep->request->time);
-                       req->resolver->errors ++;
-                       dns_check_throttling (req->resolver);
-
-                       req->func (rep, req->arg);
-
-                       return;
-               }
-               r = send_dns_request (req);
-               if (r == -1) {
-                       rep = memory_pool_alloc0 (req->pool, sizeof (struct rspamd_dns_reply));
-                       rep->request = req;
-                       rep->code = DNS_RC_SERVFAIL;
-                       upstream_fail (&serv->up, rep->request->time);
-                       req->func (rep, req->arg);
-
-               }
-               else if (r == 1) {
-                       /* Add timer event */
-                       event_del (&req->timer_event);
-                       evtimer_set (&req->timer_event, dns_timer_cb, req);
-                       event_base_set (req->resolver->ev_base, &req->timer_event);
-                       evtimer_add (&req->timer_event, &req->tv);
-
-                       /* Add request to hash table */
-                       g_hash_table_insert (req->io->requests, &req->id, req);
-                       register_async_event (req->session, (event_finalizer_t)dns_fin_cb,
-                                       req, g_quark_from_static_string ("dns resolver"));
-               }
-       }
+       remove_normal_event (reqdata->session, rspamd_dns_fin_cb, reqdata->req);
 }
 
 gboolean 
 make_dns_request (struct rspamd_dns_resolver *resolver,
-               struct rspamd_async_session *session, memory_pool_t *pool, dns_callback_type cb, 
-               gpointer ud, enum rspamd_request_type type, ...)
+               struct rspamd_async_session *session, memory_pool_t *pool, dns_callback_type cb,
+               gpointer ud, enum rdns_request_type type, const char *name)
 {
-       va_list args;
-       struct rspamd_dns_request *req;
-       struct rspamd_dns_server *serv;
-       struct in_addr *addr;
-       const gchar *name, *service, *proto;
-       gint r;
-       const gint max_id_cycles = 32;
-       struct dns_header *header;
-
-       /* If no DNS servers defined silently return FALSE */
-       if (resolver->servers_num == 0) {
-               return FALSE;
-       }
-       /* Check throttling */
-       if (resolver->throttling) {
-               return FALSE;
-       }
-
-       req = memory_pool_alloc (pool, sizeof (struct rspamd_dns_request));
-       req->pool = pool;
-       req->session = session;
-       req->resolver = resolver;
-       req->func = cb;
-       req->arg = ud;
-       req->type = type;
-       
-       va_start (args, type);
-       switch (type) {
-               case DNS_REQUEST_PTR:
-                       addr = va_arg (args, struct in_addr *);
-                       make_ptr_req (req, addr);
-                       break;
-               case DNS_REQUEST_MX:
-                       name = va_arg (args, const gchar *);
-                       make_mx_req (req, name);
-                       break;
-               case DNS_REQUEST_A:
-                       name = va_arg (args, const gchar *);
-                       make_a_req (req, name);
-                       break;
-               case DNS_REQUEST_AAA:
-#ifdef HAVE_INET_PTON
-                       name = va_arg (args, const gchar *);
-                       make_aaa_req (req, name);
-                       break;
-#else
-                       msg_err ("your system has no ipv6 support, cannot make aaa request");
-                       break;
-#endif
-               case DNS_REQUEST_TXT:
-                       name = va_arg (args, const gchar *);
-                       make_txt_req (req, name);
-                       break;
-               case DNS_REQUEST_SPF:
-                       name = va_arg (args, const gchar *);
-                       make_spf_req (req, name);
-                       break;
-               case DNS_REQUEST_SRV:
-                       service = va_arg (args, const gchar *);
-                       proto = va_arg (args, const gchar *);
-                       name = va_arg (args, const gchar *);
-                       make_srv_req (req, service, proto, name);
-                       break;
-       }
-       va_end (args);
-
-       /* Add EDNS RR */
-       rspamd_dns_add_edns0 (req);
-
-       req->retransmits = 0;
-       req->time = time (NULL);
-       if (resolver->is_master_slave) {
-               serv = (struct rspamd_dns_server *)get_upstream_master_slave (resolver->servers,
-                               resolver->servers_num, sizeof (struct rspamd_dns_server),
-                               req->time, DEFAULT_UPSTREAM_ERROR_TIME, DEFAULT_UPSTREAM_DEAD_TIME, DEFAULT_UPSTREAM_MAXERRORS);
-       }
-       else {
-               serv = (struct rspamd_dns_server *)get_upstream_round_robin (resolver->servers,
-                               resolver->servers_num, sizeof (struct rspamd_dns_server),
-                               req->time, DEFAULT_UPSTREAM_ERROR_TIME, DEFAULT_UPSTREAM_DEAD_TIME, DEFAULT_UPSTREAM_MAXERRORS);
-       }
-       if (serv == NULL) {
-               msg_err ("cannot find suitable server for request");
-               return FALSE;
-       }
+       struct rdns_request *req;
+       struct rspamd_dns_request_ud *reqdata;
        
-       /* Now select IO channel */
+       reqdata = memory_pool_alloc (pool, sizeof (struct rspamd_dns_request_ud));
+       reqdata->session = session;
+       reqdata->cb = cb;
+       reqdata->ud = ud;
 
-       req->io = serv->cur_io_channel;
-       if (req->io == NULL) {
-               msg_err ("cannot find suitable io channel for the server %s", serv->name);
-               return FALSE;
-       }
-       serv->cur_io_channel = serv->cur_io_channel->next;
-       req->sock = req->io->sock;
+       req = rdns_make_request_full (resolver->r, rspamd_dns_callback, reqdata,
+                       resolver->request_timeout, resolver->max_retransmits, name, 1, type);
 
-       if (req->sock == -1) {
-               return FALSE;
-       }
-
-       /* Fill timeout */
-       msec_to_tv (resolver->request_timeout, &req->tv);
-       evtimer_set (&req->timer_event, dns_timer_cb, req);
-       event_base_set (req->resolver->ev_base, &req->timer_event);
-       
-       /* Now send request to server */
-       r = send_dns_request (req);
-
-       if (r == 1) {
-               /* Add request to hash table */
-               r = 0;
-               while (g_hash_table_lookup (req->io->requests, &req->id)) {
-                       /* Check for unique id */
-                       header = (struct dns_header *)req->packet;
-                       header->qid = dns_permutor_generate_id ();
-                       req->id = header->qid;
-                       if (++r > max_id_cycles) {
-                               msg_err ("cannot generate new id for server %s", serv->name);
-                               return FALSE;
-                       }
-               }
-               /* Add timer event */
-               evtimer_add (&req->timer_event, &req->tv);
-               g_hash_table_insert (req->io->requests, &req->id, req);
-               register_async_event (session, (event_finalizer_t)dns_fin_cb, req,
+       if (req != NULL) {
+               register_async_event (session, (event_finalizer_t)rspamd_dns_fin_cb, req,
                                g_quark_from_static_string ("dns resolver"));
+               /* Ref event to free it only when according async event is deleted from the session */
+               rdns_request_retain (req);
+               reqdata->req = req;
        }
-       else if (r == -1) {
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static gboolean
-parse_resolv_conf (struct rspamd_dns_resolver *resolver)
-{
-       FILE                           *r;
-       gchar                           buf[BUFSIZ], *p, addr_holder[16];
-       struct rspamd_dns_server       *new;
-
-       r = fopen (RESOLV_CONF, "r");
-
-       if (r == NULL) {
-               msg_err ("cannot open %s: %s", RESOLV_CONF, strerror (errno));
+       else {
                return FALSE;
        }
-       
-       while (! feof (r)) {
-               if (fgets (buf, sizeof (buf), r)) {
-                       g_strstrip (buf);
-                       if (g_ascii_strncasecmp (buf, "nameserver", sizeof ("nameserver") - 1) == 0) {
-                               p = buf + sizeof ("nameserver");
-                               while (*p && g_ascii_isspace (*p)) {
-                                       p ++;
-                               }
-                               if (! *p) {
-                                       msg_warn ("cannot parse empty nameserver line in resolv.conf");
-                                       continue;
-                               }
-                               else {
-                                       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 = strdup (p);
-                                               resolver->servers_num ++;
-                                       }
-                                       else {
-                                               msg_warn ("cannot parse ip address of nameserver: %s", p);
-                                               continue;
-                                       }
-                               }
-                       }
-               }
-       }
 
-       fclose (r);
        return TRUE;
 }
 
-/* Hashing utilities */
-static gboolean
-dns_id_equal (gconstpointer v1, gconstpointer v2)
-{
-       return *((const guint16*) v1) == *((const guint16*) v2);
-}
-
-static guint
-dns_id_hash (gconstpointer v)
-{
-       return *(const guint16 *) v;
-}
-
 
 struct rspamd_dns_resolver *
 dns_resolver_init (struct event_base *ev_base, struct config_file *cfg)
 {
        GList                          *cur;
        struct rspamd_dns_resolver     *new;
-       gchar                          *begin, *p, *err, addr_holder[16];
-       gint                            priority, i, j;
-       struct rspamd_dns_server       *serv;
-       struct rspamd_dns_io_channel   *ioc;
+       gchar                          *begin, *p, *err;
+       gint                            priority;
        
        new = g_slice_alloc0 (sizeof (struct rspamd_dns_resolver));
        new->ev_base = ev_base;
-       new->io_channels = g_hash_table_new (g_direct_hash, g_direct_equal);
        new->request_timeout = cfg->dns_timeout;
        new->max_retransmits = cfg->dns_retransmits;
-       new->max_errors = cfg->dns_throttling_errors;
-       msec_to_tv (cfg->dns_throttling_time, &new->throttling_time);
+
+       new->r = rdns_resolver_new ();
+       rdns_bind_libevent (new->r, new->ev_base);
+       rdns_resolver_set_log_level (new->r, cfg->log_level);
 
        if (cfg->nameservers == NULL) {
                /* Parse resolv.conf */
-               if (! parse_resolv_conf (new) || new->servers_num == 0) {
+               if (!rdns_resolver_parse_resolv_conf (new->r, "/etc/resolv.conf")) {
                        msg_err ("cannot parse resolv.conf and no nameservers defined, so no ways to resolve addresses");
                        return new;
                }
@@ -1360,42 +125,15 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg)
                        if (p != NULL) {
                                *p = '\0';
                                p ++;
-                               if (!new->is_master_slave) {
-                                       priority = strtoul (p, &err, 10);
-                                       if (err != NULL && *err != '\0') {
-                                               if ((*err == 'm' || *err == 'M' || *err == 's' || *err == 'S')) {
-                                                       new->is_master_slave = TRUE;
-                                               }
-                                               else {
-                                                       msg_info ("bad character '%x', must be 'm' or 's' or a numeric priority", *err);
-                                               }
-                                       }
-                               }
-                               if (new->is_master_slave) {
-                                       if (*p == 'm' || *p == 'M') {
-                                               priority = 100;
-                                       }
-                                       else if (*p == 's' || *p == 'S') {
-                                               priority = 1;
-                                       }
-                                       else {
-                                               msg_info ("master/slave mode is turned on, and %c character is invalid", *p);
-                                               priority = 0;
-                                       }
+                               priority = strtoul (p, &err, 10);
+                               if (err != NULL && *err != '\0') {
+                                       msg_info ("bad character '%x', must be 'm' or 's' or a numeric priority", *err);
                                }
                        }
                        else {
                                priority = 0;
                        }
-                       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 = strdup (begin);
-                               serv->up.priority = priority;
-                               serv->up.weight = priority;
-                               new->servers_num ++;
-                       }
-                       else {
+                       if (!rdns_resolver_add_server (new->r, begin, 53, priority, cfg->dns_io_per_server)) {
                                msg_warn ("cannot parse ip address of nameserver: %s", begin);
                                cur = g_list_next (cur);
                                continue;
@@ -1403,56 +141,10 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg)
 
                        cur = g_list_next (cur);
                }
-               if (new->servers_num == 0) {
-                       msg_err ("no valid nameservers defined, try to parse resolv.conf");
-                       if (! parse_resolv_conf (new) || new->servers_num == 0) {
-                               msg_err ("cannot parse resolv.conf and no nameservers defined, so no ways to resolve addresses");
-                               return new;
-                       }
-               }
 
        }
-       /* Now init io channels to all servers */
-       for (i = 0; i < new->servers_num; i ++) {
-               serv = &new->servers[i];
-               for (j = 0; j < (gint)cfg->dns_io_per_server; j ++) {
-                       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);
-                               ioc->srv = serv;
-                               ioc->resolver = new;
-                               event_set (&ioc->ev, ioc->sock, EV_READ | EV_PERSIST, dns_read_cb, new);
-                               event_base_set (new->ev_base, &ioc->ev);
-                               event_add (&ioc->ev, NULL);
-                               CDL_PREPEND (serv->io_channels, ioc);
-                               serv->cur_io_channel = ioc;
-                               g_hash_table_insert (new->io_channels, GINT_TO_POINTER (ioc->sock), ioc);
-                       }
-               }
-       }
-
-       return new;
-}
 
-const gchar *
-dns_strerror (enum dns_rcode rcode)
-{
-       rcode &= 0xf;
-       static gchar numbuf[16];
+       rdns_resolver_init (new->r);
 
-       if ('\0' == dns_rcodes[rcode][0]) {
-               rspamd_snprintf (numbuf, sizeof (numbuf), "UNKNOWN: %d", (gint)rcode);
-               return numbuf;
-       }
-       return dns_rcodes[rcode];
-}
-
-const gchar *
-dns_strtype (enum rspamd_request_type type)
-{
-       return dns_types[type];
+       return new;
 }
index ee52ba13c4381cdb252e0211acce3ae36ba907ca..e39fb987634026303d00b373a913b0c8340a7bf5 100644 (file)
--- a/src/dns.h
+++ b/src/dns.h
 #include "config.h"
 #include "mem_pool.h"
 #include "events.h"
-#include "upstream.h"
-
-struct rspamd_dns_reply;
-struct config_file;
-
-typedef void (*dns_callback_type) (struct rspamd_dns_reply *reply, gpointer arg);
-
-enum rspamd_request_type {
-       DNS_REQUEST_A = 0,
-       DNS_REQUEST_PTR,
-       DNS_REQUEST_MX,
-       DNS_REQUEST_TXT,
-       DNS_REQUEST_SRV,
-       DNS_REQUEST_SPF,
-       DNS_REQUEST_AAA
-};
-
-struct rspamd_dns_request {
-       memory_pool_t *pool;                            /**< pool associated with request                       */
-       struct rspamd_dns_resolver *resolver;
-       struct rspamd_dns_io_channel *io;
-       dns_callback_type func;
-       gpointer arg;
-       struct event timer_event;
-       struct event io_event;
-       struct timeval tv;
-       guint retransmits;
-       guint16 id;
-       struct rspamd_async_session *session;
-       struct rspamd_dns_reply *reply;
-       guint8 *packet;
-       const gchar *requested_name;
-       off_t pos;
-       guint packet_len;
-       gint sock;
-       enum rspamd_request_type type;
-       time_t time;
-       struct rspamd_dns_request *next;
-};
-
-union rspamd_reply_element_un {
-       struct {
-               struct in_addr addr;
-               guint16 addrcount;
-       } a;
-#ifdef HAVE_INET_PTON
-       struct {
-               struct in6_addr addr;
-       } aaa;
-#endif
-       struct {
-               gchar *name;
-       } ptr;
-       struct {
-               gchar *name;
-               guint16 priority;
-       } mx;
-       struct {
-               gchar *data;
-       } txt;
-       struct {
-               guint16 priority;
-               guint16 weight;
-               guint16 port;
-               gchar *target;
-       } 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,
-       DNS_RC_SERVFAIL = 2,
-       DNS_RC_NXDOMAIN = 3,
-       DNS_RC_NOTIMP   = 4,
-       DNS_RC_REFUSED  = 5,
-       DNS_RC_YXDOMAIN = 6,
-       DNS_RC_YXRRSET  = 7,
-       DNS_RC_NXRRSET  = 8,
-       DNS_RC_NOTAUTH  = 9,
-       DNS_RC_NOTZONE  = 10,
-};
-       
-struct rspamd_dns_reply {
-       struct rspamd_dns_request *request;
-       enum dns_rcode code;
-       struct rspamd_reply_entry *entries;
-};
+#include "rdns.h"
 
+struct rspamd_dns_resolver;
 
 /* Rspamd DNS API */
 
@@ -145,17 +52,7 @@ struct rspamd_dns_resolver *dns_resolver_init (struct event_base *ev_base, struc
  * @return TRUE if request was sent.
  */
 gboolean make_dns_request (struct rspamd_dns_resolver *resolver, 
-               struct rspamd_async_session *session, memory_pool_t *pool, dns_callback_type cb, 
-               gpointer ud, enum rspamd_request_type type, ...);
-
-/**
- * Get textual presentation of DNS error code
- */
-const gchar *dns_strerror (enum dns_rcode rcode);
-
-/**
- * Get textual presentation of DNS request type
- */
-const gchar *dns_strtype (enum rspamd_request_type type);
+               struct rspamd_async_session *session, memory_pool_t *pool,
+               dns_callback_type cb, gpointer ud, enum rdns_request_type type, const char *name);
 
 #endif
index 2bfbe582f125a8960ef39f2baa8e10e23487b58b..b3d8f768f241bf172f19e3f48bb2d99c4520fa7d 100644 (file)
@@ -66,12 +66,12 @@ struct lua_dns_cbdata {
 };
 
 static void
-lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+lua_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct lua_dns_cbdata              *cd = arg;
        gint                            i = 0;
        struct rspamd_dns_resolver    **presolver;
-       struct rspamd_reply_entry     *elt;
+       struct rdns_reply_entry        *elt;
 
        lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->cbref);
        presolver = lua_newuserdata (cd->L, sizeof (gpointer));
@@ -86,13 +86,6 @@ lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
        if (reply->code == DNS_RC_NOERROR) {
                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;
-                       }
                        switch (elt->type) {
                        case DNS_REQUEST_A:
                                lua_ip_push (cd->L, AF_INET, &elt->content.a.addr);
@@ -127,7 +120,7 @@ lua_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
        }
        else {
                lua_pushnil (cd->L);
-               lua_pushstring (cd->L, dns_strerror (reply->code));
+               lua_pushstring (cd->L, rdns_strerror (reply->code));
        }
 
        if (cd->user_str != NULL) {
@@ -179,7 +172,8 @@ lua_dns_resolver_init (lua_State *L)
 }
 
 static int
-lua_dns_resolver_resolve_common (lua_State *L, struct rspamd_dns_resolver *resolver, enum rspamd_request_type type)
+lua_dns_resolver_resolve_common (lua_State *L, struct rspamd_dns_resolver *resolver,
+               enum rdns_request_type type)
 {
        struct rspamd_async_session                                     *session, **psession;
        memory_pool_t                                                           *pool, **ppool;
index 324807005bc1cc97e39dee1e7ffe89d3578052ac..15fe08e81aab2b8bc89d629ee66d7d795a4d8bec 100644 (file)
@@ -299,10 +299,10 @@ lua_http_err_cb (GError * err, void *arg)
 
 
 static void
-lua_http_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+lua_http_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct lua_http_ud             *ud = arg;
-       struct rspamd_reply_entry      *elt;
+       struct rdns_reply_entry        *elt;
        struct in_addr                  ina;
        struct timeval                  tv;
 
index c0b5c7d52c18c970875df5083a6de03f7ecbe47c..dedb7850c16a6fd06b0c400e033c67b917b62938 100644 (file)
@@ -240,14 +240,14 @@ lua_redis_make_request_real (struct lua_redis_userdata *ud)
  * @param arg user data
  */
 static void
-lua_redis_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+lua_redis_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct lua_redis_userdata                       *ud = arg;
-       struct rspamd_reply_entry                       *elt;
+       struct rdns_reply_entry                 *elt;
 
 
        if (reply->code != DNS_RC_NOERROR) {
-               lua_redis_push_error (dns_strerror (reply->code), ud, FALSE);
+               lua_redis_push_error (rdns_strerror (reply->code), ud, FALSE);
                return;
        }
        else {
index 062e0b8ac7972cd7ecdb15f1e4116576221abfa2..eebe63c496c1249222e5a6871803d20c89ee04c4 100644 (file)
@@ -58,7 +58,7 @@
 static struct surbl_ctx        *surbl_module_ctx = NULL;
 
 static void surbl_test_url (struct worker_task *task, void *user_data);
-static void dns_callback (struct rspamd_dns_reply *reply, gpointer arg);
+static void dns_callback (struct rdns_reply *reply, gpointer arg);
 static void process_dns_results (struct worker_task *task,
                struct suffix_item *suffix, gchar *url, guint32 addr);
 
@@ -628,7 +628,8 @@ make_surbl_requests (struct uri *url, struct worker_task *task,
                        param->suffix = suffix;
                        param->host_resolve = memory_pool_strdup (task->task_pool, surbl_req);
                        debug_task ("send surbl dns request %s", surbl_req);
-                       if (make_dns_request (task->resolver, task->s, task->task_pool, dns_callback, (void *)param, DNS_REQUEST_A, surbl_req)) {
+                       if (make_dns_request (task->resolver, task->s, task->task_pool, dns_callback,
+                                       (void *)param, DNS_REQUEST_A, surbl_req)) {
                                task->dns_requests ++;
                        }
                }
@@ -670,23 +671,25 @@ process_dns_results (struct worker_task *task, struct suffix_item *suffix, gchar
 }
 
 static void
-dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct dns_param               *param = (struct dns_param *)arg;
        struct worker_task             *task = param->task;
-       struct rspamd_reply_entry      *elt;
+       struct rdns_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->entries) {
-               msg_info ("<%s> domain [%s] is in surbl %s", param->task->message_id, param->host_resolve, param->suffix->suffix);
+               msg_info ("<%s> domain [%s] is in surbl %s", param->task->message_id,
+                               param->host_resolve, param->suffix->suffix);
                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);
+               debug_task ("<%s> domain [%s] is not in surbl %s",
+                               param->task->message_id, param->host_resolve, param->suffix->suffix);
        }
 }
 
index 9f1eef254576b6a632c96d7e8117c75b5e4ec0be..4a9991016a7f820620817f9d3359810fd02ec5ea 160000 (submodule)
--- a/src/rdns
+++ b/src/rdns
@@ -1 +1 @@
-Subproject commit 9f1eef254576b6a632c96d7e8117c75b5e4ec0be
+Subproject commit 4a9991016a7f820620817f9d3359810fd02ec5ea
index 423a9b0bd5d529741ca37ae63cbb6bfea16d171c..c75cb530d41dab5a82ee0b46d855c7057d96e80a 100644 (file)
@@ -476,7 +476,7 @@ create_smtp_proxy_upstream_connection (struct smtp_proxy_session *session)
 }
 
 static void
-smtp_dnsbl_cb (struct rspamd_dns_reply *reply, void *arg)
+smtp_dnsbl_cb (struct rdns_reply *reply, void *arg)
 {
        struct smtp_proxy_session                                               *session = arg;
        const gchar                                                                             *p;
@@ -484,13 +484,13 @@ smtp_dnsbl_cb (struct rspamd_dns_reply *reply, void *arg)
 
        session->rbl_requests --;
 
-       msg_debug ("got reply for %s: %s", reply->request->requested_name, dns_strerror (reply->code));
+       msg_debug ("got reply for %s: %s", rdns_request_get_name (reply->request), rdns_strerror (reply->code));
 
        if (session->state != SMTP_PROXY_STATE_REJECT) {
 
                if (reply->code == DNS_RC_NOERROR) {
                        /* This means that address is in dnsbl */
-                       p = reply->request->requested_name;
+                       p = rdns_request_get_name (reply->request);
                        while (*p) {
                                if (*p == '.') {
                                        dots ++;
@@ -648,11 +648,11 @@ smtp_make_delay (struct smtp_proxy_session *session)
  * Handle DNS replies
  */
 static void
-smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg)
+smtp_dns_cb (struct rdns_reply *reply, void *arg)
 {
        struct smtp_proxy_session                                               *session = arg;
        gint                                                                                     res = 0;
-       struct rspamd_reply_entry                                               *elt;
+       struct rdns_reply_entry                                                 *elt;
        GList                                                                                   *cur;
 
        switch (session->state)
@@ -662,7 +662,7 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg)
                if (reply->code != DNS_RC_NOERROR) {
                        rspamd_conditional_debug (rspamd_main->logger,
                                        session->client_addr.s_addr, __FUNCTION__, "DNS error: %s",
-                                       dns_strerror (reply->code));
+                                       rdns_strerror (reply->code));
 
                        if (reply->code == DNS_RC_NXDOMAIN) {
                                session->hostname = memory_pool_strdup (session->pool,
@@ -691,7 +691,7 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg)
                if (reply->code != DNS_RC_NOERROR) {
                        rspamd_conditional_debug (rspamd_main->logger,
                                        session->client_addr.s_addr, __FUNCTION__, "DNS error: %s",
-                                       dns_strerror (reply->code));
+                                       rdns_strerror (reply->code));
 
                        if (reply->code == DNS_RC_NXDOMAIN) {
                                session->hostname = memory_pool_strdup (session->pool,
@@ -718,7 +718,8 @@ smtp_dns_cb (struct rspamd_dns_reply *reply, void *arg)
 
                        if (res == 0) {
                                msg_info(
-                                               "cannot find address for hostname: %s, ip: %s", session->hostname, inet_ntoa (session->client_addr));
+                                               "cannot find address for hostname: %s, ip: %s", session->hostname,
+                                               inet_ntoa (session->client_addr));
                                session->hostname = memory_pool_strdup (session->pool,
                                                XCLIENT_HOST_UNAVAILABLE);
                        }
index 2d0b5b8eb5738d20bc9c7b33988f8a589b229ef2..e58d44ab88cfd59a12f47da31d8a320f6954fc81 100644 (file)
--- a/src/spf.c
+++ b/src/spf.c
@@ -387,11 +387,11 @@ parse_spf_hostmask (struct worker_task *task, const gchar *begin, struct spf_add
 }
 
 static void
-spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct spf_dns_cb               *cb = arg;
        gchar                           *begin;
-       struct rspamd_reply_entry      *elt_data;
+       struct rdns_reply_entry      *elt_data;
        GList                           *tmp = NULL;
        struct worker_task              *task;
        struct spf_addr                 *new_addr;
@@ -548,13 +548,13 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
        else if (reply->code == DNS_RC_NXDOMAIN) {
                switch (cb->cur_action) {
                                case SPF_RESOLVE_MX:
-                                       if (reply->request->type == DNS_REQUEST_MX) {
+                                       if (rdns_request_has_type (reply->request, 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->request->type != DNS_REQUEST_MX) {
+                                       else {
                                                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;
@@ -562,16 +562,14 @@ spf_record_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
                                        }
                                        break;
                                case SPF_RESOLVE_A:
-                                       if (reply->request->type == DNS_REQUEST_A) {
-                                               /* XXX: process only one record */
+                                       if (rdns_request_has_type (reply->request, DNS_REQUEST_A)) {
                                                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->request->type == DNS_REQUEST_AAA) {
-                                               /* XXX: process only one record */
+                                       if (rdns_request_has_type (reply->request, DNS_REQUEST_AAA)) {
                                                memset (&cb->addr->data.normal.d.in6, 0xff, sizeof (struct in6_addr));
                                                cb->addr->data.normal.mask = 32;
                                        }
@@ -1343,10 +1341,10 @@ start_spf_parse (struct spf_record *rec, gchar *begin, guint ttl)
 }
 
 static void
-spf_dns_callback (struct rspamd_dns_reply *reply, gpointer arg)
+spf_dns_callback (struct rdns_reply *reply, gpointer arg)
 {
        struct spf_record *rec = arg;
-       struct rspamd_reply_entry *elt;
+       struct rdns_reply_entry *elt;
 
        rec->requests_inflight --;
        if (reply->code == DNS_RC_NOERROR) {