Rodrigo Mosconi
2016-07-26 04:00:43 UTC
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 <***@mosconi.mat.br?
+.\"
+.\" 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 ***@mosconi.mat.br
+.
+.\" .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 <***@mosconi.mat.br>
+ *
+ * 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);
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 <***@mosconi.mat.br?
+.\"
+.\" 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 ***@mosconi.mat.br
+.
+.\" .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 <***@mosconi.mat.br>
+ *
+ * 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);