summaryrefslogtreecommitdiffstats
path: root/rfc1035/rfc1035.c
diff options
context:
space:
mode:
Diffstat (limited to 'rfc1035/rfc1035.c')
-rw-r--r--rfc1035/rfc1035.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/rfc1035/rfc1035.c b/rfc1035/rfc1035.c
new file mode 100644
index 0000000..0e3678b
--- /dev/null
+++ b/rfc1035/rfc1035.c
@@ -0,0 +1,496 @@
+/*
+** Copyright 1998 - 2011 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "config.h"
+#include <stdio.h>
+#include "soxwrap/soxwrap.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+#include <arpa/inet.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "rfc1035.h"
+
+
+#define ISSPACE(c) (strchr(" \t\r\n", (int)(unsigned char)(c)) != NULL)
+
+#if RFC1035_IPV6
+
+#else
+
+struct in_addr rfc1035_addr_any={INADDR_ANY};
+
+#endif
+
+void rfc1035_init_timeout(struct rfc1035_res *res, unsigned s, unsigned n)
+{
+ res->rfc1035_timeout_initial=s;
+ res->rfc1035_timeout_backoff=n;
+}
+
+void rfc1035_init_ns(struct rfc1035_res *res, const RFC1035_ADDR *a, unsigned n)
+{
+unsigned i;
+unsigned j;
+
+ j=0;
+
+ random128_binary(&res->randseed);
+ md5_digest(&res->randseed, sizeof(res->randseed), res->randbuf);
+ res->randptr=0;
+
+ for (i=0; i == 0 || (i<n && i<RFC1035_MAXNS); i++)
+ {
+#if RFC1035_IPV6
+ struct in6_addr sin;
+
+ if (n == 0)
+ sin=in6addr_loopback;
+ else
+ sin=a[(j+i)%n];
+
+#else
+ struct in_addr sin;
+
+ if (n == 0)
+ {
+ rfc1035_aton("127.0.0.1", &sin);
+ }
+ else
+ sin=a[(j+i)%n];
+ memset(&res->nameservers[i], 0, sizeof(res->nameservers[i]));
+ res->nameservers[i]=sin;
+#endif
+ res->nameservers[i]=sin;
+ }
+ res->rfc1035_nnameservers=i;
+
+}
+
+int rfc1035_init_defaultdomain(struct rfc1035_res *res, const char *p)
+{
+char *q;
+
+ if (res->rfc1035_defaultdomain)
+ free(res->rfc1035_defaultdomain);
+
+ if ((res->rfc1035_defaultdomain=malloc(strlen(p)+1)) == 0)
+ return (-1);
+
+ strcpy(res->rfc1035_defaultdomain, p);
+ for (q=res->rfc1035_defaultdomain; *q; q++)
+ if (ISSPACE(*q))
+ {
+ *q=0;
+ break;
+ }
+
+ return (0);
+}
+
+void rfc1035_init_dnssec_enable(struct rfc1035_res *res, int flag)
+{
+ rfc1035_init_edns_payload(res, flag ? 1280:0);
+}
+
+
+void rfc1035_init_edns_payload(struct rfc1035_res *res, int payload_size)
+{
+ res->dnssec_payload_size=payload_size;
+}
+
+static char tl(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+
+ return c;
+}
+
+void rfc1035_init_resolv(struct rfc1035_res *res)
+{
+FILE *fp=fopen("/etc/resolv.conf", "r");
+char rfc1035_buf[512];
+RFC1035_ADDR ns[RFC1035_MAXNS];
+int nns=0;
+
+ memset(res, 0, sizeof(*res));
+
+ while (fp && fgets(rfc1035_buf, sizeof(rfc1035_buf), fp))
+ {
+ char *p;
+
+ for (p=rfc1035_buf; *p; p++)
+ *p=tl(*p);
+
+ for (p=rfc1035_buf; *p; p++)
+ if (ISSPACE(*p)) break;
+ if (*p) *p++=0;
+
+ if (strcmp(rfc1035_buf, "domain") == 0)
+ {
+ while (p && ISSPACE(*p))
+ ++p;
+ rfc1035_init_defaultdomain(res, p);
+ continue;
+ }
+
+ if (strcmp(rfc1035_buf, "nameserver")) continue;
+ while (*p && ISSPACE(*p)) p++;
+ if (nns < RFC1035_MAXNS)
+ {
+ char *q;
+
+ for (q=p; *q && !ISSPACE(*q); q++)
+ ;
+ *q=0;
+
+ if (rfc1035_aton(p, &ns[nns++]) < 0)
+ --nns;
+ }
+ }
+ if (fp) fclose(fp);
+
+ rfc1035_init_ns(res, ns, nns);
+}
+
+void rfc1035_destroy_resolv(struct rfc1035_res *res)
+{
+ if (res->rfc1035_defaultdomain)
+ {
+ free(res->rfc1035_defaultdomain);
+ }
+}
+
+/************/
+
+struct compresslist {
+ struct compresslist *next;
+ unsigned offset;
+ const char *ptr;
+ } ;
+
+static int mkpacketq(void (*)(const char *, unsigned, void *), void *,
+ unsigned *,
+ const struct rfc1035_query *,
+ unsigned,
+ const char *,
+ struct compresslist *,
+ struct rfc1035_res *);
+
+unsigned rfc1035_next_randid(struct rfc1035_res *res)
+{
+ unsigned i;
+
+ if (res->randptr >= sizeof(res->randbuf))
+ {
+ for (i=0; i<sizeof(res->randseed); i++)
+ if ( ++((unsigned char *)res->randseed)[i])
+ break;
+
+ md5_digest(res->randseed, sizeof(res->randseed),
+ res->randbuf);
+ res->randptr=0;
+ }
+
+ i= ((unsigned)((unsigned char *)res->randbuf)[res->randptr] << 8) |
+ ((unsigned char *)res->randbuf)[res->randptr+1];
+ res->randptr += 2;
+ return i;
+}
+
+int rfc1035_mkquery(struct rfc1035_res *res, /* resolver */
+ unsigned opcode, /* opcode */
+ const struct rfc1035_query *questions,
+ unsigned nquestions,
+ void (*func)(const char *, unsigned, void *), void *arg)
+{
+struct {
+ unsigned char idhi, idlo;
+ unsigned char infohi, infolo;
+ unsigned char qhi, qlo;
+ unsigned char ahi, alo;
+ unsigned char nhi, nlo;
+ unsigned char auhi, aulo;
+ } header;
+unsigned cnt;
+
+ unsigned id=rfc1035_next_randid(res);
+
+ header.idhi= id >> 8;
+ header.idlo= id;
+
+ header.infohi= (opcode << 3) & 0x78;
+
+ if (!res->norecursive)
+ header.infohi |= 1; /* Want a recursive query */
+ header.infolo=0;
+ header.qhi=nquestions >> 8;
+ header.qlo=nquestions;
+ header.ahi=0;
+ header.alo=0;
+ header.nhi=0;
+ header.nlo=0;
+ header.auhi=0;
+ header.aulo=0;
+
+ if (res->dnssec_payload_size)
+ header.aulo=1;
+
+ (*func)( (const char *)&header, sizeof(header), arg);
+ cnt=sizeof(header);
+ if (nquestions)
+ if (mkpacketq(func, arg, &cnt, questions, nquestions,
+ questions->name, 0, res)) return (-1);
+
+ if (res->dnssec_payload_size)
+ {
+ /* RFC 2671, section 4.3 */
+
+ struct {
+ char opt_root_domain_name;
+ char opt_type_hi;
+ char opt_type_lo;
+ char opt_class_hi;
+ char opt_class_lo;
+ char opt_extendedrcode;
+ char opt_version;
+ char opt_ttl_zhi;
+ char opt_ttl_zlo;
+ char opt_rdlen_hi;
+ char opt_rdlen_lo;
+ } rfc2671_43;
+
+ memset(&rfc2671_43, 0, sizeof(rfc2671_43));
+
+ rfc2671_43.opt_type_lo=RFC1035_TYPE_OPT;
+
+ rfc2671_43.opt_class_hi= res->dnssec_payload_size >> 8;
+ rfc2671_43.opt_class_lo= res->dnssec_payload_size;
+ rfc2671_43.opt_ttl_zhi |= 0x80; /* RFC 3225 */
+
+ (*func)((char *)&rfc2671_43, sizeof(rfc2671_43), arg);
+ }
+
+ return (0);
+}
+
+int rfc1035_hostnamecmp(const char *p, const char *q)
+{
+ while (*p || *q)
+ {
+ if (*p == '.' || *q == '.' )
+ {
+ if ( (*p && *p != '.') || (*q && *q != '.'))
+ return (1);
+ while (*p == '.') ++p;
+ while (*q == '.') ++q;
+ continue;
+ }
+ if (!*p || !*q) return (1);
+ if ( tl(*p) != tl(*q)) return (1);
+ ++p;
+ ++q;
+ }
+ return (0);
+}
+
+static struct compresslist *search(struct compresslist *cp, const char *name)
+{
+ for ( ; cp; cp=cp->next)
+ {
+ if (rfc1035_hostnamecmp(name, cp->ptr) == 0 &&
+ (cp->offset & 0x3FFF) == cp->offset)
+ return (cp);
+ /* Packet compression uses the two high bits */
+ }
+ return (0);
+}
+
+static int mkpacketq_full(void (*)(const char *, unsigned, void *),
+ void *,
+ unsigned *,
+ const struct rfc1035_query *,
+ unsigned,
+ const char *,
+ struct compresslist *, struct rfc1035_res *);
+
+static int mkpacketq(void (*func)(const char *, unsigned, void *), void *arg,
+ unsigned *cnt,
+ const struct rfc1035_query *qp,
+ unsigned nqp,
+ const char *nameptr,
+ struct compresslist *comp_list,
+ struct rfc1035_res *res)
+{
+char *buf;
+int rc;
+
+
+ if (!res->rfc1035_defaultdomain || strchr(nameptr, '.'))
+ return (mkpacketq_full(func, arg, cnt, qp, nqp, nameptr,
+ comp_list, res));
+
+ /* Append default domain */
+
+ if ((buf=malloc(strlen(nameptr)+
+ strlen(res->rfc1035_defaultdomain)+2)) == 0)
+ return (-1);
+
+ strcat(strcat(strcpy(buf, nameptr), "."),
+ res->rfc1035_defaultdomain);
+
+ rc=mkpacketq_full(func, arg, cnt, qp, nqp, buf, comp_list, res);
+ free(buf);
+ return (rc);
+}
+
+static int mkpacketq_full(void (*func)(const char *, unsigned, void *),
+ void *arg,
+ unsigned *cnt,
+ const struct rfc1035_query *qp,
+ unsigned nqp,
+ const char *nameptr,
+ struct compresslist *comp_list,
+ struct rfc1035_res *res)
+{
+unsigned llen;
+struct compresslist *cp;
+
+ while (nameptr && *nameptr == '.')
+ ++nameptr;
+
+ if (!nameptr || !*nameptr)
+ {
+ struct {
+ unsigned char padtail;
+ unsigned char qtypehi, qtypelo;
+ unsigned char qclasshi, qclasslo;
+ } qtail;
+
+ qtail.padtail=0;
+ qtail.qtypehi=qp->qtype >> 8;
+ qtail.qtypelo=qp->qtype;
+ qtail.qclasshi=qp->qclass >> 8;
+ qtail.qclasslo=qp->qclass;
+
+ (*func)((const char *)&qtail, sizeof(qtail), arg);
+ ++qp;
+ --nqp;
+ *cnt += sizeof(qtail);
+ if (nqp)
+ return (mkpacketq(func, arg, cnt,
+ qp, nqp, qp->name, comp_list, res));
+ return (0);
+ }
+
+ for (llen=0; nameptr[llen] && nameptr[llen] != '.'; llen++)
+ ;
+ cp=search(comp_list, nameptr);
+ if (cp)
+ {
+ struct {
+ unsigned char ptrhi, ptrlo;
+ unsigned char qtypehi, qtypelo;
+ unsigned char qclasshi, qclasslo;
+ } qtail;
+
+ qtail.ptrhi= (cp->offset >> 8) | 0xC0;
+ qtail.ptrlo= cp->offset;
+ qtail.qtypehi=qp->qtype >> 8;
+ qtail.qtypelo=qp->qtype;
+ qtail.qclasshi=qp->qclass >> 8;
+ qtail.qclasslo=qp->qclass;
+
+ (*func)( (const char *)&qtail, sizeof(qtail), arg);
+ ++qp;
+ --nqp;
+ *cnt += sizeof(qtail);
+
+ if (nqp)
+ return (mkpacketq(func, arg, cnt,
+ qp, nqp, qp->name, comp_list, res));
+ }
+ else
+ {
+ unsigned n=llen;
+ unsigned char c;
+ struct compresslist newc;
+
+ if (n > 63) return (-1);
+
+ newc.next=comp_list;
+ newc.offset= *cnt;
+ newc.ptr=nameptr;
+
+ c=(unsigned char)n;
+ (*func)((const char *) &c, 1, arg);
+ (*func)( nameptr, c, arg);
+ *cnt += 1+c;
+ return (mkpacketq_full(func, arg, cnt,
+ qp, nqp, nameptr+llen, &newc, res));
+ }
+ return (0);
+}
+
+/*******************************************************/
+
+int rfc1035_wait_reply(int fd, unsigned nsecs)
+{
+fd_set fds;
+struct timeval tv;
+int n;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec=nsecs;
+ tv.tv_usec=0;
+ while ((n=sox_select(fd+1, &fds, 0, 0, &tv)) < 0)
+ {
+ if (errno != EINTR)
+ break;
+ }
+
+ if (n > 0 && FD_ISSET(fd, &fds))
+ return (0);
+ errno=ETIMEDOUT;
+ return (-1);
+}
+
+int rfc1035_wait_query(int fd, unsigned nsecs)
+{
+fd_set fds;
+struct timeval tv;
+int n;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec=nsecs;
+ tv.tv_usec=0;
+ while ((n=sox_select(fd+1, 0, &fds, 0, &tv)) < 0)
+ {
+ if (errno != EINTR)
+ break;
+ }
+
+ if (n > 0 && FD_ISSET(fd, &fds))
+ return (0);
+ errno=ETIMEDOUT;
+ return (-1);
+}