Discussion:
simple DNS lookup utility
(too old to reply)
Rodrigo Mosconi
2016-07-26 04:00:43 UTC
Permalink
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);
Peter J. Philipp
2016-07-26 10:00:41 UTC
Permalink
Post by Rodrigo Mosconi
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
Hello Rodrigo Mosconi,

I haven't used this utility only read the code a little. I think the
bsearch of the RR types is cool. I did think that when you cast to
unsigned long for some SOA values you may be doing something unintended,
it's better to cast to uint32_t IMO if casting at all. The reason being
an unsigned long on amd64 is 8 bytes size, and 4 bytes size on i386.

Anyhow since you're leaning on libasr you're getting experience with it.
There was a call by OpenSMTPD on twitter a while back that "if DNSSEC is put
into libasr, they would look into DANE". I don't know where the status of
that is now. I did some code and posted it to the freenode IRC channel
#opensmtpd, since eric was very busy at the time I don't know if he saw it.

What you can do is perhaps look into getting a full dnssec stack into libasr
as a follow up project if you want. I'd try to get in touch with eric@ if
you're interested in that. Perhaps you guys can form a coding group to make
this horrendously difficult project easier.

If you're interested in that I'd recommend to you this book that I also have
that I use for my DNSSEC implementations. It's called "The DNSSEC
Specifications" by Reed Media Services. It's basically the RFC's printed out
and put into a book, but it's handy for dealing with DNSSEC since you have
an offline copy of the RFC's to read at places where there is no computer.

If that's not the way you want to go, perhaps you want to write a DNS server.
I did this and my code can be found at http://delphinusdns.centroid.eu. I'm
currently programming on a sign utility for DNSSEC signing zones. DNS is a
never ending subject and I've been programming 10+ years on my DNS server, what
I have learned is that it's a long term commitment to do any code for DNS.

So in conclusion, you've proved that you can code DNS, a few doors open for
you but they promise to be a long journey to reach the final destination and
a lot of hard work. You can choose to close those doors and stick with the
achievement of a dig like tool and persue other short term projects or you
can take the leap, but it'll consume your life for years on end if you stay
at it. It can be profitable for you if you market it right, or it can keep
you unfed for a decade or longer. I'm just saying. :-)

To reiterate I think your code looks fairly good with minor nits given from
a mediocre programmer such as me.

Best Regards,

-peter
Rodrigo Mosconi
2016-07-27 05:30:03 UTC
Permalink
Post by Peter J. Philipp
Post by Rodrigo Mosconi
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
Hello Rodrigo Mosconi,
I haven't used this utility only read the code a little. I think the
bsearch of the RR types is cool. I did think that when you cast to
unsigned long for some SOA values you may be doing something unintended,
it's better to cast to uint32_t IMO if casting at all. The reason being
an unsigned long on amd64 is 8 bytes size, and 4 bytes size on i386.
Anyhow since you're leaning on libasr you're getting experience with it.
There was a call by OpenSMTPD on twitter a while back that "if DNSSEC is
put
into libasr, they would look into DANE". I don't know where the status of
that is now. I did some code and posted it to the freenode IRC channel
#opensmtpd, since eric was very busy at the time I don't know if he saw it.
What you can do is perhaps look into getting a full dnssec stack into
libasr
you're interested in that. Perhaps you guys can form a coding group to
make
this horrendously difficult project easier.
If you're interested in that I'd recommend to you this book that I also
have
that I use for my DNSSEC implementations. It's called "The DNSSEC
Specifications" by Reed Media Services. It's basically the RFC's printed
out
and put into a book, but it's handy for dealing with DNSSEC since you have
an offline copy of the RFC's to read at places where there is no computer.
If that's not the way you want to go, perhaps you want to write a DNS
server.
I did this and my code can be found at http://delphinusdns.centroid.eu.
I'm
currently programming on a sign utility for DNSSEC signing zones. DNS is a
never ending subject and I've been programming 10+ years on my DNS server,
what
I have learned is that it's a long term commitment to do any code for DNS.
So in conclusion, you've proved that you can code DNS, a few doors open for
you but they promise to be a long journey to reach the final destination
and
a lot of hard work. You can choose to close those doors and stick with the
achievement of a dig like tool and persue other short term projects or you
can take the leap, but it'll consume your life for years on end if you stay
at it. It can be profitable for you if you market it right, or it can keep
you unfed for a decade or longer. I'm just saying. :-)
To reiterate I think your code looks fairly good with minor nits given from
a mediocre programmer such as me.
Best Regards,
-peter
Thanks Peter,

Related with DNS, I`m thinking on improve it later to become more like
dig. For now,
I`m finishing a 40 pages report about it.. (yes, the report is bigger than
the code...).

[]`s
Mosconi

Loading...