Move unpack functions into a seperate file.
authorsunil <sunil@openbsd.org>
Sat, 6 Jan 2018 07:57:53 +0000 (07:57 +0000)
committersunil <sunil@openbsd.org>
Sat, 6 Jan 2018 07:57:53 +0000 (07:57 +0000)
Required for upcoming 'smtpctl spf walk'.
Ok eric@ gilles@ millert@

usr.sbin/smtpd/dns.c
usr.sbin/smtpd/smtpd/Makefile
usr.sbin/smtpd/unpack_dns.c [new file with mode: 0644]
usr.sbin/smtpd/unpack_dns.h [new file with mode: 0644]

index 0f12f92..b5c13e6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -39,6 +39,7 @@
 
 #include "smtpd.h"
 #include "log.h"
+#include "unpack_dns.h"
 
 struct dns_lookup {
        struct dns_session      *session;
@@ -61,84 +62,6 @@ static void dns_dispatch_ptr(struct asr_result *, void *);
 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)
 {
@@ -462,268 +385,3 @@ dns_lookup_host(struct dns_session *s, const char *host, int preference)
        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);
-}
index a762141..b193c34 100644 (file)
@@ -1,4 +1,4 @@
-#      $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}/..
 
@@ -14,6 +14,7 @@ SRCS+=        crypto.c
 SRCS+= delivery.c
 SRCS+= dict.c
 SRCS+= dns.c
+SRCS+= unpack_dns.c
 SRCS+= envelope.c
 SRCS+= esc.c
 SRCS+= expand.c
diff --git a/usr.sbin/smtpd/unpack_dns.c b/usr.sbin/smtpd/unpack_dns.c
new file mode 100644 (file)
index 0000000..fe50b02
--- /dev/null
@@ -0,0 +1,295 @@
+/*     $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);
+}
diff --git a/usr.sbin/smtpd/unpack_dns.h b/usr.sbin/smtpd/unpack_dns.h
new file mode 100644 (file)
index 0000000..2318a0c
--- /dev/null
@@ -0,0 +1,96 @@
+/*     $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);
+