aboutsummaryrefslogtreecommitdiff
path: root/src/dnsbase.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-02-17 12:56:00 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-02-17 12:56:00 +0000
commitad4e496b8acfbcaf1ba6aabd2ba8b508f196361d (patch)
tree5960b99cbae5352562b8aa1230119f4702241278 /src/dnsbase.c
parent4cb6c6dd32298e583c45c49fce63d452bb903f27 (diff)
downloadmailfromd-ad4e496b8acfbcaf1ba6aabd2ba8b508f196361d.tar.gz
mailfromd-ad4e496b8acfbcaf1ba6aabd2ba8b508f196361d.tar.bz2
Begin implementing SPF support
git-svn-id: file:///svnroot/mailfromd/trunk@1250 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'src/dnsbase.c')
-rw-r--r--src/dnsbase.c789
1 files changed, 789 insertions, 0 deletions
diff --git a/src/dnsbase.c b/src/dnsbase.c
new file mode 100644
index 00000000..49c86f03
--- /dev/null
+++ b/src/dnsbase.c
@@ -0,0 +1,789 @@
+/* This file is part of mailfromd.
+ Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include "mailfrom.h"
+
+struct mx_buffer {
+ unsigned pref;
+ char *name;
+};
+
+static int
+comp_pref(const void *a, const void *b)
+{
+ const struct mx_buffer *ma = a, *mb = b;
+ if (ma->pref > mb->pref)
+ return 1;
+ else if (ma->pref < mb->pref)
+ return -1;
+ return 0;
+}
+
+/* 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(char *host, char *answer, size_t answer_size, mxbuf_t mxbuf,
+ size_t *pcount, unsigned long *pttl)
+{
+ int i, n, nmx;
+ struct mx_buffer mx_buffer[MAXMXCOUNT];
+ HEADER *hp;
+ unsigned char *eom, *cp;
+ unsigned short qdcount, ancount;
+ struct __res_state stat;
+
+ debug1(80,"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) {
+ debug2(10, "res_nquery failed (errno=%s, h_errno=%d)",
+ mu_strerror(errno), h_errno);
+ switch (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, 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;
+
+ /* 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];
+ unsigned long ttl;
+
+ if ((n = dn_expand((unsigned char *)answer,
+ eom, cp, tname, sizeof tname)) < 0)
+ break;
+ cp += n;
+ GETSHORT(type, cp);
+ cp += INT16SZ;
+ GETLONG(ttl, cp);
+ if (*pttl > ttl)
+ *pttl = ttl;
+ GETSHORT(n, cp);
+ if (type != T_MX) {
+ debug2(90,"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;
+ mx_buffer[nmx].pref = pref;
+ mx_buffer[nmx].name = strdup(tname);
+ debug2(20,"MX %u %s", mx_buffer[nmx].pref,
+ mx_buffer[nmx].name);
+ if (++nmx >= MAXMXCOUNT)
+ break;
+ }
+
+ /* Sort according to preference value */
+ qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref);
+
+ /* Prepare return value */
+ memset(mxbuf, 0, sizeof(mxbuf_t));
+ for (i = 0; i < nmx; i++)
+ mxbuf[i] = mx_buffer[i].name;
+ *pcount = nmx;
+ return dns_success;
+}
+
+int
+dns_str_is_ipv4(char *addr)
+{
+ int dot_count;
+ int digit_count;
+
+ dot_count = 0;
+ digit_count = 0;
+ while (*addr != 0 && *addr != ' ') {
+ if (*addr == '.') {
+ if (++dot_count > 3)
+ break;
+ digit_count = 0;
+ } else if (!(isdigit(*addr) && ++digit_count <= 3)) {
+ return 0;
+ }
+ addr++;
+ }
+
+ return dot_count == 3;
+}
+
+MUTEX_DCL(dns_mutex)
+
+/* 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
+ MAXDEPTH */
+dns_status
+dns_get_mx_records(char *host, int maxdepth, mxbuf_t mxbuf, size_t *mxcount,
+ unsigned long *ttl)
+{
+ char *hbuf = NULL;
+ dns_status status = dns_failure;
+
+ MUTEX_LOCK(dns_mutex);
+ if (dns_str_is_ipv4(host)) {
+ status = resolve_ipstr(host, &hbuf);
+ if (status != dns_success)
+ host = NULL;
+ }
+
+ if (host) {
+ unsigned char *answer = malloc(MAXPACKET);
+ if (!answer)
+ status = dns_failure;
+ else {
+ char *p;
+ int depth;
+
+ for (p = host, depth = 0; p && depth < maxdepth;
+ p++, depth++) {
+ *ttl = ~(unsigned long)0;
+ status = _getmx(p, answer, MAXPACKET, mxbuf,
+ mxcount, ttl);
+ if (status == dns_success
+ || status == dns_temp_failure)
+ break;
+ p = strchr(p, '.');
+ if (!p)
+ break;
+ }
+ free(answer);
+ }
+ }
+ MUTEX_UNLOCK(dns_mutex);
+ free(hbuf);
+ return status;
+}
+
+void
+dns_freemx(mxbuf_t mxbuf)
+{
+ int i;
+ for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++)
+ free(mxbuf[i]);
+}
+
+#define LOOKUP_FAILURE -1
+#define LOOKUP_SUCCESS 0
+#define LOOKUP_CNAME 1
+
+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 */
+ char *answer; /* Answer buffer */
+ size_t answer_size; /* Size of answer buffer */
+
+ /* Return data: */
+ char *hbuf; /* Return buffer */
+ size_t hbsize; /* Size of return buffer */
+ size_t hbcount; /* ?? */
+
+ time_t ttl; /* TTL value */
+ 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 */
+};
+
+#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)
+ if (c = *ptr++ - *name++)
+ return c;
+ if (*domain && *ptr != '.')
+ return *ptr - *domain;
+ ptr++;
+ while (*domain)
+ if (c = *ptr++ - *domain++)
+ return c;
+ 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) {
+ debug2(10, "res_nquerydomain failed (errno=%s, h_errno=%d)",
+ mu_strerror(errno), h_errno);
+ switch (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, 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;
+ unsigned long ttl = ~(unsigned long)0;
+ 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 */
+ GETLONG(ttl, cp);
+ if (lp->ttl > ttl)
+ lp->ttl = 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) {
+ debug1(1, "size (%d) too big", n);
+ } else {
+ if (n != sizeof(GACOPYZ_UINT32_T)) {
+ debug1(1,
+ "unsupported address size: %d",
+ n);
+ } else if (lp->hbcount * sizeof(GACOPYZ_UINT32_T) >= lp->hbsize)
+ debug(1, "Too many addresses");
+ else {
+ memmove((GACOPYZ_UINT32_T *)
+ lp->hbuf + lp->hbcount,
+ cp, n);
+ lp->hbcount++;
+ }
+ }
+ 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;
+ }
+ l = strlen(nbuf);
+ if (lp->hbcount + l >= lp->hbsize)
+ l = lp->hbsize - lp->hbcount - 1;
+ memcpy(lp->hbuf + lp->hbcount, nbuf, l);
+ lp->hbcount += l;
+ lp->hbuf[lp->hbcount++] = 0;
+ lp->atype = T_PTR;
+ SET_STATUS(lp, dns_success);
+ break;
+
+ case T_TXT:
+ if (lp->atype != T_ANY && lp->atype != type)
+ continue;
+ l = cp[0];
+ if (lp->hbcount + l >= lp->hbsize)
+ l = lp->hbsize - lp->hbcount - 1;
+ memcpy(lp->hbuf + lp->hbcount, cp + 1, l);
+ lp->hbcount += l;
+ lp->hbuf[lp->hbcount++] = 0;
+ 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);
+ if (!lp->answer) {
+ static unsigned char *answer;
+ if (!answer)
+ answer = xmalloc(MAXPACKET);
+ lp->answer = answer;
+ lp->answer_size = MAXPACKET;
+ }
+ while (cname_loop_body(lp) == LOOKUP_CNAME)
+ ;
+ MUTEX_UNLOCK(dns_mutex);
+}
+
+typedef char IPBUF[3*4+3+1];
+
+int
+dns_reverse_ipstr(const char *ipstr, char *revipstr)
+{
+ int i;
+ const char *p;
+ char *q;
+
+ q = revipstr + strlen(ipstr);
+ *q = 0;
+ for (i = 0, p = ipstr; *p && i < 4; i++) {
+ int len;
+
+ for (len = 0; p[len] && p[len] != '.'; len++)
+ ;
+ q -= len;
+ memcpy(q, p, len);
+ if (q > revipstr)
+ *--q = '.';
+ p += len;
+ if (*p == '.')
+ p++;
+ }
+
+ return *p || i != 4;
+}
+
+dns_status
+dns_resolve_ipstr(const char *ipstr, const char *domain,
+ char *answer, size_t answer_size,
+ char *hbuf, size_t hbsize, unsigned long *ttl)
+{
+ int i;
+ char namebuf[NSIZE];
+ char domainbuf[NSIZE];
+ struct loop_data ld;
+
+ ld.qtype = ld.atype = T_ANY;
+
+ 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;
+ ld.hbuf = hbuf;
+ ld.hbsize = hbsize;
+ ld.hbcount = 0;
+ ld.ttl = ~(unsigned long)0;
+ ld.status = dns_failure;
+ ld.loopcnt = MAXCNAMEDEPTH;
+
+ cnameloop(&ld);
+
+ if (ld.status == dns_success && ld.atype == T_A) {
+ struct in_addr s;
+ char *p;
+ s.s_addr = *(GACOPYZ_UINT32_T*)hbuf;
+ p = inet_ntoa(s);
+ strncpy(hbuf, p, hbsize);
+ }
+
+ *ttl = ld.ttl;
+ return ld.status;
+}
+
+dns_status
+dns_resolve_hostname(char *host, char *answer, size_t answer_size,
+ char *ipbuf, size_t ipbsize, unsigned long *ttl)
+{
+ struct loop_data ld;
+ char domainbuf[256] = "";
+
+ ld.qtype = ld.atype = T_A;
+ ld.name = host;
+ ld.name_size = strlen(host);
+ ld.domain = domainbuf;
+ ld.domain_size = sizeof domainbuf;
+ ld.answer = answer;
+ ld.answer_size = answer_size;
+ ld.hbuf = ipbuf;
+ ld.hbsize = ipbsize;
+ ld.hbcount = 0;
+ ld.ttl = ~(unsigned long)0;
+ ld.status = dns_failure;
+ ld.loopcnt = MAXCNAMEDEPTH;
+
+ cnameloop(&ld);
+
+ if (ld.status == dns_success && ld.atype == T_A) {
+ struct in_addr s;
+ char *p;
+ s.s_addr = *(GACOPYZ_UINT32_T*)ipbuf;
+ p = inet_ntoa(s);
+ strncpy(ipbuf, p, ipbsize);
+ }
+
+ *ttl = ld.ttl;
+ return ld.status;
+}
+
+
+dns_status
+a_lookup(char *host,
+ GACOPYZ_UINT32_T *ipbuf, size_t ipbsize, size_t *ipcount,
+ unsigned long *ttl, char *answer, size_t answer_size)
+{
+ struct loop_data ld;
+ char domainbuf[256] = "";
+
+ ld.qtype = ld.atype = T_A;
+ ld.name = host;
+ ld.name_size = strlen(host);
+ ld.domain = domainbuf;
+ ld.domain_size = sizeof domainbuf;
+ ld.answer = answer;
+ ld.answer_size = answer_size;
+ ld.hbuf = (char*) ipbuf;
+ ld.hbsize = ipbsize * sizeof ipbuf[0];
+ ld.hbcount = 0;
+ ld.ttl = ~(unsigned long)0;
+ ld.status = dns_failure;
+ ld.loopcnt = MAXCNAMEDEPTH;
+
+ cnameloop(&ld);
+
+ if (ld.status == dns_success) {
+ *ipcount = ld.hbcount;
+ if (ttl)
+ *ttl = ld.ttl;
+ }
+ return ld.status;
+}
+
+static void
+textbuf_to_argv(const char *hbuf, size_t hsize, char **argv, size_t argc)
+{
+ size_t i;
+ const char *p;
+
+ for (i = 0, p = hbuf; i < argc - 1 && p < hbuf + hsize;
+ p += strlen(p) + 1)
+ argv[i++] = xstrdup(p);
+ argv[i] = NULL;
+}
+
+dns_status
+ptr_lookup(struct in_addr ip,
+ char **names, size_t maxnames, unsigned long *ttl,
+ char *answer, size_t answer_size)
+{
+ int i;
+ IPBUF ipstr;
+ char namebuf[NSIZE];
+ char domainbuf[NSIZE];
+ char hbuf[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 = answer;
+ ld.answer_size = answer_size;
+ ld.hbuf = hbuf;
+ ld.hbsize = sizeof hbuf;
+ ld.hbcount = 0;
+ ld.ttl = ~(unsigned long)0;
+ ld.status = dns_failure;
+ ld.loopcnt = MAXCNAMEDEPTH;
+
+ cnameloop(&ld);
+
+ if (ld.status == dns_success) {
+ textbuf_to_argv(ld.hbuf, ld.hbcount, names, maxnames);
+ if (ttl)
+ *ttl = ld.ttl;
+ }
+
+ return ld.status;
+}
+
+dns_status
+txt_lookup(char *name,
+ char **names, size_t maxnames, unsigned long *ttl,
+ char *answer, size_t answer_size)
+{
+ int i;
+ IPBUF ipstr;
+ char namebuf[NSIZE];
+ char domainbuf[NSIZE];
+ char hbuf[NSIZE];
+ struct loop_data ld;
+ char *p;
+
+ ld.qtype = T_TXT;
+ ld.atype = T_TXT;
+ ld.name = name;
+ ld.name_size = strlen(name);
+ ld.domain = domainbuf;
+ ld.domain_size = sizeof domainbuf;
+ ld.answer = answer;
+ ld.answer_size = answer_size;
+ ld.hbuf = hbuf;
+ ld.hbsize = sizeof hbuf;
+ ld.hbcount = 0;
+ ld.ttl = ~(unsigned long)0;
+ ld.status = dns_failure;
+ ld.loopcnt = MAXCNAMEDEPTH;
+
+ cnameloop(&ld);
+
+ if (ld.status == dns_success) {
+ textbuf_to_argv(ld.hbuf, ld.hbcount, names, maxnames);
+ if (ttl)
+ *ttl = ld.ttl;
+ }
+
+ return ld.status;
+}
+
+/* FIXME: This is a placeholder for a function that should look up for any SPF or TXT
+ records for DOMAIN. If any SPF are found, TXT should be discarded.
+ For the time being, it handles only TXT */
+dns_status
+spf_lookup(char *domain,
+ char **txt, size_t maxtxt, unsigned long *ttl,
+ char *answer, size_t answer_size)
+{
+ return txt_lookup(domain, txt, maxtxt, ttl, answer, answer_size);
+}
+
+
+/* rfc4408, chapter 5.5 */
+dns_status
+ptr_validate(const char *ipstr, char ***vnptr, size_t *vcount)
+{
+ struct in_addr ip;
+ char *names[11], **p;
+ char *vnames[10];
+ size_t vi = 0;
+ int status;
+
+ if (!inet_aton(ipstr, &ip))
+ return dns_failure;
+
+ status = ptr_lookup(ip, names, NELEMS(names),
+ NULL, NULL, 0);
+ if (status != dns_success)
+ return status;
+
+ for (p = names; *p; p++) {
+ GACOPYZ_UINT32_T ipbuf[10];
+ size_t ipcount;
+ status = a_lookup(*p,
+ ipbuf, NELEMS(ipbuf),
+ &ipcount,
+ NULL, NULL, 0);
+ if (status == dns_success && vi < NELEMS(vnames[0])) {
+ size_t i;
+
+ for (i = 0; i < ipcount; i++)
+ if (ipbuf[i] == ip.s_addr) {
+ vnames[vi++] = *p;
+ if (vnptr)
+ *p = NULL;
+ break;
+ }
+ }
+ free(*p);
+ }
+
+ if (vi > 0 && vnptr) {
+ size_t i;
+
+ *vnptr = xcalloc(vi+1, sizeof vnptr[0]);
+ for (i = 0; i < vi; i++)
+ (*vnptr)[i] = vnames[i];
+ (*vnptr)[i] = NULL;
+ *vcount = vi;
+ }
+ return vi > 0 ? dns_success : dns_not_found;
+}

Return to:

Send suggestions and report system problems to the System administrator.