Hi,

For a course work, I wrote a simple DNS lookup utility using only the
native libc.  It`s not yet a complete replacement for dig/host/nslookup,
but I can work to improve it later.
I would like to receive any comments about it.


Follow the diff.

thx,

Mosconi

Index: usr.bin/resolv/Makefile
===================================================================
RCS file: usr.bin/resolv/Makefile
diff -N usr.bin/resolv/Makefile
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ usr.bin/resolv/Makefile    26 Jul 2016 03:45:43 -0000
@@ -0,0 +1,8 @@
+#    $OpenBSD$
+
+PROG=    resolv
+
+CFLAGS+= -Wall -O0 -g
+CFLAGS+= -I. -I${.CURDIR} -I${.CURDIR}/../../lib/libc/asr
+
+.include <bsd.prog.mk>
Index: usr.bin/resolv/resolv.1
===================================================================
RCS file: usr.bin/resolv/resolv.1
diff -N usr.bin/resolv/resolv.1
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ usr.bin/resolv/resolv.1    26 Jul 2016 03:45:43 -0000
@@ -0,0 +1,131 @@
+.\"
+.\" Copyright (c) 2016 Rodrigo Mosconi <[email protected]?
+.\"
+.\" 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.
+.\"
+.\" The following requests are required for all man pages.
+.\"
+.\" Remove `\&' from the line below.
+.Dd $\&Mdocdate$
+.Dt RESOLV 1
+.Os
+.Sh NAME
+.Nm resolv
+.Nd simple DNS lookup utility
+.Sh SYNOPSIS
+.Nm resolv
+.Op Fl c Ar class
+.Op Fl h
+.Op Fl s Ar server
+.Op Fl t Ar type
+.Ar name
+.Sh DESCRIPTION
+.Nm
+is a utility to make DNS queries to convert name into IP/IPv6 address.
+When it is called with no arguments or options,
+.Nm
+will print a synopsis of its command line.
+.Pp
+The options are:
+.Pp
+.Bl -tag -width 10n
+.It Fl c Ar class
+query with class
+.Ar class
+rather than the dafault
+.Ar IN .
+.It Fl h
+print a help.
+.It Fl s Ar server
+query against
+.Ar server
+rather than the default from
+.Pa /etc/resolv.conf .
+.It Fl s Ar type
+query with type
+.Ar type
+rather than the default
+.Ar ANY .
+.El
+.\" The following requests should be uncommented and used where
appropriate.
+.\" .Sh CONTEXT
+.\" For section 9 functions only.
+.\" .Sh RETURN VALUES
+.\" For sections 2, 3, and 9 function return values only.
+.Sh ENVIRONMENT
+.Bl -tag -width NAMESERVER
+.It Ev NAMESERVER
+If the environment variable
+.Ev NAMESERVER
+is set, and the
+.Fl s
+option is not specified,
+.Nm
+will query against that server.
+.El
+.\" For sections 1, 6, 7, and 8 only.
+.Sh FILES
+.Bl -tag -width "/etc/resolv.conf" -compact
+.It Pa /etc/resolv.conf
+.El
+.Sh EXIT STATUS
+.Ex -std resolv
+.\" For sections 1, 6, and 8 only.
+.Sh EXAMPLES
+A typical
+.Nm
+usage is like:
+.Pp
+.Dl $ resolv www.openbsd.org
+.Pp
+To query using the server 10.1.2.3 is like:
+.Pp
+.Dl $ resolv -s 10.1.2.3 www.openbsd.org
+.Pp
+To obtain the MX:
+.Pp
+.Dl $ resolv -t mx www.openbsd.org
+.P
+.\" .Sh DIAGNOSTICS
+.\" For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
+.\" .Sh ERRORS
+.\" For sections 2, 3, 4, and 9 errno settings only.
+.Sh SEE ALSO
+.\" .Xr foobar 1
+.Xr resolv.conf 5
+.Xr nsd 8
+.Xr rebound 8
+.Xr unbound 8
+.Sh STANDARDS
+.Rs
+.%A Mockapetris, P.
+.%D November 1987
+.%R RFC 1034
+.%T "Domain names - concepts and facilities"
+.Re
+.Pp
+.Rs
+.%A Mockapetris, P.
+.%D November 1987
+.%R RFC 1035
+.%T "Domain names - implementation and specification"
+.Re
+.\" .Sh HISTORY
+.Sh AUTHORS
+The
+.Nm
+program was written by
+.An Rodrigo Mosconi Aq Mt [email protected]
+.
+.\" .Sh CAVEATS
+.\" .Sh BUGS
Index: usr.bin/resolv/resolv.c
===================================================================
RCS file: usr.bin/resolv/resolv.c
diff -N usr.bin/resolv/resolv.c
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ usr.bin/resolv/resolv.c    26 Jul 2016 03:45:44 -0000
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 2016 Rodrigo Mosconi <[email protected]>
+ *
+ * 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 <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <asr.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <search.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "asr_private.h"
+
+/*
+ * missing from  nameserv.h
+ */
+
+#define T_NSEC3PARAM 51
+
+
+
+#define OPCODE_SHIFT    11
+#define Z_SHIFT          4
+
+static unsigned int s_get_rdclass(char *);
+static unsigned int s_get_rdtype(char *);
+static int          s_cmpkw(const void *,const void *);
+static void         usage(void);
+static const char*  s_get_rdclassbyint(unsigned int);
+static const char*  s_get_rdtypebyint(unsigned int);
+
+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 {
+        uint8_t   algorithm;
+        uint8_t   type;
+        char      fingerprint[BUFSIZ+1];
+    } sshfp;
+    struct {
+        uint16_t        type_covered;
+        uint8_t         algorithm;
+        uint8_t         labels;
+        uint32_t        original_ttl;
+        uint32_t        signature_expiration;
+        uint32_t        signature_inception;
+        uint16_t        key_tag;
+        char            signer_name[MAXDNAME];
+        char            fingerprint[BUFSIZ+1];
+    } rrsig;
+        struct {
+        char            txt[MAXCDNAME];
+        } txt;
+    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_u8(struct unpack *, uint8_t *);
+static int unpack_u16(struct unpack *, uint16_t *);
+static int unpack_u32(struct unpack *, uint32_t *);
+static int unpack_hex(struct unpack *, char* , uint16_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 *);
+const char * print_rr(const struct dns_rr *, char *, size_t );
+
+
+struct kw {
+    unsigned int num;
+    char *str;
+};
+
+
+static const struct kw rdclass_kw[] = {
+    { C_IN,    "IN"    },        /* the arpa internet */
+    { C_CHAOS, "CHAOS" },     /* for chaos net (MIT) */
+    { C_HS,    "HS"    },        /* for Hesiod name server (MIT) (XXX) */
+    { C_ANY,   "ANY"   },        /* wildcard match */
+};
+
+#define nr_of_rdclasses (sizeof(rdclass_kw)/sizeof(rdclass_kw[0]))
+
+static struct kw rdtype_kw[] = {
+    {  T_A,         "A"        },  /* host address */
+    {  T_NS,            "NS"       },  /* authoritative server */
+    {  T_MD,            "MD"       },  /* mail destination */
+    {  T_MF,            "MF"       },  /* mail forwarder */
+    {  T_CNAME,         "CNAME"    },  /* canonical name */
+    {  T_SOA,           "SOA"      },  /* start of authority zone */
+    {  T_MB,            "MB"       },  /* mailbox domain name */
+    {  T_MG,            "MG"       },  /* mail group member */
+    {  T_MR,            "MR"       },  /* mail rename name */
+    {  T_NULL,          "NULL"     },  /* null resource record */
+    {  T_WKS,           "WKS"      },  /* well known service */
+    {  T_PTR,           "PTR"      },  /* domain name pointer */
+    {  T_HINFO,         "HINFO"    },  /* host information */
+    {  T_MINFO,         "MINFO"    },  /* mailbox information */
+    {  T_MX,            "MX"       },  /* mail routing information */
+    {  T_TXT,           "TXT"      },  /* text strings */
+    {  T_RP,            "RP"       },  /* responsible person */
+    {  T_AFSDB,         "AFSDB"    },  /* AFS cell database */
+    {  T_X25,           "X25"      },  /* X_25 calling address */
+    {  T_ISDN,          "ISDN"     },  /* ISDN calling address */
+    {  T_RT,            "RT"       },  /* router */
+    {  T_NSAP,         "NSAP"     },  /* NSAP address */
+    {  T_NSAP_PTR,     "NSAP_PTR" },  /* reverse NSAP lookup (deprecated)
*/
+    {  T_SIG,           "SIG"      },  /* security signature */
+    {  T_KEY,           "KEY"      },  /* security key */
+    {  T_PX,            "PX"       },  /* X.400 mail mapping */
+    {  T_GPOS,          "GPOS"     },  /* geographical position
(withdrawn) */
+    {  T_AAAA,          "AAAA"     },  /* IP6 Address */
+    {  T_LOC,           "LOC"      },  /* Location Information */
+    {  T_NXT,           "NXT"      },  /* Next Valid Name in Zone */
+    {  T_EID,           "EID"      },  /* Endpoint identifier */
+    {  T_NIMLOC,        "NIMLOC"   },  /* Nimrod locator */
+    {  T_SRV,           "SRV"      },  /* Server selection */
+    {  T_ATMA,          "ATMA"     },  /* ATM Address */
+    {  T_NAPTR,         "NAPTR"    },  /* Naming Authority PoinTeR */
+    {  T_KX,            "KX"       },  /* Key Exchanger */
+    {  T_CERT,          "CERT"     },  /* CERT */
+    {  T_A6,            "A6"       },  /* A6 */
+    {  T_DNAME,         "DNAME"    },  /* DNAME */
+    {  T_SINK,          "SINK"     },  /* SINK */
+    {  T_OPT,           "OPT"      },  /* OPT pseudo-RR, RFC2671 */
+    {  T_APL,           "APL"      },  /* APL */
+    {  T_DS,            "DS"       },  /* Delegation Signer */
+    {  T_SSHFP,         "SSHFP"    },  /* SSH Key Fingerprint */
+    {  T_RRSIG,         "RRSIG"    },  /* RRSIG */
+    {  T_NSEC,          "NSEC"     },  /* NSEC */
+    {  T_DNSKEY,        "DNSKEY"   },  /* DNSKEY */
+    {  T_NSEC3PARAM,    "NSEC3PARAM" },  /* NSEC */
+    {  T_UINFO,         "UINFO"    },  /* user (finger) information */
+    {  T_UID,           "UID"      },  /* user ID */
+    {  T_GID,           "GID"      },  /* group ID */
+    {  T_UNSPEC,        "UNSPEC"   },  /* Unspecified format (binary data)
*/
+    {  T_TKEY,          "TKEY"     },  /* Transaction Key */
+    {  T_TSIG,          "TSIG"     },  /* Transaction Signature */
+    {  T_IXFR,          "IXFR"     },  /* incremental zone transfer */
+    {  T_AXFR,          "AXFR"     },  /* transfer zone of authority */
+    {  T_MAILB,         "MAILB"    },  /* transfer mailbox records */
+    {  T_MAILA,         "MAILA"    },  /* transfer mail agent records */
+    {  T_ANY,           "ANY"      },  /* wildcard match */
+};
+
+#define nr_of_rdtypes (sizeof(rdtype_kw)/sizeof(rdtype_kw[0]))
+
+static int
+s_cmpkw(const void *k,const void *e){
+    return strcasecmp(k,((const struct kw *)e)->str)==0?0:-1;
+}
+
+static int
+s_cmpkw_num(const void *k,const void *e){
+    return *(unsigned int *) k - ((const struct kw *)e)->num;
+}
+
+
+static unsigned int
+s_get_rdclass(char *optarg){
+    struct kw *class;
+
+    size_t nr = nr_of_rdclasses;
+    class = lfind(optarg, rdclass_kw, &nr,
+      sizeof(struct kw), s_cmpkw);
+
+    if (class)
+    return class->num;
+    else
+    return (unsigned int)-1;
+}
+
+static const char *
+s_get_rdclassbyint(unsigned int rdclass){
+    struct kw *class;
+
+    class = bsearch(&rdclass, rdclass_kw, nr_of_rdclasses,
+      sizeof(struct kw), s_cmpkw_num);
+
+    if (class)
+    return class->str;
+    else
+    return "??";
+}
+
+
+static unsigned int
+s_get_rdtype(char *optarg){
+    struct kw *type;
+
+    size_t nr = nr_of_rdtypes;
+    type = lfind(optarg, rdtype_kw, &nr,
+      sizeof(struct kw), s_cmpkw);
+
+    if (type)
+    return type->num;
+    else
+    return (unsigned int)-1;
+}
+
+static const char *
+s_get_rdtypebyint(unsigned int rdtype){
+    struct kw *type;
+
+    type = bsearch(&rdtype, rdtype_kw, nr_of_rdtypes,
+      sizeof(struct kw), s_cmpkw_num);
+
+    if (type)
+    return type->str;
+    else
+    return "??";
+}
+
+
+void
+usage(void){
+    printf("%s [-c class] [-h] [-s server] [-t type]
fdqn\n",getprogname());
+}
+
+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);
+}
+
+
+
+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_u8(struct unpack *p, uint8_t *u8)
+{
+    if (unpack_data(p, u8, 1) == -1)
+    return (-1);
+
+    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_hex(struct unpack *p, char *dst, uint16_t max)
+{
+    int i,l,len=BUFSIZ;
+    char *s=dst;
+
+    for (i=0 ; i<max ; i++)
+    {
+        l=snprintf(s,len,"%02X",*(unsigned char*)(p->buf+p->offset++));
+        s+=2;
+        len-=2;
+        if (i>0 && i%27==0){
+            snprintf(s,len," ");
+            s++; len--;
+        }
+
+    }
+
+    return (0);
+}
+
+
+static 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_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)
+{
+    uint8_t        txtsz;
+    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;
+
+    case T_SSHFP:
+    if (rr->rr_class != C_IN)
+        goto other;
+    unpack_u8(p, &rr->rr.sshfp.algorithm);
+    unpack_u8(p, &rr->rr.sshfp.type);
+    unpack_hex(p, rr->rr.sshfp.fingerprint, rdlen-2);
+    break;
+
+    case T_TXT:
+    if (rr->rr_class != C_IN)
+        goto other;
+    unpack_u8(p,&txtsz);
+        unpack_data(p,
rr->rr.txt.txt,txtsz<sizeof(rr->rr.txt.txt)?txtsz:sizeof(rr->rr.txt.txt));
+        break;
+
+    case T_RRSIG:
+    if (rr->rr_class != C_IN)
+        goto other;
+    unpack_u16(p, &rr->rr.rrsig.type_covered);
+    unpack_u8(p, &rr->rr.rrsig.algorithm);
+    unpack_u8(p, &rr->rr.rrsig.labels);
+    unpack_u32(p, &rr->rr.rrsig.original_ttl);
+    unpack_u32(p, &rr->rr.rrsig.signature_expiration);
+    unpack_u32(p, &rr->rr.rrsig.signature_inception);
+    unpack_u16(p, &rr->rr.rrsig.key_tag);
+    unpack_dname(p, rr->rr.rrsig.signer_name, sizeof
rr->rr.rrsig.signer_name);
+    unpack_hex(p, rr->rr.rrsig.fingerprint, rdlen - p->offset);
+    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);
+}
+
+char *
+_strdname(const char *_dname, char *buf, size_t max)
+{
+    const unsigned char *dname = _dname;
+    char    *res;
+    size_t   left, n, count;
+
+    if (_dname[0] == 0) {
+    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);
+}
+
+
+
+const char *
+print_rr(const struct dns_rr *rr, char *buf, size_t max)
+{
+    char    *res;
+    char     tmp[256];
+    char     tmp2[256];
+    int      r,i;
+    char    *b2;
+    char    *b2p    ;
+    char    *b2l;
+
+    res = buf;
+
+    r = snprintf(buf, max, "%s %u %s %s ",
+      print_dname(rr->rr_dname, tmp, sizeof tmp),
+      rr->rr_ttl,
+      s_get_rdclassbyint(rr->rr_class),
+      s_get_rdtypebyint(rr->rr_type));
+    if (r == -1) {
+    buf[0] = '\0';
+    return (buf);
+    }
+
+    if ((size_t)r >= max)
+    return (buf);
+
+    max -= r;
+    buf += r;
+
+    switch (rr->rr_type) {
+    case T_CNAME:
+    print_dname(rr->rr.cname.cname, buf, max);
+    break;
+    case T_MX:
+    snprintf(buf, max, "%lu %s",
+      (unsigned long)rr->rr.mx.preference,
+      print_dname(rr->rr.mx.exchange, tmp, sizeof tmp));
+    break;
+    case T_NS:
+    print_dname(rr->rr.ns.nsname, buf, max);
+    break;
+    case T_PTR:
+    print_dname(rr->rr.ptr.ptrname, buf, max);
+    break;
+    case T_SOA:
+    snprintf(buf, max, "%s %s %lu %lu %lu %lu %lu",
+      print_dname(rr->rr.soa.rname, tmp, sizeof tmp),
+      print_dname(rr->rr.soa.mname, tmp2, sizeof tmp2),
+      (unsigned long)rr->rr.soa.serial,
+      (unsigned long)rr->rr.soa.refresh,
+      (unsigned long)rr->rr.soa.retry,
+      (unsigned long)rr->rr.soa.expire,
+      (unsigned long)rr->rr.soa.minimum);
+    break;
+    case T_A:
+    if (rr->rr_class != C_IN)
+        goto other;
+    snprintf(buf, max, "%s", inet_ntop(AF_INET,
+        &rr->rr.in_a.addr, tmp, sizeof tmp));
+    break;
+    case T_AAAA:
+    if (rr->rr_class != C_IN)
+        goto other;
+    snprintf(buf, max, "%s", inet_ntop(AF_INET6,
+        &rr->rr.in_aaaa.addr6, tmp, sizeof tmp));
+    break;
+    case T_SSHFP:
+    if (rr->rr_class != C_IN)
+        goto other;
+    snprintf(buf, max, "%d %d %s", rr->rr.sshfp.algorithm,
+      rr->rr.sshfp.type, rr->rr.sshfp.fingerprint);
+    break;
+
+    case T_TXT:
+    if (rr->rr_class != C_IN)
+        goto other;
+    snprintf(buf,max, "\"%s\"", rr->rr.txt.txt);
+        break;
+
+    case T_RRSIG:
+    if (rr->rr_class != C_IN)
+        goto other;
+    snprintf(buf, max, "%s %u %u %u %u ( %u %u %s %s)",
+      s_get_rdtypebyint(rr->rr.rrsig.type_covered),
+      rr->rr.rrsig.algorithm,
+      rr->rr.rrsig.labels,
+      rr->rr.rrsig.original_ttl,
+      rr->rr.rrsig.signature_expiration,
+      rr->rr.rrsig.signature_inception,
+      rr->rr.rrsig.key_tag,
+      print_dname(rr->rr.rrsig.signer_name, tmp, sizeof tmp),
+      rr->rr.rrsig.fingerprint
+        );
+    break;
+
+/*
+  case T_SRV:
+  if (rr->rr_class != C_IN)
+  goto other;
+
+  break;
+
+*/
+    default:
+    other:
+    b2=calloc(3,(int)rr->rr.other.rdlen+1);
+    b2p=b2;
+    b2l=b2+(3*(int)rr->rr.other.rdlen);
+    for (i=0;i<(int)rr->rr.other.rdlen;i++){
+        b2p+=snprintf(b2p,b2l-b2p,"%02X ",((unsigned char
*)rr->rr.other.rdata)[i]);
+    }
+    snprintf(buf, max, "(rdlen=%i) %s", (int)rr->rr.other.rdlen, b2);
+    free(b2);
+    break;
+    }
+
+    return (res);
+}
+
+static const char *
+rcodetostr(uint16_t v)
+{
+    switch (v) {
+    case NOERROR:   return "NOERROR";
+    case FORMERR:   return "FORMERR";
+    case SERVFAIL:  return "SERVFAIL";
+    case NXDOMAIN:  return "NXDOMAIN";
+    case NOTIMP:    return "NOTIMP";
+    case REFUSED:   return "REFUSED";
+    default:        return "?";
+    }
+}
+
+static const char *
+print_header(const struct dns_header *h, char *buf, size_t max)
+{
+    snprintf(buf, max,
+      "id:0x%04x %s op:%i %s %s %s %s z:%i r:%s qd:%i an:%i ns:%i ar:%i",
+      ((int)h->id),
+      (h->flags & QR_MASK) ? "QR":"  ",
+      (int)(OPCODE(h->flags) >> OPCODE_SHIFT),
+      (h->flags & AA_MASK) ? "AA":"  ",
+      (h->flags & TC_MASK) ? "TC":"  ",
+      (h->flags & RD_MASK) ? "RD":"  ",
+      (h->flags & RA_MASK) ? "RA":"  ",
+      ((h->flags & Z_MASK) >> Z_SHIFT),
+      rcodetostr(RCODE(h->flags)),
+      h->qdcount, h->ancount, h->nscount, h->arcount);
+
+    return (buf);
+}
+
+
+
+
+/*
+ * Simple DNS resolver
+ */
+int
+main(int argc, char **argv)
+{
+    unsigned int rdclass=C_IN;
+    unsigned int rdtype=T_ANY;
+    int ch;
+    char *server =NULL;
+    char                buf[BUFSIZ];
+
+    struct asr_query *aq;
+    struct asr_result ar;
+    struct unpack        p;
+    struct dns_header    hdr;
+    struct dns_query     q;
+    struct dns_rr        rr;
+    char                 response_server[INET6_ADDRSTRLEN];
+
+    if(pledge("stdio dns",NULL)==-1)
+    err(1,"pledge");
+
+    while ((ch = getopt(argc, argv, "c:ht:s:")) != -1) {
+    switch(ch) {
+    case 'c':
+        rdclass=s_get_rdclass(optarg);
+        break;
+    case 'h':
+        usage();
+        return 0;
+    case 't':
+        rdtype=s_get_rdtype(optarg);
+        break;
+        case 's':
+        server = optarg;
+        break;
+        default:
+        usage();
+        exit(1);
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc == 0){
+        usage();
+    exit(1);
+    }
+
+
+    if (server)
+    setenv ("NAMESERVER",server,1);
+
+    aq = res_query_async(argv[0], rdclass, rdtype, NULL);
+
+    asr_run_sync(aq,&ar);
+
+    if (ar.ar_errno == ETIMEDOUT)
+        errx(1,"timeout to query\n");
+
+
+    switch(ar.ar_ns.ss_family) {
+    case AF_INET:
+    inet_ntop(AF_INET, &(((struct sockaddr_in*) &ar.ar_ns)->sin_addr),
+      response_server,sizeof(response_server));
+    break;
+    case AF_INET6:
+    inet_ntop(AF_INET6, &((struct sockaddr_in6*) &ar.ar_ns)->sin6_addr,
+      response_server,sizeof(response_server));
+    break;
+    default:
+    errx(1,"Unknow Address Family: %d\n", ar.ar_ns.ss_family);
+    }
+
+
+
+    unpack_init(&p, ar.ar_data, ar.ar_datalen);
+    unpack_header(&p, &hdr);
+    printf("response from %s", response_server);
+    if (hdr.flags & AA_MASK)
+    printf(" (autoritative)\n");
+    else
+    printf("\n");
+    print_header(&hdr, buf, BUFSIZ-1);
+    printf("%s\n", buf);
+    unpack_query(&p, &q);
+
+    for (; hdr.ancount; hdr.ancount--) {
+    unpack_rr(&p, &rr);
+    print_rr(&rr, buf, BUFSIZ-1);
+    printf("%s\n", buf);
+    }
+
+    free(ar.ar_data);
+
+    exit(0);
+}
+
Index: usr.bin/Makefile
===================================================================
RCS file: /cvs/src/usr.bin/Makefile,v
retrieving revision 1.153
diff -u -p -u -r1.153 Makefile
--- usr.bin/Makefile    16 Jul 2015 20:50:40 -0000    1.153
+++ usr.bin/Makefile    26 Jul 2016 03:45:44 -0000
@@ -19,7 +19,7 @@ SUBDIR= apply arch at aucat audioctl awk
     nfsstat nice nm nl nohup openssl pagesize passwd paste patch pctr \
     pkg-config pkill \
     pr printenv printf quota radioctl rcs rdist rdistd \
-    readlink renice rev rpcgen rpcinfo rs rup rusers rwall \
+    readlink renice resolv rev rpcgen rpcinfo rs rup rusers rwall \
     sdiff script sed sendbug shar showmount signify skey \
     skeyaudit skeyinfo skeyinit sndiod \
     sort spell split sqlite3 ssh stat su systat \
Index: lib/libc/asr/asr.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/asr.c,v
retrieving revision 1.54
diff -u -p -u -r1.54 asr.c
--- lib/libc/asr/asr.c    18 Jun 2016 15:25:28 -0000    1.54
+++ lib/libc/asr/asr.c    26 Jul 2016 03:45:44 -0000
@@ -61,7 +61,7 @@ static void *__THREAD_NAME(_asr);
 static struct asr *_asr = NULL;

 /* Allocate and configure an async "resolver". */
-static void *
+void *
 _asr_resolver(void)
 {
     static int     init = 0;
@@ -744,6 +744,17 @@ asr_ctx_envopts(struct asr_ctx *ac)
         if (s < sizeof buf)
             asr_ctx_parse(ac, buf);
     }
+
+        if ((e = getenv("NAMESERVER")) != NULL) {
+                strlcpy(buf, "nameserver ", sizeof buf);
+                strlcat(buf, e, sizeof buf);
+                s = strlcat(buf, "\n", sizeof buf);
+                if (s < sizeof buf)
+            ac->ac_nscount=0;
+                        asr_ctx_parse(ac, buf);
+        }
+
+
 }

 /*
Index: lib/libc/asr/asr_private.h
===================================================================
RCS file: /cvs/src/lib/libc/asr/asr_private.h,v
retrieving revision 1.38
diff -u -p -u -r1.38 asr_private.h
--- lib/libc/asr/asr_private.h    16 Dec 2015 16:32:30 -0000    1.38
+++ lib/libc/asr/asr_private.h    26 Jul 2016 03:45:44 -0000
@@ -310,7 +310,7 @@ ssize_t _asr_dname_from_fqdn(const char
 ssize_t _asr_addr_as_fqdn(const char *, int, char *, size_t);

 /* asr.c */
-static void *_asr_resolver(void);
+void *_asr_resolver(void);
 void _asr_resolver_done(void *);
 struct asr_ctx *_asr_use_resolver(void *);
 struct asr_ctx *_asr_no_resolver(void);

Reply via email to