aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-02-19 17:29:23 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-02-19 17:29:23 +0000
commit5b78ecce464ef90e4794ed3c6f1d0dcfd5ed2e83 (patch)
treef547db2872ebf1490d1a356b436b225496bb7a5c
parentc73632361af0ec1faea773257b4b8764713cb169 (diff)
downloadrspamd-5b78ecce464ef90e4794ed3c6f1d0dcfd5ed2e83.tar.gz
rspamd-5b78ecce464ef90e4794ed3c6f1d0dcfd5ed2e83.zip
Integrate rspamd with librdns.
-rw-r--r--CMakeLists.txt3
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/cfg_file.h2
-rw-r--r--src/cfg_rcl.c2
-rw-r--r--src/dkim.c6
-rw-r--r--src/dns.c1402
-rw-r--r--src/dns.h111
-rw-r--r--src/lua/lua_dns.c16
-rw-r--r--src/lua/lua_http.c4
-rw-r--r--src/lua/lua_redis.c6
-rw-r--r--src/plugins/surbl.c15
m---------src/rdns0
-rw-r--r--src/smtp_proxy.c17
-rw-r--r--src/spf.c18
14 files changed, 96 insertions, 1512 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30583c86f..14e2a0b58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 84f980655..b6a0731dd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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)
diff --git a/src/cfg_file.h b/src/cfg_file.h
index 6f3489455..13acb158f 100644
--- a/src/cfg_file.h
+++ b/src/cfg_file.h
@@ -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 */
diff --git a/src/cfg_rcl.c b/src/cfg_rcl.c
index 5793b5010..2d0f9b186 100644
--- a/src/cfg_rcl.c
+++ b/src/cfg_rcl.c
@@ -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,
diff --git a/src/dkim.c b/src/dkim.c
index fe48668aa..2b74d53ce 100644
--- a/src/dkim.c
+++ b/src/dkim.c
@@ -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 {
diff --git a/src/dns.c b/src/dns.c
index a74e5b692..5b2f928b2 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -25,1329 +25,94 @@
#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;
}
diff --git a/src/dns.h b/src/dns.h
index ee52ba13c..e39fb9876 100644
--- a/src/dns.h
+++ b/src/dns.h
@@ -29,102 +29,9 @@
#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
diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c
index 2bfbe582f..b3d8f768f 100644
--- a/src/lua/lua_dns.c
+++ b/src/lua/lua_dns.c
@@ -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;
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index 324807005..15fe08e81 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -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;
diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c
index c0b5c7d52..dedb7850c 100644
--- a/src/lua/lua_redis.c
+++ b/src/lua/lua_redis.c
@@ -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 {
diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c
index 062e0b8ac..eebe63c49 100644
--- a/src/plugins/surbl.c
+++ b/src/plugins/surbl.c
@@ -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);
}
}
diff --git a/src/rdns b/src/rdns
-Subproject 9f1eef254576b6a632c96d7e8117c75b5e4ec0b
+Subproject 4a9991016a7f820620817f9d3359810fd02ec5e
diff --git a/src/smtp_proxy.c b/src/smtp_proxy.c
index 423a9b0bd..c75cb530d 100644
--- a/src/smtp_proxy.c
+++ b/src/smtp_proxy.c
@@ -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);
}
diff --git a/src/spf.c b/src/spf.c
index 2d0b5b8eb..e58d44ab8 100644
--- 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) {