diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-10-20 13:23:47 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-10-20 14:35:20 +0300 |
commit | 5cf28509ada303e8995113af9390d10553c60bef (patch) | |
tree | 6ef3c94ee4bf7350f8a3d26331ae4d0c260ccf11 | |
parent | 04a44fafaa2baf0be206a457febca5540b7e3f4a (diff) | |
download | mailfromd-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.ac | 3 | ||||
-rw-r--r-- | lib/dns.c | 850 | ||||
-rw-r--r-- | lib/dns.h | 60 | ||||
-rw-r--r-- | src/builtin/dns.bi | 12 | ||||
-rw-r--r-- | src/spf.c | 26 |
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 @@ -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, @@ -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); @@ -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 |