aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-10-20 13:23:47 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2017-10-20 14:35:20 +0300
commit5cf28509ada303e8995113af9390d10553c60bef (patch)
tree6ef3c94ee4bf7350f8a3d26331ae4d0c260ccf11
parent04a44fafaa2baf0be206a457febca5540b7e3f4a (diff)
downloadmailfromd-5cf28509ada303e8995113af9390d10553c60bef.tar.gz
mailfromd-5cf28509ada303e8995113af9390d10553c60bef.tar.bz2
Rewrite base dns functions using adns.
* configure.ac: Require libadns. * lib/dns.c: Rewrite. * lib/dns.h (dns_resolve_ipstr, dns_resolve_hostname): Simplify parameters. (dns_reply): Remove max, last_len, and last_max.
-rw-r--r--configure.ac3
-rw-r--r--lib/dns.c850
-rw-r--r--lib/dns.h60
-rw-r--r--src/builtin/dns.bi12
-rw-r--r--src/spf.c26
5 files changed, 257 insertions, 694 deletions
diff --git a/configure.ac b/configure.ac
index 2dd23baa..b4f785cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -103,6 +103,9 @@ AC_REPLACE_FUNCS(daemon)
# Check for GNU Mailutils
AM_GNU_MAILUTILS([3.3], [all auth dbm sieve], [:])
+AC_CHECK_LIB([adns], [adns_init],,
+ [AC_MSG_ERROR([required library libadns not found])])
+
### Check for Emacs site-lisp directory
AM_PATH_LISPDIR
diff --git a/lib/dns.c b/lib/dns.c
index 7f62a85d..5d428e50 100644
--- a/lib/dns.c
+++ b/lib/dns.c
@@ -22,16 +22,14 @@
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <netdb.h>
-#include <resolv.h>
+#include <adns.h>
#include "libmf.h"
#include "dns.h"
#include "mailutils/alloc.h"
#include "mailutils/argcv.h"
+#include "mailutils/io.h"
+#include "mailutils/stream.h"
struct mx_buffer {
unsigned pref;
@@ -39,140 +37,56 @@ struct mx_buffer {
};
static mu_debug_handle_t debug_handle;
+static adns_state state;
-void
-dnsbase_init()
+static void
+dns_log_cb(adns_state ads, void *logfndata, const char *fmt, va_list al)
{
- if (!debug_handle)
- debug_handle = mu_debug_register_category("dns");
+/* FIXME: Could have used just:
+ mu_diag_vprintf(MU_DIAG_DEBUG, fmt, al);
+ but it will emit \e<N> directives in the middle of the string, which
+ upsets the mailutils' logstream implementation.
+
+ A possible work over would be to use logfndata to select between
+ mu_diag_vprintf,mu_diag_cont_vprintf or appropriate mu_debug_log_
+ call.
+
+ For the time being, a simplified approach is used: */
+ mu_stream_vprintf(mu_strerr, fmt, al);
}
-static int
-comp_pref(const void *a, const void *b)
+void
+dnsbase_init(void)
{
- const struct mx_buffer *ma = a, *mb = b;
- if (ma->pref > mb->pref)
- return 1;
- else if (ma->pref < mb->pref)
- return -1;
- return strcmp(ma->name, mb->name);
+ if (!debug_handle)
+ debug_handle = mu_debug_register_category("dns");
}
-/* Obtain MX records for domain name HOST. Return them in mxbuf, sorted by
- preference in ascending order.
- Notice that we *have* to use old BIND-4-style method, since glibc folks
- in their incredible wiseness have not exported new interface functions
- from libresolve.so. The only way to access them would be to link with
- -lresolve statically.
-
- Let's hope that someday this stupidity will change. */
-
-static dns_status
-_getmx(const char *host, unsigned char *answer, size_t answer_size,
- struct mxbuf *mxbuf)
+void
+dnsbase_real_init(void)
{
- struct mx_buffer *mx_buffer = NULL;
- size_t mx_max = 0;
- size_t nmx = 0;
- int i, n;
- HEADER *hp;
- unsigned char *eom, *cp;
- unsigned short qdcount, ancount;
- struct __res_state stat;
-
- mu_debug(debug_handle, MU_DEBUG_TRACE8,
- ("Getting MX records for %s", host));
- memset((void *)&stat, 0, sizeof(struct __res_state));
- res_ninit(&stat);
- n = res_nquery (&stat, host, C_IN, T_MX, answer, answer_size);
- res_nclose(&stat);
- if (n < 0) {
- mu_debug(debug_handle, MU_DEBUG_TRACE0,
- ("res_nquery failed (errno=%s, h_errno=%d)",
- strerror(errno), stat.res_h_errno));
- switch (stat.res_h_errno) {
- case NO_DATA:
- case NO_RECOVERY:
- case HOST_NOT_FOUND:
- return dns_not_found;
-
- case TRY_AGAIN:
- case -1:
- return dns_temp_failure;
-
- default:
- mu_error(_("res_nquery(%s) failed with unexpected h_errno %d"),
- host, stat.res_h_errno);
- return dns_failure;
- }
- }
-
- if (n > answer_size)
- n = answer_size;
-
- hp = (HEADER*)answer;
- cp = (unsigned char *) answer + HFIXEDSZ;
- eom = (unsigned char *) answer + n;
+ int rc;
+ int flags;
+ mu_debug_level_t lev;
- /* Skip query part */
- for (qdcount = ntohs((unsigned short)hp->qdcount);
- qdcount--;
- cp += n + QFIXEDSZ) {
- if ((n = dn_skipname(cp, eom)) < 0)
- return dns_failure;
- }
-
- ancount = ntohs((unsigned short)hp->ancount);
-
- /* Collect MX records */
- for (i = nmx = 0; i < ancount; i++) {
- unsigned short pref, type;
- char tname[NS_MAXDNAME];
-
- if ((n = dn_expand((unsigned char *)answer,
- eom, cp, tname, sizeof tname)) < 0)
- break;
- cp += n;
- GETSHORT(type, cp);
- cp += INT16SZ;
- cp += INT32SZ;
- GETSHORT(n, cp);
- if (type != T_MX) {
- mu_debug(debug_handle, MU_DEBUG_TRACE8,
- ("unexpected answer type %d, size %d\n",
- type, n));
- cp += n;
- continue;
- }
- GETSHORT(pref, cp);
- if ((n = dn_expand((u_char *)answer, eom, cp,
- tname, sizeof tname)) < 0)
- break;
- cp += n;
- if (nmx == mx_max)
- mx_buffer = mu_2nrealloc(mx_buffer,
- &mx_max,
- sizeof(mx_buffer[0]));
-
- mx_buffer[nmx].pref = pref;
- mx_buffer[nmx].name = mu_strdup(tname);
- mu_debug(debug_handle, MU_DEBUG_TRACE2,
- ("MX %u %s", mx_buffer[nmx].pref,
- mx_buffer[nmx].name));
- nmx++;
+ flags = adns_if_nosigpipe;
+ if (mu_debug_get_category_level(debug_handle, &lev) == 0 && lev)
+ flags |= adns_if_debug;
+ rc = adns_init_logfn(&state, flags, NULL, dns_log_cb, NULL);
+ if (rc) {
+ mu_diag_funcall(MU_DIAG_ERROR, "adns_init", NULL, rc);
+ exit(1);
}
+}
- /* Sort according to preference value */
- qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref);
-
- /* Prepare return value */
- mxbuf_init(mxbuf, nmx);
- for (i = 0; i < nmx; i++)
- mxbuf->mx_buf[i] = mx_buffer[i].name;
- mxbuf->mx_cnt = i;
- free(mx_buffer);
- return dns_success;
+static adns_state
+get_state(void)
+{
+ if (!state)
+ dnsbase_real_init();
+ return state;
}
+
int
dns_str_is_ipv4(const char *addr)
@@ -196,7 +110,40 @@ dns_str_is_ipv4(const char *addr)
return dot_count == 3;
}
-MUTEX_DCL(dns_mutex)
+static int
+errno_to_dns_status(int e)
+{
+ switch (e) {
+ case 0:
+ return dns_success;
+ case EAGAIN:
+#ifdef EINPROGRESS
+ case EINPROGRESS:
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT:
+#endif
+ return dns_temp_failure;
+ default:
+ return dns_failure;
+ }
+}
+
+static int
+adns_to_dns_status(int e)
+{
+ switch (e) {
+ case adns_s_ok:
+ return dns_success;
+ case adns_s_timeout:
+ return dns_temp_failure;
+ case adns_s_nxdomain:
+ case adns_s_nodata:
+ return dns_not_found;
+ default:
+ return dns_failure;
+ }
+}
/* Return MX records for the given HOST. If no records were found, recurse
to its parent domains until any record is found or recursion depth reaches
@@ -204,35 +151,24 @@ MUTEX_DCL(dns_mutex)
dns_status
dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf)
{
- char *hbuf = NULL;
dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+ int i;
- MUTEX_LOCK(dns_mutex);
- if (dns_str_is_ipv4(host)) {
- status = mf_to_dns_status(resolve_ipstr(host, &hbuf));
- if (status != dns_success)
- host = NULL;
- }
-
- if (host) {
- unsigned char *answer = mu_alloc(MAXPACKET);
- const char *p;
- int depth;
-
- for (p = host, depth = 0; p && depth < maxdepth;
- p++, depth++) {
- status = _getmx(p, answer, MAXPACKET, mxbuf);
- if (status == dns_success
- || status == dns_temp_failure)
- break;
- p = strchr(p, '.');
- if (!p)
- break;
- }
- free(answer);
- }
- MUTEX_UNLOCK(dns_mutex);
- free(hbuf);
+ rc = adns_synchronous(get_state(), host, adns_r_mx,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status != dns_success)
+ return status;
+ mxbuf_init(mxbuf, ans->nrrs);
+ for (i = 0; i < ans->nrrs; i++)
+ mxbuf->mx_buf[i] = mu_strdup(ans->rrs.inthostaddr[i].ha.host);
+ mxbuf->mx_cnt = i;
+ free(ans);
return status;
}
@@ -275,319 +211,23 @@ mxbuf_free(struct mxbuf *mxbuf)
}
}
-#define LOOKUP_FAILURE -1
-#define LOOKUP_SUCCESS 0
-#define LOOKUP_CNAME 1
-
void
dns_reply_free(struct dns_reply *r)
{
- if (r->base) {
- size_t i;
- for (i = 0; i < r->count; i++)
- free(r->base[i]);
- free(r->base);
- }
-}
-
-static void
-dns_reply_append(struct dns_reply *r, void *ptr, size_t len, int last)
-{
- if (r->count == r->max)
- r->base = mu_2nrealloc(r->base,
- &r->max,
- sizeof(r->base[0]));
- if (last && r->count) {
- while (r->last_len + len > r->last_max)
- r->base[r->count-1] =
- mu_2nrealloc(r->base[r->count-1],
- &r->last_max,
- 1);
- } else if (ptr == NULL) {
- r->base[r->count] = NULL;
- return;
- } else {
- r->base[r->count] = mu_alloc(len);
- r->count++;
- r->last_len = 0;
- r->last_max = len;
- }
-
- memcpy((char*)r->base[r->count-1] + r->last_len, ptr, len);
- r->last_len += len;
-}
-
-struct loop_data {
- int qtype; /* Type of the query */
- char *name; /* Key to look up */
- size_t name_size; /* Length of the key */
- char *domain; /* Domain name */
- size_t domain_size; /* Length of the domain name */
- unsigned char *answer; /* Answer buffer */
- size_t answer_size; /* Size of answer buffer */
-
- /* Return data: */
- struct dns_reply repl;
-
- dns_status status; /* Status */
- int atype; /* On input: desired answer type or T_ANY
- On output: Answer type */
-
- /* Internal data */
- size_t loopcnt; /* Number of CNAME loops allowed */
-};
-
-#ifndef MAX
-# define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
-#define NSIZE MAX(MAXPACKET, MAXDNAME*2+2)
-#define SET_STATUS(lp,s) if ((lp)->status != dns_success) (lp)->status = s
-
-typedef struct {
- GACOPYZ_UINT32_T x;
- char a;
-} align;
-
-static int
-domain_name_cmp(const char *ptr, const char *name, const char *domain)
-{
- int c;
- while (*name && *ptr)
- if (c = tolower(*ptr++) - tolower(*name++))
- return c;
- if (*domain) {
- if (*ptr != '.')
- return tolower(*ptr) - tolower(*domain);
- ptr++;
- while (*domain && *ptr)
- if (c = tolower(*ptr++) - tolower(*domain++))
- return c;
- if (*domain == '.' && domain[1] == 0)
- domain++;
- if (*ptr == '.' && ptr[1] == 0)
- ptr++;
- if (*domain || *ptr)
- return 1;
- }
- return 0;
-}
-
-static int
-cname_loop_body(struct loop_data *lp)
-{
- int i, n, rc;
- HEADER *hp;
- unsigned char *eom, *cp;
- unsigned short qdcount, ancount;
- char *p;
- size_t len;
- struct __res_state statb;
-
- memset((void *)&statb, 0, sizeof(struct __res_state));
- res_ninit(&statb);
- n = res_nquerydomain (&statb, lp->name, lp->domain, C_IN, lp->qtype,
- lp->answer, lp->answer_size);
- res_nclose(&statb);
- if (n < 0) {
- mu_debug(debug_handle, MU_DEBUG_TRACE0,
- ("res_nquerydomain failed (errno=%s, h_errno=%d)",
- strerror(errno), statb.res_h_errno));
- switch (statb.res_h_errno) {
- case NO_DATA:
- case NO_RECOVERY:
- case HOST_NOT_FOUND:
- SET_STATUS(lp, dns_not_found);
- return LOOKUP_FAILURE;
-
- case TRY_AGAIN:
- case -1:
- SET_STATUS(lp, dns_temp_failure);
- return LOOKUP_FAILURE;
-
- default:
- mu_error(_("res_nquerydomain(%s) failed with unexpected h_errno %d"),
- lp->name, statb.res_h_errno);
- SET_STATUS(lp, dns_failure);
- return LOOKUP_FAILURE;
- }
- }
-
- if (n > lp->answer_size)
- n = lp->answer_size;
-
- hp = (HEADER*) lp->answer;
- cp = (unsigned char *) lp->answer + HFIXEDSZ;
- eom = (unsigned char *) lp->answer + n;
-
- /* Skip query part */
- for (qdcount = ntohs((unsigned short)hp->qdcount);
- qdcount--;
- cp += n + QFIXEDSZ) {
- if ((n = dn_skipname(cp, eom)) < 0) {
- SET_STATUS(lp, dns_failure);
- return LOOKUP_FAILURE;
- }
- }
-
- SET_STATUS(lp, dns_not_found);
-
- for (ancount = ntohs((unsigned short) hp->ancount), i = 0;
- i < ancount && cp < eom;
- cp += n, i++) {
- unsigned short type;
- char nbuf[NSIZE];
- char *bp = nbuf;
- size_t blen = sizeof nbuf;
- size_t l;
-
- n = dn_expand((unsigned char *) lp->answer, eom, cp,
- nbuf, sizeof nbuf);
- if (n < 0)
- break;
- cp += n;
- GETSHORT(type, cp);
- cp += INT16SZ; /* skip over class */
- cp += INT32SZ; /* skip over ttl */
- GETSHORT(n, cp); /* rdlength */
-
- switch (type) {
- case T_A:
- if (lp->atype != T_ANY && lp->atype != type)
- continue;
- if (domain_name_cmp(bp, lp->name, lp->domain) != 0)
- continue;
-
- /* Skip host name */
- l = strlen(bp) + 1;
- bp += l;
- blen -= l;
-
- blen -= sizeof(align) - ((u_long)bp % sizeof(align));
- bp += sizeof(align) - ((u_long)bp % sizeof(align));
-
- if (bp + n >= nbuf + blen) {
- mu_debug(debug_handle, MU_DEBUG_TRACE0,
- ("size (%d) too big", n));
- } else if (n != sizeof(GACOPYZ_UINT32_T)) {
- mu_debug(debug_handle, MU_DEBUG_TRACE0,
- ("unsupported address size: %d", n));
- } else {
- dns_reply_append(&lp->repl, cp, n, 0);
- }
- bp += n;
- blen -= n;
- lp->atype = T_A;
- SET_STATUS(lp, dns_success);
- break;
-
- case T_PTR:
- if (lp->atype != T_ANY && lp->atype != type)
- continue;
- if ((rc = dn_expand((unsigned char *)lp->answer,
- eom, cp,
- nbuf, sizeof(nbuf))) < 0) {
- SET_STATUS(lp, dns_failure);
- return LOOKUP_FAILURE;
- }
- dns_reply_append(&lp->repl, nbuf, strlen(nbuf) + 1, 0);
- lp->atype = T_PTR;
- SET_STATUS(lp, dns_success);
- break;
-
- case T_TXT:
- if (lp->atype != type)
- continue;
- else {
- unsigned char *cur, *end;
- int i = 0;
-
- cur = cp;
- end = cp + n;
- while (cur < end) {
- l = *cur++;
- dns_reply_append(&lp->repl,
- cur, l,
- i > 0);
- cur += l;
- i++;
- }
- dns_reply_append(&lp->repl, "", 1, 1);
- lp->atype = T_TXT;
- SET_STATUS(lp, dns_success);
- }
- break;
-
- case T_CNAME:
- if (--lp->loopcnt == 0) {
- mu_error(_("DNS failure: CNAME loop for %s"),
- lp->name);
- SET_STATUS(lp, dns_failure);
- return LOOKUP_FAILURE;
- }
-
- if ((rc = dn_expand((unsigned char *)lp->answer,
- eom, cp,
- nbuf, sizeof(nbuf))) < 0) {
- SET_STATUS(lp, dns_failure);
- return LOOKUP_FAILURE;
- }
-
- /* RFC 1034 section 3.6 specifies that CNAME
- should point at the canonical name -- but
- urges software to try again anyway.
- */
- p = strchr (nbuf, '.');
- if (!p)
- return LOOKUP_SUCCESS;
- len = p - nbuf;
- if (len + 1 >= lp->name_size)
- return LOOKUP_FAILURE;
- memcpy(lp->name, nbuf, len);
- lp->name[len] = 0;
- len = strlen (p + 1);
- if (len + 1 >= lp->domain_size)
- return LOOKUP_FAILURE;
- strcpy(lp->domain, p + 1);
- return LOOKUP_CNAME;
- }
- }
-
- return lp->status == dns_success ? LOOKUP_SUCCESS : LOOKUP_FAILURE;
-}
-
-static void
-cnameloop(struct loop_data *lp)
-{
- MUTEX_LOCK(dns_mutex);
-
- lp->repl.base = NULL;
- lp->repl.max = 0;
- lp->repl.count = 0;
- lp->status = dns_failure;
- lp->loopcnt = MAXCNAMEDEPTH;
+ int i;
- if (!lp->answer) {
- static unsigned char *answer;
- if (!answer)
- answer = mu_alloc(MAXPACKET);
- lp->answer = answer;
- lp->answer_size = MAXPACKET;
- }
-
- if (lp->domain[0] == 0) {
- if (lp->name_size == 0) {
- lp->status = dns_not_found;
- return;
- }
- if (lp->name[lp->name_size - 1] == '.')
- lp->name[--lp->name_size] = 0;
+ switch (r->type) {
+ case dns_reply_str:
+ for (i = 0; i < r->count; i++)
+ free(r->data.str[i]);
+ free(r->data.str);
+ break;
+ case dns_reply_ip:
+ free(r->data.ip);
+ break;
}
-
- while (cname_loop_body(lp) == LOOKUP_CNAME)
- ;
- MUTEX_UNLOCK(dns_mutex);
-}
-
+}
+
typedef char IPBUF[3*4+3+1];
int
@@ -617,178 +257,162 @@ dns_reverse_ipstr(const char *ipstr, char *revipstr)
}
dns_status
-dns_resolve_ipstr(const char *ipstr, const char *domain,
- unsigned char *answer, size_t answer_size,
- char **hbuf)
+dns_resolve_ipstr(const char *ipstr, const char *domain, char **hbuf)
{
- char namebuf[NSIZE];
- char domainbuf[NSIZE];
- struct loop_data ld;
-
- ld.qtype = ld.atype = T_ANY;
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+ char *name;
+ if (!dns_str_is_ipv4(ipstr))
+ return dns_failure;
if (!domain) {
- if (dns_reverse_ipstr(ipstr, namebuf))
- return dns_failure;
-
- ld.name = namebuf;
- ld.name_size = sizeof namebuf;
- } else {
- strncpy(namebuf, ipstr, sizeof(namebuf)-1);
- namebuf[sizeof(namebuf)-1] = 0;
- ld.name = namebuf;
- ld.name_size = strlen(ld.name);
- }
-
- ld.domain = domainbuf;
- strcpy(domainbuf, domain ? domain : "in-addr.arpa");
- ld.domain_size = sizeof domainbuf;
- ld.answer = answer;
- ld.answer_size = answer_size;
-
- cnameloop(&ld);
-
- if (ld.status == dns_success) {
- if (ld.atype == T_A) {
- struct in_addr s;
- s.s_addr = *(GACOPYZ_UINT32_T*)ld.repl.base[0];
- *hbuf = mu_strdup(inet_ntoa(s));
- } else if (ld.atype == T_PTR) {
- *hbuf = mu_strdup(ld.repl.base[0]);
- } else
- abort();
- dns_reply_free(&ld.repl);
- }
+ IPBUF ipbuf;
+ if (dns_reverse_ipstr(ipstr, ipbuf))
+ return dns_failure;
+ mu_asprintf(&name, "%s.in-addr.arpa", ipbuf);
+ } else {
+ mu_asprintf(&name, "%s.%s", ipstr, domain);
+ }
- return ld.status;
+ rc = adns_synchronous(get_state(), name, adns_r_ptr,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ free(name);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success)
+ *hbuf = mu_strdup(ans->rrs.str[0]);
+ free(ans);
+ return status;
}
dns_status
-dns_resolve_hostname(const char *host,
- unsigned char *answer, size_t answer_size,
- char **ipbuf)
+dns_resolve_hostname(const char *host, char **ipbuf)
{
- struct loop_data ld;
- char namebuf[NSIZE];
- char domainbuf[NSIZE];
-
- domainbuf[0] = 0;
- ld.qtype = ld.atype = T_A;
-
- strncpy(namebuf, host, sizeof namebuf - 1);
- ld.name = namebuf;
- ld.name_size = sizeof namebuf;
- ld.domain = domainbuf;
- ld.domain_size = sizeof domainbuf;
- ld.answer = answer;
- ld.answer_size = answer_size;
-
- cnameloop(&ld);
-
- if (ld.status == dns_success && ld.atype == T_A) {
- struct in_addr s;
- s.s_addr = *(GACOPYZ_UINT32_T*)ld.repl.base[0];
- *ipbuf = mu_strdup(inet_ntoa(s));
- dns_reply_free(&ld.repl);
- }
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
- return ld.status;
+ rc = adns_synchronous(get_state(), host, adns_r_a,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success)
+ *ipbuf = mu_strdup(inet_ntoa(ans->rrs.inaddr[0]));
+ free(ans);
+ return status;
}
-
+
dns_status
a_lookup(const char *host, struct dns_reply *repl)
{
- struct loop_data ld;
- char namebuf[NSIZE];
- char domainbuf[NSIZE];
-
- domainbuf[0] = 0;
- ld.qtype = ld.atype = T_A;
- strncpy(namebuf, host, sizeof namebuf - 1);
- ld.name = namebuf;
- ld.name_size = sizeof namebuf;
- ld.domain = domainbuf;
- ld.domain_size = sizeof domainbuf;
- ld.answer = NULL;
- ld.answer_size = 0;
-
- cnameloop(&ld);
- if (ld.status == dns_success) {
- *repl = ld.repl;
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+
+ rc = adns_synchronous(get_state(), host, adns_r_a,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success) {
+ int i;
+ repl->type = dns_reply_ip;
+ repl->count = ans->nrrs;
+ repl->data.ip = mu_calloc(repl->count,
+ sizeof(repl->data.ip[0]));
+ for (i = 0; i < ans->nrrs; i++)
+ repl->data.ip[i] = ans->rrs.inaddr[i].s_addr;
}
- return ld.status;
+ free(ans);
+ return status;
}
dns_status
ptr_lookup(struct in_addr ip, struct dns_reply *repl)
{
- char namebuf[NSIZE];
- char domainbuf[NSIZE];
- struct loop_data ld;
- char *p;
-
- ip.s_addr = ntohl(ip.s_addr);
- p = inet_ntoa(ip);
- strncpy(namebuf, p, sizeof namebuf);
-
- ld.qtype = ld.atype = T_PTR;
- ld.name = namebuf;
- ld.name_size = sizeof namebuf;
- ld.domain = domainbuf;
- strcpy(domainbuf, "in-addr.arpa");
- ld.domain_size = sizeof domainbuf;
- ld.answer = NULL;
- ld.answer_size = 0;
-
- cnameloop(&ld);
-
- if (ld.status == dns_success) {
- *repl = ld.repl;
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+ char *name;
+
+ mu_asprintf(&name, "%s.in-addr.arpa", inet_ntoa(ip));
+ rc = adns_synchronous(get_state(), name, adns_r_ptr,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ free(name);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success) {
+ int i;
+ repl->type = dns_reply_str;
+ repl->count = ans->nrrs;
+ repl->data.str = mu_calloc(repl->count,
+ sizeof(repl->data.str[0]));
+ for (i = 0; i < ans->nrrs; i++)
+ repl->data.str[i] = mu_strdup(ans->rrs.str[i]);
}
-
- return ld.status;
+ free(ans);
+ return status;
}
dns_status
txt_lookup(const char *name, struct dns_reply *repl)
{
- char domainbuf[NSIZE];
- struct loop_data ld;
-
- ld.qtype = T_TXT;
- ld.atype = T_TXT;
- ld.name = mu_strdup(name);
- ld.name_size = strlen(ld.name);
- domainbuf[0] = 0;
- ld.domain = domainbuf;
- ld.domain_size = sizeof domainbuf;
- ld.answer = NULL;
- ld.answer_size = 0;
-
- cnameloop(&ld);
-
- free(ld.name);
-
- if (ld.status == dns_success) {
- *repl = ld.repl;
+ dns_status status = dns_failure;
+ int rc;
+ adns_answer *ans;
+
+ rc = adns_synchronous(get_state(), name, adns_r_txt,
+ adns_qf_quoteok_cname|adns_qf_cname_loose,
+ &ans);
+ if (rc)
+ return errno_to_dns_status(rc);
+ status = adns_to_dns_status(ans->status);
+ if (status == dns_success) {
+ int i;
+ repl->type = dns_reply_str;
+ repl->count = ans->nrrs;
+ repl->data.str = mu_calloc(repl->count,
+ sizeof(repl->data.str[0]));
+ for (i = 0; i < ans->nrrs; i++)
+ repl->data.str[i] = mu_strdup(ans->rrs.manyistr[i]->str);
}
-
- return ld.status;
+ free(ans);
+ return status;
}
dns_status
-spf_lookup(const char *domain, char ***txtv, size_t *txtc)
+spf_lookup(const char *domain, char **rec)
{
- dns_status res;
+ dns_status status;
struct dns_reply r;
- res = txt_lookup(domain, &r);
- if (res == dns_success) {
- *txtv = (char**)r.base;
- if (txtc)
- *txtc = r.count;
+
+ status = txt_lookup(domain, &r);
+ if (status == dns_success) {
+ int i;
+
+ status = dns_not_found;
+
+ for (i = 0; i < r.count; i++) {
+ if (memcmp(r.data.str[i], "v=spf1", 6) == 0
+ && (r.data.str[i][6] == 0
+ || mu_isspace(r.data.str[i][6]))) {
+ *rec = mu_strdup(r.data.str[i]);
+ status = dns_success;
+ break;
+ }
+ }
+ dns_reply_free(&r);
}
- return res;
+ return status;
}
/* rfc4408, chapter 5.5 */
@@ -813,16 +437,16 @@ ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount)
for (i = 0; i < ptr_repl.count; i++) {
struct dns_reply r;
- status = a_lookup((char*)ptr_repl.base[i], &r);
+ status = a_lookup(ptr_repl.data.str[i], &r);
if (status == dns_success) {
size_t k;
for (k = 0; k < r.count; k++) {
- if (dns_reply_ip(&r, k) == ip.s_addr) {
+ if (r.data.ip[k] == ip.s_addr) {
if (sc == sn)
sv = mu_2nrealloc(sv, &sn,
sizeof(sv[0]));
- sv[sc++] = mu_strdup(ptr_repl.base[i]);
+ sv[sc++] = mu_strdup(ptr_repl.data.str[i]);
break;
}
}
@@ -887,7 +511,7 @@ getmxip(char *host, GACOPYZ_UINT32_T **pipbuf, size_t *pcount)
if (ipcount == ipmax)
ipbuf = mu_2nrealloc(ipbuf, &ipmax,
sizeof(ipbuf));
- ipbuf[ipcount] = ntohl(dns_reply_ip(&r, n));
+ ipbuf[ipcount] = ntohl(r.data.ip[n]);
}
dns_reply_free(&r);
}
@@ -902,17 +526,13 @@ getmxip(char *host, GACOPYZ_UINT32_T **pipbuf, size_t *pcount)
mf_status
resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf)
{
- static unsigned char *answer;
char *hbuf;
dns_status dstat;
- if (!answer)
- answer = mu_alloc(MAXPACKET);
mu_debug(debug_handle, MU_DEBUG_TRACE8,
("Getting canonical name for %s", ipstr));
- dstat = dns_resolve_ipstr(ipstr, domain, answer, MAXPACKET,
- &hbuf);
+ dstat = dns_resolve_ipstr(ipstr, domain, &hbuf);
switch (dstat) {
case dns_success:
@@ -937,19 +557,13 @@ resolve_ipstr(const char *ipstr, char **phbuf)
mf_status
resolve_hostname(const char *host, char **pipbuf)
{
- static unsigned char *answer;
char *ipbuf;
- char *tmphost = mu_strdup(host);
dns_status dstat;
- if (!answer)
- answer = mu_alloc(MAXPACKET);
mu_debug(debug_handle, MU_DEBUG_TRACE8,
("Getting IP address for %s", host));
- dstat = dns_resolve_hostname(tmphost, answer, MAXPACKET,
- &ipbuf);
- free(tmphost);
+ dstat = dns_resolve_hostname(host, &ipbuf);
switch (dstat) {
case dns_success:
mu_debug(debug_handle, MU_DEBUG_TRACE8,
diff --git a/lib/dns.h b/lib/dns.h
index 6b204c0a..0b5ca8ec 100644
--- a/lib/dns.h
+++ b/lib/dns.h
@@ -40,39 +40,6 @@ struct mxbuf {
size_t mx_cnt;
};
-#define MAXCNAMEDEPTH 24 /* FIXME */
-
-#ifdef HAVE_PTHREAD
-# define MUTEX_DCL(name) \
- static pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER;
-# define MUTEX_LOCK(name) \
- pthread_mutex_lock(&name)
-# define MUTEX_UNLOCK(name) \
- pthread_mutex_unlock(&name);
-#else
-# define MUTEX_DCL(name)
-# define MUTEX_LOCK(name)
-# define MUTEX_UNLOCK(name)
-#endif
-
-#if !defined res_ninit && !defined HAVE_RES_NINIT
-# define res_ninit(s)
-#endif
-
-#if !defined res_nclose && !defined HAVE_RES_NCLOSE
-# define res_nclose(s)
-#endif
-
-#if !defined res_nquery && !defined HAVE_RES_NQUERY
-# define res_nquery(stat,name,class,type,answer,anslen) \
- res_query(name,class,type,answer,anslen)
-#endif
-
-#if !defined res_nquerydomain && !defined HAVE_RES_NQUERYDOMAIN
-# define res_nquerydomain(stat,name,domain,class,type,answer,anslen) \
- res_querydomain(name,domain,class,type,answer,anslen)
-#endif
-
void mxbuf_init(struct mxbuf *mxbuf, size_t n);
void mxbuf_free(struct mxbuf *mxbuf);
@@ -83,30 +50,27 @@ dns_status dns_get_mx_records(const char *host, int maxdepth,
int dns_reverse_ipstr(const char *ipstr, char *revipstr);
dns_status dns_resolve_ipstr(const char *ipstr, const char *domain,
- unsigned char *answer, size_t answer_size,
char **hbuf);
dns_status dns_resolve_hostname(const char *host,
- unsigned char *answer, size_t answer_size,
char **ipbuf);
+typedef enum {
+ dns_reply_ip,
+ dns_reply_str
+} dns_reply_type;
+
struct dns_reply {
- size_t count;
- size_t max;
-
- void **base;
- size_t last_len;
- size_t last_max;
+ int count;
+ dns_reply_type type;
+ union {
+ char **str;
+ GACOPYZ_UINT32_T *ip;
+ } data;
};
void dns_reply_free(struct dns_reply *r);
-static inline GACOPYZ_UINT32_T
-dns_reply_ip(struct dns_reply const *repl, size_t n)
-{
- return *(GACOPYZ_UINT32_T*)repl->base[n];
-}
-
dns_status a_lookup(const char *host, struct dns_reply *repl);
dns_status ptr_lookup(struct in_addr ip, struct dns_reply *repl);
@@ -114,7 +78,7 @@ dns_status txt_lookup(const char *name, struct dns_reply *repl);
dns_status ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount);
-dns_status spf_lookup(const char *domain, char ***txtv, size_t *txtc);
+dns_status spf_lookup(const char *domain, char **record);
#endif
diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi
index 137cccc8..c23aaf31 100644
--- a/src/builtin/dns.bi
+++ b/src/builtin/dns.bi
@@ -61,8 +61,8 @@ END
static int
ipaddr_cmp(const void *a, const void *b)
{
- GACOPYZ_UINT32_T ipa = ntohl(**(GACOPYZ_UINT32_T**)a);
- GACOPYZ_UINT32_T ipb = ntohl(**(GACOPYZ_UINT32_T**)b);
+ GACOPYZ_UINT32_T ipa = ntohl(*(GACOPYZ_UINT32_T*)a);
+ GACOPYZ_UINT32_T ipb = ntohl(*(GACOPYZ_UINT32_T*)b);
if (ipa < ipb)
return -1;
if (ipa > ipb)
@@ -80,12 +80,12 @@ MF_DEFUN(dns_getaddr, STRING, STRING string)
switch (dnstat) {
case dns_success: {
MF_OBSTACK_BEGIN();
- qsort(r.base, r.count, sizeof r.base[0], ipaddr_cmp);
+ qsort(r.data.ip, r.count, sizeof r.data.ip[0], ipaddr_cmp);
for (i = 0; i < r.count; i++) {
struct in_addr addr;
char *q;
- addr.s_addr = dns_reply_ip(&r, i);
+ addr.s_addr = r.data.ip[i];
q = inet_ntoa(addr);
if (i > 0)
MF_OBSTACK_1GROW(' ');
@@ -125,13 +125,13 @@ MF_DEFUN(dns_getname, STRING, STRING ipstr)
case dns_success: {
size_t i;
- qsort(r.base, r.count, sizeof r.base[0], hostname_cmp);
+ qsort(r.data.str, r.count, sizeof r.data.str[0], hostname_cmp);
MF_OBSTACK_BEGIN();
for (i = 0; i < r.count; i++) {
if (i > 0)
MF_OBSTACK_1GROW(' ');
- MF_OBSTACK_GROW((char*)r.base[i]);
+ MF_OBSTACK_GROW((char*)r.data.str[i]);
}
MF_OBSTACK_1GROW(0);
diff --git a/src/spf.c b/src/spf.c
index edec1d45..05fbd538 100644
--- a/src/spf.c
+++ b/src/spf.c
@@ -641,7 +641,7 @@ mech_a(spf_data *dat, spf_term_arg *arg, unsigned long masklen)
res = spf_term_nomatch;
for (i = 0; i < r.count; i++) {
- if (ntohl(dns_reply_ip(&r, i) & netmask) == addr.s_addr) {
+ if (ntohl(r.data.ip[i] & netmask) == addr.s_addr) {
res = spf_term_match;
break;
}
@@ -807,7 +807,7 @@ mod_exp(spf_data *dat, spf_term_arg *arg, u