aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dns.c122
-rw-r--r--src/dns.h26
-rw-r--r--test/rspamd_dns_test.c15
3 files changed, 147 insertions, 16 deletions
diff --git a/src/dns.c b/src/dns.c
index 12cc63b16..dcbde4afe 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -420,7 +420,7 @@ static void
make_ptr_req (struct rspamd_dns_request *req, struct in_addr addr)
{
char ipbuf[sizeof("255.255.255.255.in-addr.arpa")];
- guint32 a = addr.s_addr, r;
+ guint32 a = ntohl (addr.s_addr), r;
guint16 *p;
r = rspamd_snprintf (ipbuf, sizeof(ipbuf), "%d.%d.%d.%d.in-addr.arpa",
@@ -435,6 +435,7 @@ make_ptr_req (struct rspamd_dns_request *req, struct in_addr addr)
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;
}
@@ -452,6 +453,7 @@ make_a_req (struct rspamd_dns_request *req, const char *name)
*p = htons (DNS_C_IN);
req->pos += sizeof (guint16) * 2;
req->type = DNS_REQUEST_A;
+ req->requested_name = name;
}
static void
@@ -467,6 +469,7 @@ make_txt_req (struct rspamd_dns_request *req, const char *name)
*p = htons (DNS_C_IN);
req->pos += sizeof (guint16) * 2;
req->type = DNS_REQUEST_TXT;
+ req->requested_name = name;
}
static void
@@ -482,6 +485,45 @@ make_mx_req (struct rspamd_dns_request *req, const char *name)
*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 char *service, const char *proto, const char *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 char *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 int
@@ -759,6 +801,30 @@ dns_parse_rr (guint8 *in, union rspamd_reply_element *elt, guint8 **pos, struct
*(elt->txt.data + datalen) = '\0';
}
break;
+ case DNS_T_SPF:
+ if (rep->request->type != DNS_REQUEST_SPF) {
+ p += datalen;
+ }
+ else {
+ elt->spf.data = memory_pool_alloc (rep->request->pool, datalen + 1);
+ memcpy (elt->spf.data, p, datalen);
+ *(elt->spf.data + datalen) = '\0';
+ }
+ break;
+ case DNS_T_SRV:
+ if (rep->request->type != DNS_REQUEST_SRV) {
+ p += datalen;
+ }
+ else {
+ GET16 (elt->srv.priority);
+ GET16 (elt->srv.weight);
+ GET16 (elt->srv.port);
+ if (! dns_parse_labels (in, &elt->srv.target, &p, rep, remain, TRUE)) {
+ msg_info ("invalid labels in SRV record");
+ return FALSE;
+ }
+ }
+ break;
default:
msg_info ("unexpected RR type: %d", type);
}
@@ -811,7 +877,7 @@ dns_parse_reply (guint8 *in, int r, struct rspamd_dns_resolver *resolver)
rep->request = req;
rep->type = req->type;
rep->elements = NULL;
- rep->code = ntohs (header->rcode);
+ rep->code = header->rcode;
r -= pos - in;
/* Extract RR records */
@@ -839,14 +905,13 @@ dns_read_cb (int fd, short what, void *arg)
/* First read packet from socket */
r = read (fd, in, sizeof (in));
- if (r > 96) {
+ if (r > sizeof (struct dns_header) + sizeof (struct dns_query)) {
if ((rep = dns_parse_reply (in, r, resolver)) != NULL) {
rep->request->func (rep, rep->request->arg);
- upstream_ok (&rep->request->server->up, time (NULL));
+ upstream_ok (&rep->request->server->up, rep->request->time);
return;
}
}
-
}
static void
@@ -865,6 +930,7 @@ dns_timer_cb (int fd, short what, void *arg)
rep->request = req;
rep->code = DNS_RC_SERVFAIL;
req->func (rep, req->arg);
+ upstream_fail (&rep->request->server->up, rep->request->time);
return;
}
/* Select other server */
@@ -891,6 +957,7 @@ dns_timer_cb (int fd, short what, void *arg)
rep->request = req;
rep->code = DNS_RC_SERVFAIL;
req->func (rep, req->arg);
+ upstream_fail (&rep->request->server->up, rep->request->time);
return;
}
/* Add other retransmit event */
@@ -903,7 +970,7 @@ dns_timer_cb (int fd, short what, void *arg)
rep->request = req;
rep->code = DNS_RC_SERVFAIL;
req->func (rep, req->arg);
- upstream_fail (&req->server->up, time (NULL));
+ upstream_fail (&rep->request->server->up, rep->request->time);
}
}
@@ -924,6 +991,7 @@ dns_retransmit_handler (int fd, short what, void *arg)
rep->request = req;
rep->code = DNS_RC_SERVFAIL;
req->func (rep, req->arg);
+ upstream_fail (&rep->request->server->up, rep->request->time);
return;
}
r = send_dns_request (req);
@@ -933,7 +1001,7 @@ dns_retransmit_handler (int fd, short what, void *arg)
rep->request = req;
rep->code = DNS_RC_SERVFAIL;
req->func (rep, req->arg);
- upstream_fail (&req->server->up, time (NULL));
+ upstream_fail (&rep->request->server->up, rep->request->time);
}
else if (r == 1) {
/* Add timer event */
@@ -955,7 +1023,7 @@ make_dns_request (struct rspamd_dns_resolver *resolver,
va_list args;
struct rspamd_dns_request *req;
struct in_addr addr;
- const char *name;
+ const char *name, *service, *proto;
gint r;
req = memory_pool_alloc (pool, sizeof (struct rspamd_dns_request));
@@ -984,6 +1052,16 @@ make_dns_request (struct rspamd_dns_resolver *resolver,
name = va_arg (args, const char *);
make_txt_req (req, name);
break;
+ case DNS_REQUEST_SPF:
+ name = va_arg (args, const char *);
+ make_spf_req (req, name);
+ break;
+ case DNS_REQUEST_SRV:
+ service = va_arg (args, const char *);
+ proto = va_arg (args, const char *);
+ name = va_arg (args, const char *);
+ make_srv_req (req, service, proto, name);
+ break;
}
va_end (args);
@@ -1008,6 +1086,7 @@ make_dns_request (struct rspamd_dns_resolver *resolver,
/* Fill timeout */
req->tv.tv_sec = resolver->request_timeout / 1000;
req->tv.tv_usec = (resolver->request_timeout - req->tv.tv_sec * 1000) * 1000;
+ req->time = time (NULL);
/* Now send request to server */
r = send_dns_request (req);
@@ -1152,3 +1231,30 @@ dns_resolver_init (struct config_file *cfg)
return new;
}
+
+static char dns_rcodes[16][16] = {
+ [DNS_RC_NOERROR] = "NOERROR",
+ [DNS_RC_FORMERR] = "FORMERR",
+ [DNS_RC_SERVFAIL] = "SERVFAIL",
+ [DNS_RC_NXDOMAIN] = "NXDOMAIN",
+ [DNS_RC_NOTIMP] = "NOTIMP",
+ [DNS_RC_REFUSED] = "REFUSED",
+ [DNS_RC_YXDOMAIN] = "YXDOMAIN",
+ [DNS_RC_YXRRSET] = "YXRRSET",
+ [DNS_RC_NXRRSET] = "NXRRSET",
+ [DNS_RC_NOTAUTH] = "NOTAUTH",
+ [DNS_RC_NOTZONE] = "NOTZONE",
+};
+
+const char *
+dns_strerror (enum dns_rcode rcode)
+{
+ rcode &= 0xf;
+ static char numbuf[16];
+
+ if ('\0' == dns_rcodes[rcode][0]) {
+ rspamd_snprintf (numbuf, sizeof (numbuf), "UNKNOWN: %d", (int)rcode);
+ return numbuf;
+ }
+ return dns_rcodes[rcode];
+}
diff --git a/src/dns.h b/src/dns.h
index 7bac41037..338daf033 100644
--- a/src/dns.h
+++ b/src/dns.h
@@ -11,7 +11,7 @@
#define DNS_D_MAXLABEL 63 /* + 1 '\0' */
#define DNS_D_MAXNAME 255 /* + 1 '\0' */
-#define MAX_ADDRS 64
+#define MAX_ADDRS 4
struct rspamd_dns_reply;
struct config_file;
@@ -59,7 +59,9 @@ enum rspamd_request_type {
DNS_REQUEST_A = 0,
DNS_REQUEST_PTR,
DNS_REQUEST_MX,
- DNS_REQUEST_TXT
+ DNS_REQUEST_TXT,
+ DNS_REQUEST_SRV,
+ DNS_REQUEST_SPF
};
struct rspamd_dns_request {
@@ -76,10 +78,12 @@ struct rspamd_dns_request {
struct rspamd_async_session *session;
struct rspamd_dns_reply *reply;
guint8 *packet;
+ const char *requested_name;
off_t pos;
guint packet_len;
int sock;
enum rspamd_request_type type;
+ time_t time;
};
@@ -90,15 +94,24 @@ union rspamd_reply_element {
guint16 addrcount;
} a;
struct {
- char *name;
+ gchar *name;
} ptr;
struct {
- char *name;
- guint32 priority;
+ gchar *name;
+ guint16 priority;
} mx;
struct {
- char *data;
+ gchar *data;
} txt;
+ struct {
+ gchar *data;
+ } spf;
+ struct {
+ guint16 priority;
+ guint16 weight;
+ guint16 port;
+ gchar *target;
+ } srv;
};
enum dns_rcode {
@@ -212,5 +225,6 @@ struct rspamd_dns_resolver *dns_resolver_init (struct config_file *cfg);
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, ...);
+const char *dns_strerror (enum dns_rcode rcode);
#endif
diff --git a/test/rspamd_dns_test.c b/test/rspamd_dns_test.c
index 35b43c9a5..a6ffcc79a 100644
--- a/test/rspamd_dns_test.c
+++ b/test/rspamd_dns_test.c
@@ -14,7 +14,7 @@ test_dns_cb (struct rspamd_dns_reply *reply, gpointer arg)
union rspamd_reply_element *elt;
GList *cur;
- msg_debug ("got reply with code %d", reply->code);
+ msg_debug ("got reply with code %s for request %s", dns_strerror (reply->code), reply->request->requested_name);
if (reply->code == DNS_RC_NOERROR) {
cur = reply->elements;
while (cur) {
@@ -29,6 +29,13 @@ test_dns_cb (struct rspamd_dns_reply *reply, gpointer arg)
case DNS_REQUEST_TXT:
msg_debug ("got txt %s", elt->txt.data);
break;
+ case DNS_REQUEST_SPF:
+ msg_debug ("got spf %s", elt->spf.data);
+ break;
+ case DNS_REQUEST_SRV:
+ msg_debug ("got srv pri:%d, weight:%d, port: %d, target: %s", elt->srv.weight,
+ elt->srv.priority, elt->srv.port, elt->srv.target);
+ break;
case DNS_REQUEST_MX:
msg_debug ("got mx %s:%d", elt->mx.name, elt->mx.priority);
break;
@@ -75,12 +82,16 @@ rspamd_dns_test_func ()
requests ++;
g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_A, "google.com"));
requests ++;
- g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_PTR, "81.19.70.3"));
+ g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_PTR, inet_addr ("81.19.70.3")));
requests ++;
g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_MX, "rambler.ru"));
requests ++;
g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_TXT, "rambler.ru"));
requests ++;
+ g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_SPF, "rambler.ru"));
+ requests ++;
+ g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_SRV, "xmpp-server", "tcp", "jabber.org"));
+ requests ++;
g_assert (make_dns_request (resolver, s, pool, test_dns_cb, NULL, DNS_REQUEST_TXT, "non-existent.arpa"));
g_assert (resolver != NULL);