Required for upcoming 'smtpctl spf walk'.
Ok eric@ gilles@ millert@
-/* $OpenBSD: dns.c,v 1.84 2017/05/31 04:50:55 deraadt Exp $ */
+/* $OpenBSD: dns.c,v 1.85 2018/01/06 07:57:53 sunil Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
#include "smtpd.h"
#include "log.h"
+#include "unpack_dns.h"
struct dns_lookup {
struct dns_session *session;
static void dns_dispatch_mx(struct asr_result *, void *);
static void dns_dispatch_mx_preference(struct asr_result *, void *);
-struct unpack {
- const char *buf;
- size_t len;
- size_t offset;
- const char *err;
-};
-
-struct dns_header {
- uint16_t id;
- uint16_t flags;
- uint16_t qdcount;
- uint16_t ancount;
- uint16_t nscount;
- uint16_t arcount;
-};
-
-struct dns_query {
- char q_dname[MAXDNAME];
- uint16_t q_type;
- uint16_t q_class;
-};
-
-struct dns_rr {
- char rr_dname[MAXDNAME];
- uint16_t rr_type;
- uint16_t rr_class;
- uint32_t rr_ttl;
- union {
- struct {
- char cname[MAXDNAME];
- } cname;
- struct {
- uint16_t preference;
- char exchange[MAXDNAME];
- } mx;
- struct {
- char nsname[MAXDNAME];
- } ns;
- struct {
- char ptrname[MAXDNAME];
- } ptr;
- struct {
- char mname[MAXDNAME];
- char rname[MAXDNAME];
- uint32_t serial;
- uint32_t refresh;
- uint32_t retry;
- uint32_t expire;
- uint32_t minimum;
- } soa;
- struct {
- struct in_addr addr;
- } in_a;
- struct {
- struct in6_addr addr6;
- } in_aaaa;
- struct {
- uint16_t rdlen;
- const void *rdata;
- } other;
- } rr;
-};
-
-static char *print_dname(const char *, char *, size_t);
-static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
- char *, size_t);
-static int unpack_data(struct unpack *, void *, size_t);
-static int unpack_u16(struct unpack *, uint16_t *);
-static int unpack_u32(struct unpack *, uint32_t *);
-static int unpack_inaddr(struct unpack *, struct in_addr *);
-static int unpack_in6addr(struct unpack *, struct in6_addr *);
-static int unpack_dname(struct unpack *, char *, size_t);
-static void unpack_init(struct unpack *, const char *, size_t);
-static int unpack_header(struct unpack *, struct dns_header *);
-static int unpack_query(struct unpack *, struct dns_query *);
-static int unpack_rr(struct unpack *, struct dns_rr *);
-
-
static int
domainname_is_addr(const char *s, struct sockaddr *sa, socklen_t *sl)
{
as = getaddrinfo_async(host, NULL, &hints, NULL);
event_asr_run(as, dns_dispatch_host, lookup);
}
-
-static char *
-print_dname(const char *_dname, char *buf, size_t max)
-{
- const unsigned char *dname = _dname;
- char *res;
- size_t left, n, count;
-
- if (_dname[0] == 0) {
- (void)strlcpy(buf, ".", max);
- return buf;
- }
-
- res = buf;
- left = max - 1;
- for (n = 0; dname[0] && left; n += dname[0]) {
- count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
- memmove(buf, dname + 1, count);
- dname += dname[0] + 1;
- left -= count;
- buf += count;
- if (left) {
- left -= 1;
- *buf++ = '.';
- }
- }
- buf[0] = 0;
-
- return (res);
-}
-
-static ssize_t
-dname_expand(const unsigned char *data, size_t len, size_t offset,
- size_t *newoffset, char *dst, size_t max)
-{
- size_t n, count, end, ptr, start;
- ssize_t res;
-
- if (offset >= len)
- return (-1);
-
- res = 0;
- end = start = offset;
-
- for (; (n = data[offset]); ) {
- if ((n & 0xc0) == 0xc0) {
- if (offset + 2 > len)
- return (-1);
- ptr = 256 * (n & ~0xc0) + data[offset + 1];
- if (ptr >= start)
- return (-1);
- if (end < offset + 2)
- end = offset + 2;
- offset = start = ptr;
- continue;
- }
- if (offset + n + 1 > len)
- return (-1);
-
- /* copy n + at offset+1 */
- if (dst != NULL && max != 0) {
- count = (max < n + 1) ? (max) : (n + 1);
- memmove(dst, data + offset, count);
- dst += count;
- max -= count;
- }
- res += n + 1;
- offset += n + 1;
- if (end < offset)
- end = offset;
- }
- if (end < offset + 1)
- end = offset + 1;
-
- if (dst != NULL && max != 0)
- dst[0] = 0;
- if (newoffset)
- *newoffset = end;
- return (res + 1);
-}
-
-void
-unpack_init(struct unpack *unpack, const char *buf, size_t len)
-{
- unpack->buf = buf;
- unpack->len = len;
- unpack->offset = 0;
- unpack->err = NULL;
-}
-
-static int
-unpack_data(struct unpack *p, void *data, size_t len)
-{
- if (p->err)
- return (-1);
-
- if (p->len - p->offset < len) {
- p->err = "too short";
- return (-1);
- }
-
- memmove(data, p->buf + p->offset, len);
- p->offset += len;
-
- return (0);
-}
-
-static int
-unpack_u16(struct unpack *p, uint16_t *u16)
-{
- if (unpack_data(p, u16, 2) == -1)
- return (-1);
-
- *u16 = ntohs(*u16);
-
- return (0);
-}
-
-static int
-unpack_u32(struct unpack *p, uint32_t *u32)
-{
- if (unpack_data(p, u32, 4) == -1)
- return (-1);
-
- *u32 = ntohl(*u32);
-
- return (0);
-}
-
-static int
-unpack_inaddr(struct unpack *p, struct in_addr *a)
-{
- return (unpack_data(p, a, 4));
-}
-
-static int
-unpack_in6addr(struct unpack *p, struct in6_addr *a6)
-{
- return (unpack_data(p, a6, 16));
-}
-
-static int
-unpack_dname(struct unpack *p, char *dst, size_t max)
-{
- ssize_t e;
-
- if (p->err)
- return (-1);
-
- e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
- if (e == -1) {
- p->err = "bad domain name";
- return (-1);
- }
- if (e < 0 || e > MAXDNAME) {
- p->err = "domain name too long";
- return (-1);
- }
-
- return (0);
-}
-
-static int
-unpack_header(struct unpack *p, struct dns_header *h)
-{
- if (unpack_data(p, h, HFIXEDSZ) == -1)
- return (-1);
-
- h->flags = ntohs(h->flags);
- h->qdcount = ntohs(h->qdcount);
- h->ancount = ntohs(h->ancount);
- h->nscount = ntohs(h->nscount);
- h->arcount = ntohs(h->arcount);
-
- return (0);
-}
-
-static int
-unpack_query(struct unpack *p, struct dns_query *q)
-{
- unpack_dname(p, q->q_dname, sizeof(q->q_dname));
- unpack_u16(p, &q->q_type);
- unpack_u16(p, &q->q_class);
-
- return (p->err) ? (-1) : (0);
-}
-
-static int
-unpack_rr(struct unpack *p, struct dns_rr *rr)
-{
- uint16_t rdlen;
- size_t save_offset;
-
- unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
- unpack_u16(p, &rr->rr_type);
- unpack_u16(p, &rr->rr_class);
- unpack_u32(p, &rr->rr_ttl);
- unpack_u16(p, &rdlen);
-
- if (p->err)
- return (-1);
-
- if (p->len - p->offset < rdlen) {
- p->err = "too short";
- return (-1);
- }
-
- save_offset = p->offset;
-
- switch (rr->rr_type) {
-
- case T_CNAME:
- unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
- break;
-
- case T_MX:
- unpack_u16(p, &rr->rr.mx.preference);
- unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
- break;
-
- case T_NS:
- unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
- break;
-
- case T_PTR:
- unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
- break;
-
- case T_SOA:
- unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
- unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
- unpack_u32(p, &rr->rr.soa.serial);
- unpack_u32(p, &rr->rr.soa.refresh);
- unpack_u32(p, &rr->rr.soa.retry);
- unpack_u32(p, &rr->rr.soa.expire);
- unpack_u32(p, &rr->rr.soa.minimum);
- break;
-
- case T_A:
- if (rr->rr_class != C_IN)
- goto other;
- unpack_inaddr(p, &rr->rr.in_a.addr);
- break;
-
- case T_AAAA:
- if (rr->rr_class != C_IN)
- goto other;
- unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
- break;
- default:
- other:
- rr->rr.other.rdata = p->buf + p->offset;
- rr->rr.other.rdlen = rdlen;
- p->offset += rdlen;
- }
-
- if (p->err)
- return (-1);
-
- /* make sure that the advertised rdlen is really ok */
- if (p->offset - save_offset != rdlen)
- p->err = "bad dlen";
-
- return (p->err) ? (-1) : (0);
-}
-# $OpenBSD: Makefile,v 1.88 2017/08/13 11:10:31 eric Exp $
+# $OpenBSD: Makefile,v 1.89 2018/01/06 07:57:53 sunil Exp $
.PATH: ${.CURDIR}/..
SRCS+= delivery.c
SRCS+= dict.c
SRCS+= dns.c
+SRCS+= unpack_dns.c
SRCS+= envelope.c
SRCS+= esc.c
SRCS+= expand.c
--- /dev/null
+/* $OpenBSD: unpack_dns.c,v 1.1 2018/01/06 07:57:53 sunil Exp $ */
+
+/*
+ * Copyright (c) 2011-2014 Eric Faurot <eric@faurot.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <arpa/inet.h>
+
+#include <string.h>
+
+#include "unpack_dns.h"
+
+static int unpack_data(struct unpack *, void *, size_t);
+static int unpack_u16(struct unpack *, uint16_t *);
+static int unpack_u32(struct unpack *, uint32_t *);
+static int unpack_inaddr(struct unpack *, struct in_addr *);
+static int unpack_in6addr(struct unpack *, struct in6_addr *);
+static int unpack_dname(struct unpack *, char *, size_t);
+
+void
+unpack_init(struct unpack *unpack, const char *buf, size_t len)
+{
+ unpack->buf = buf;
+ unpack->len = len;
+ unpack->offset = 0;
+ unpack->err = NULL;
+}
+
+int
+unpack_header(struct unpack *p, struct dns_header *h)
+{
+ if (unpack_data(p, h, HFIXEDSZ) == -1)
+ return (-1);
+
+ h->flags = ntohs(h->flags);
+ h->qdcount = ntohs(h->qdcount);
+ h->ancount = ntohs(h->ancount);
+ h->nscount = ntohs(h->nscount);
+ h->arcount = ntohs(h->arcount);
+
+ return (0);
+}
+
+int
+unpack_query(struct unpack *p, struct dns_query *q)
+{
+ unpack_dname(p, q->q_dname, sizeof(q->q_dname));
+ unpack_u16(p, &q->q_type);
+ unpack_u16(p, &q->q_class);
+
+ return (p->err) ? (-1) : (0);
+}
+
+int
+unpack_rr(struct unpack *p, struct dns_rr *rr)
+{
+ uint16_t rdlen;
+ size_t save_offset;
+
+ unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
+ unpack_u16(p, &rr->rr_type);
+ unpack_u16(p, &rr->rr_class);
+ unpack_u32(p, &rr->rr_ttl);
+ unpack_u16(p, &rdlen);
+
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < rdlen) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ save_offset = p->offset;
+
+ switch (rr->rr_type) {
+
+ case T_CNAME:
+ unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
+ break;
+
+ case T_MX:
+ unpack_u16(p, &rr->rr.mx.preference);
+ unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
+ break;
+
+ case T_NS:
+ unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
+ break;
+
+ case T_PTR:
+ unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
+ break;
+
+ case T_SOA:
+ unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
+ unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
+ unpack_u32(p, &rr->rr.soa.serial);
+ unpack_u32(p, &rr->rr.soa.refresh);
+ unpack_u32(p, &rr->rr.soa.retry);
+ unpack_u32(p, &rr->rr.soa.expire);
+ unpack_u32(p, &rr->rr.soa.minimum);
+ break;
+
+ case T_A:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_inaddr(p, &rr->rr.in_a.addr);
+ break;
+
+ case T_AAAA:
+ if (rr->rr_class != C_IN)
+ goto other;
+ unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
+ break;
+ default:
+ other:
+ rr->rr.other.rdata = p->buf + p->offset;
+ rr->rr.other.rdlen = rdlen;
+ p->offset += rdlen;
+ }
+
+ if (p->err)
+ return (-1);
+
+ /* make sure that the advertised rdlen is really ok */
+ if (p->offset - save_offset != rdlen)
+ p->err = "bad dlen";
+
+ return (p->err) ? (-1) : (0);
+}
+
+ssize_t
+dname_expand(const unsigned char *data, size_t len, size_t offset,
+ size_t *newoffset, char *dst, size_t max)
+{
+ size_t n, count, end, ptr, start;
+ ssize_t res;
+
+ if (offset >= len)
+ return (-1);
+
+ res = 0;
+ end = start = offset;
+
+ for (; (n = data[offset]); ) {
+ if ((n & 0xc0) == 0xc0) {
+ if (offset + 2 > len)
+ return (-1);
+ ptr = 256 * (n & ~0xc0) + data[offset + 1];
+ if (ptr >= start)
+ return (-1);
+ if (end < offset + 2)
+ end = offset + 2;
+ offset = start = ptr;
+ continue;
+ }
+ if (offset + n + 1 > len)
+ return (-1);
+
+ /* copy n + at offset+1 */
+ if (dst != NULL && max != 0) {
+ count = (max < n + 1) ? (max) : (n + 1);
+ memmove(dst, data + offset, count);
+ dst += count;
+ max -= count;
+ }
+ res += n + 1;
+ offset += n + 1;
+ if (end < offset)
+ end = offset;
+ }
+ if (end < offset + 1)
+ end = offset + 1;
+
+ if (dst != NULL && max != 0)
+ dst[0] = 0;
+ if (newoffset)
+ *newoffset = end;
+ return (res + 1);
+}
+
+char *
+print_dname(const char *_dname, char *buf, size_t max)
+{
+ const unsigned char *dname = _dname;
+ char *res;
+ size_t left, n, count;
+
+ if (_dname[0] == 0) {
+ (void)strlcpy(buf, ".", max);
+ return buf;
+ }
+
+ res = buf;
+ left = max - 1;
+ for (n = 0; dname[0] && left; n += dname[0]) {
+ count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
+ memmove(buf, dname + 1, count);
+ dname += dname[0] + 1;
+ left -= count;
+ buf += count;
+ if (left) {
+ left -= 1;
+ *buf++ = '.';
+ }
+ }
+ buf[0] = 0;
+
+ return (res);
+}
+
+static int
+unpack_data(struct unpack *p, void *data, size_t len)
+{
+ if (p->err)
+ return (-1);
+
+ if (p->len - p->offset < len) {
+ p->err = "too short";
+ return (-1);
+ }
+
+ memmove(data, p->buf + p->offset, len);
+ p->offset += len;
+
+ return (0);
+}
+
+static int
+unpack_u16(struct unpack *p, uint16_t *u16)
+{
+ if (unpack_data(p, u16, 2) == -1)
+ return (-1);
+
+ *u16 = ntohs(*u16);
+
+ return (0);
+}
+
+static int
+unpack_u32(struct unpack *p, uint32_t *u32)
+{
+ if (unpack_data(p, u32, 4) == -1)
+ return (-1);
+
+ *u32 = ntohl(*u32);
+
+ return (0);
+}
+
+static int
+unpack_inaddr(struct unpack *p, struct in_addr *a)
+{
+ return (unpack_data(p, a, 4));
+}
+
+static int
+unpack_in6addr(struct unpack *p, struct in6_addr *a6)
+{
+ return (unpack_data(p, a6, 16));
+}
+
+static int
+unpack_dname(struct unpack *p, char *dst, size_t max)
+{
+ ssize_t e;
+
+ if (p->err)
+ return (-1);
+
+ e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
+ if (e == -1) {
+ p->err = "bad domain name";
+ return (-1);
+ }
+ if (e < 0 || e > MAXDNAME) {
+ p->err = "domain name too long";
+ return (-1);
+ }
+
+ return (0);
+}
--- /dev/null
+/* $OpenBSD: unpack_dns.h,v 1.1 2018/01/06 07:57:53 sunil Exp $ */
+
+/*
+ * Copyright (c) 2011-2014 Eric Faurot <eric@faurot.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+struct unpack {
+ const char *buf;
+ size_t len;
+ size_t offset;
+ const char *err;
+};
+
+struct dns_header {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+struct dns_query {
+ char q_dname[MAXDNAME];
+ uint16_t q_type;
+ uint16_t q_class;
+};
+
+struct dns_rr {
+ char rr_dname[MAXDNAME];
+ uint16_t rr_type;
+ uint16_t rr_class;
+ uint32_t rr_ttl;
+ union {
+ struct {
+ char cname[MAXDNAME];
+ } cname;
+ struct {
+ uint16_t preference;
+ char exchange[MAXDNAME];
+ } mx;
+ struct {
+ char nsname[MAXDNAME];
+ } ns;
+ struct {
+ char ptrname[MAXDNAME];
+ } ptr;
+ struct {
+ char mname[MAXDNAME];
+ char rname[MAXDNAME];
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+ } soa;
+ struct {
+ struct in_addr addr;
+ } in_a;
+ struct {
+ struct in6_addr addr6;
+ } in_aaaa;
+ struct {
+ uint16_t rdlen;
+ const void *rdata;
+ } other;
+ } rr;
+};
+
+void unpack_init(struct unpack *, const char *, size_t);
+int unpack_header(struct unpack *, struct dns_header *);
+int unpack_rr(struct unpack *, struct dns_rr *);
+int unpack_query(struct unpack *, struct dns_query *);
+char *print_dname(const char *, char *, size_t);
+ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *,
+ char *, size_t);
+