svn commit: r254939 - in vendor/ldns-host: . dist

Dag-Erling Smørgrav des at FreeBSD.org
Mon Aug 26 22:25:56 UTC 2013


Author: des
Date: Mon Aug 26 22:25:55 2013
New Revision: 254939
URL: http://svnweb.freebsd.org/changeset/base/254939

Log:
  Import an LDNS-based implementation of host(1).

Added:
  vendor/ldns-host/
  vendor/ldns-host/README   (contents, props changed)
  vendor/ldns-host/dist/
  vendor/ldns-host/dist/Makefile   (contents, props changed)
  vendor/ldns-host/dist/ldns-host.1   (contents, props changed)
  vendor/ldns-host/dist/ldns-host.c   (contents, props changed)

Added: vendor/ldns-host/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/ldns-host/README	Mon Aug 26 22:25:55 2013	(r254939)
@@ -0,0 +1,13 @@
+This is an LDNS-based implementation of host(1) by Magerya Vitaly:
+
+	http://tx97.net/ldns-host/
+
+Use devel/mercurial to pull the latest sources:
+
+% hg clone http://hg.tx97.net/ldns-host
+
+Use the following command to generate the tag:
+
+% hg log --template "hg-{date(date|localdate, '%Y%m%d-%H%M%S')}\n" | head -1
+
+$FreeBSD$

Added: vendor/ldns-host/dist/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/ldns-host/dist/Makefile	Mon Aug 26 22:25:55 2013	(r254939)
@@ -0,0 +1,23 @@
+PROG=ldns-host
+SRC=ldns-host.c
+MAN=ldns-host.1
+
+LOCALBASE?=/usr/local
+PREFIX?=${LOCALBASE}
+MANDIR?=${PREFIX}/man
+
+XCFLAGS=${CFLAGS} -I${LOCALBASE}/include
+XLDFLAGS=${LDFLAGS} -L${LOCALBASE}/lib -lldns
+
+${PROG}: ${SRC}
+	${CC} -o $@ ${XCFLAGS} ${XLDFLAGS} ${SRC}
+
+clean:
+	rm -f ${PROG}
+
+install: ${PROG}
+	cp ${PROG} ${PREFIX}/bin/
+	cp ${MAN} ${MANDIR}/man1/
+
+deinstall:
+	rm -f ${PREFIX}/bin/${PROG} ${MANDIR}/man1/${MAN}

Added: vendor/ldns-host/dist/ldns-host.1
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/ldns-host/dist/ldns-host.1	Mon Aug 26 22:25:55 2013	(r254939)
@@ -0,0 +1,246 @@
+.\" (c) Magerya Vitaly
+.\"
+.\" Copying and distribution of this file, with or without modification,
+.\" are permitted in any medium without royalty provided the copyright
+.\" notice and this notice are preserved. This file is offered as-is,
+.\" without any warranty.
+.Dd Aug 27, 2012
+.Dt LDNS-HOST 1
+.Os
+.Sh NAME
+.Nm ldns-host
+.Nd DNS lookup utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl aCdilrsTvw46
+.Op Fl c Ar class
+.Op Fl N Ar ndots
+.Op Fl R Ar number
+.Op Fl t Ar type
+.Op Fl W Ar wait
+.Ar name
+.Op Ar server
+.Sh DESCRIPTION
+.Nm
+is a simple utility for performing DNS lookups.  It is normally
+used to convert names to IP addresses and vice versa.
+.Pp
+.Ar name
+is the domain name that is to be looked up.  It can also be a
+dotted-decimal IPv4 address or a colon-delimited IPv6 address,
+in which case
+.Nm
+will by default perform a reverse lookup for that address.
+.Pp
+When
+.Ar name
+is not provided,
+.Nm
+prints a short summary of it's usage.
+.Pp
+.Ar server
+is an optional argument which is either a domain name or an IP
+address of the name server that
+.Nm
+should query instead of the server or servers listed in
+.Pa /etc/resolv.conf .
+When
+.Ar server
+is a domain name, system resolver is used to obtain it's address.
+.Pp
+Supported options:
+.Bl -tag -width indent
+.It Fl a
+Make a verbose query of type
+.Cm ANY .
+Equivalent to
+.Fl v Fl t Cm ANY .
+.It Fl C
+Query for
+.Cm SOA
+records for zone
+.Ar name
+from all of it's authoritative name servers.  The list of name
+servers is obtained via
+.Cm NS
+query for
+.Ar name .
+.It Fl c Ar class
+Perform DNS query of class
+.Ar class .
+Recognized classes are 
+.Cm IN Pq Internet ,
+.Cm CH Pq Chaosnet ,
+.Cm HS Pq Hesiod ,
+.Cm NONE ,
+.Cm ANY
+and
+.Cm CLASS Ns Ar N 
+(where
+.Ar N
+is a number from 1 to 255).  Default is
+.Cm IN .
+.It Fl d
+Produce verbose output.  This is a synonym for
+.Fl v ,
+and is provided for backward compatibility.
+.It Fl i
+Use IP6.INT domain for reverse lookups of IPv6 addresses (as
+defined in RFC1886; note that RFC4159 deprecates IP6.INT).
+By default IP6.ARPA is used.
+.It Fl l
+List all
+.Cm NS, PTR, A
+and
+.Cm AAAA
+records in zone
+.Ar name
+by performing a zone transfer
+.Pq Cm AXFR .
+You can combine this option with
+.Fl a
+to print all records, or with
+.Fl t
+to only print specific ones.
+.It Fl N Ar ndots
+Consider names with at least this many dots as absolute.  That
+is, try to resolve them directly before consulting
+.Ic domain
+or
+.Ic search
+options from
+.Pa /etc/resolv.conf .
+.It Fl r
+Perform non-recursive query to the name server by clearing RD
+.Pq Dq recursion desired
+bit of the query.
+.It Fl R Ar number
+Retry this many times when a query does not receive an answer
+in time.  The default is 1 retry.  If
+.Ar number
+is negative or zero, 1 is used instead.
+.It Fl s
+Report SERVFAIL responses as they are, do not ignore them.
+.It Fl T
+Query name server over TCP.  By default UDP is used, except for
+.Cm AXFR
+and
+.Cm IXFR
+queries, which require TCP.
+.Nm
+will also retry UDP queries in TCP mode if the UDP response was
+truncated (i.e. had TC bit set).
+.It Fl t Ar type
+Perform DNS query of type
+.Ar type ,
+which can be any standard query type name
+.Pq Cm A , CNAME , MX , TXT , No etc ,
+a wildcard query
+.Pq Cm ANY ,
+or
+.Cm TYPE Ns Ar N ,
+where
+.Ar N
+is a number from 1 to 65535.  For
+.Cm IXFR Pq incremental zone transfer
+queries the starting serial number can be specified by appending
+an equal sign followed by the number
+.Pq e.g. Fl t Cm IXFR Ns =12345678 .
+.Pp
+The default is to query for
+.Cm A , AAAA , No and Cm MX
+records, unless
+.Fl C
+or
+.Fl l
+options are given (in which case
+.Cm SOA
+or
+.Cm AXFR
+queries are made) or
+.Ar name
+is a valid IP address
+(in which case reverse lookup using
+.Cm PTR
+query is performed).
+.It Fl v
+Produce verbose output.
+.It Fl w
+Wait forever (or for a very long time) for response from the
+name server.
+.It Fl W Ar wait
+Wait this many seconds for a reply from name server before timing
+out.  If
+.Ar wait
+is negative or zero, value of 1 is used.  The default is to wait
+10 seconds for TCP connections, and 5 seconds for UDP (both are
+subject to retries, see option
+.Fl R ) .
+.It Fl 4
+Only use IPv4 transport.
+.It Fl 6
+Only use IPv6 transport.
+.El
+.Sh FILES
+.Pa /etc/resolv.conf
+.Sh SEE ALSO
+.Xr drill 1 ,
+.Xr resolv.conf 5
+.Sh COMPATIBILITY
+.Nm
+aims to be reasonably compatible with
+.Sq host
+utility from BIND9 distribution, both in supported options and
+in produced output.  Here is a list of known notable differences:
+.Bl -bullet
+.It
+Debugging options
+.Pq Fl D No and Fl m
+are not supported.
+.It
+Query class
+.Cm CLASS0
+and type
+.Cm TYPE0
+are not supported.
+.It
+Backslashes in domain names are treated especially.
+.It
+The maximum of 255 retries (option
+.Fl R )
+are supported.
+.It
+Some resource records are formatted differently.  For example,
+.Cm RRSIG
+and
+.Cm DNSKEY
+records are displayed without spaces in them.
+.It
+When parsing
+.Pa /etc/resolv.conf
+commands
+.Ic sortlist
+and
+.Ic options
+are ignored.  When multiple
+.Ic search
+and/or
+.Ic domain
+commands are present,
+.Nm
+first uses the last
+.Ic domain
+command, and then all of
+.Ic search
+commands, while
+.Sq host
+from BIND9 uses whatever command was specified last.
+.It
+Multi-packet zone transfers are not supported; only the first
+response packet is printed.
+.It
+.Sq Pseudosection TSIG
+is missing from verbose packet output.
+.El
+.Sh AUTHORS
+.An Vitaly Magerya Aq magv at tx97.net

Added: vendor/ldns-host/dist/ldns-host.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/ldns-host/dist/ldns-host.c	Mon Aug 26 22:25:55 2013	(r254939)
@@ -0,0 +1,881 @@
+/*-
+ * (c) Magerya Vitaly
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved. This file is offered as-is,
+ * without any warranty.
+ */
+
+#include <ldns/ldns.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* General utilities.
+ */
+
+static char *progname;
+
+#define countof(array) (sizeof(array)/sizeof(*(array)))
+
+static void
+die(int code, const char *fmt, ...) {
+    va_list args;
+
+    va_start(args, fmt);
+    fprintf(stderr, "%s: ", progname);
+    vfprintf(stderr, fmt, args);
+    fprintf(stderr, "\n");
+    va_end(args);
+    exit(code);
+}
+
+static int
+ndots(const char *name) {
+    int n;
+
+    for (n = 0; (name = strchr(name, '.')); n++, name++);
+    return n;
+}
+
+/* General LDNS-specific utilities.
+ */
+
+static ldns_status
+ldns_resolver_new_default(ldns_resolver **res) {
+    if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK ||
+        (*res = ldns_resolver_new()) != NULL)
+        return LDNS_STATUS_OK;
+    return LDNS_STATUS_MEM_ERR;
+}
+
+static ldns_status
+ldns_resolver_push_default_servers(ldns_resolver *res) {
+    ldns_status status;
+    ldns_rdf *addr;
+
+    if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK ||
+        (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
+        return ldns_rdf_deep_free(addr), status;
+    ldns_rdf_deep_free(addr);
+    if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK ||
+        (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
+        return ldns_rdf_deep_free(addr), status;
+    ldns_rdf_deep_free(addr);
+    return LDNS_STATUS_OK;
+}
+
+static ldns_rdf *
+ldns_rdf_new_addr_frm_str(const char *str) {
+    ldns_rdf *addr;
+
+    if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL)
+        addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
+    return addr;
+}
+
+static void
+ldns_resolver_remove_nameservers(ldns_resolver *res) {
+    while (ldns_resolver_nameserver_count(res) > 0)
+        ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));
+}
+
+static ldns_rdf *
+ldns_rdf_reverse_a(ldns_rdf *addr, const char *base) {
+    char *buf;
+    int i, len;
+
+    len = strlen(base);
+    buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1);
+    for (len = i = 0; i < LDNS_IP4ADDRLEN; i++)
+        len += sprintf(&buf[len], "%d.",
+            (int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]);
+    sprintf(&buf[len], "%s", base);
+    return ldns_dname_new_frm_str(buf);
+}
+
+static ldns_rdf *
+ldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) {
+    char *buf;
+    int i, len;
+
+    len = strlen(base);
+    buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1);
+    for (i = 0; i < LDNS_IP6ADDRLEN; i++) {
+        uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1];
+        sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4);
+    }
+    sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base);
+    return ldns_dname_new_frm_str(buf);
+}
+
+static ldns_status
+ldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec,
+    const ldns_rdf *name, ldns_rr_class c, uint32_t serial) {
+    ldns_rdf *rdf;
+    ldns_rr *rr;
+    uint32_t n;
+
+    if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL)
+        return LDNS_STATUS_MEM_ERR;
+    ldns_rr_set_class(rr, c);
+    ldns_rr_set_owner(rr, ldns_rdf_clone(name));
+    ldns_rr_set_ttl(rr, 0);
+
+    n = 0;
+    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL)
+        goto memerr;
+    ldns_rr_set_rdf(rr, rdf, 0);
+    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1);
+
+    n = htonl(serial);
+    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL)
+        goto memerr;
+    ldns_rr_set_rdf(rr, rdf, 2);
+
+    n = 0;
+    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL)
+        goto memerr;
+    ldns_rr_set_rdf(rr, rdf, 3);
+    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4);
+    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5);
+    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6);
+
+    if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL ||
+        ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL ||
+        !ldns_pkt_push_rr(pkt, sec, rr))
+        goto memerr;
+    return LDNS_STATUS_OK;
+
+memerr:
+    ldns_rr_free(rr);
+    return LDNS_STATUS_MEM_ERR;
+}
+
+static ldns_status
+ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res,
+    const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c,
+    uint16_t flags, uint32_t ixfr_serial, int nameserver) {
+    ldns_status status;
+    ldns_pkt *qpkt;
+
+    int nscnt = ldns_resolver_nameserver_count(res);
+    ldns_rdf **ns = ldns_resolver_nameservers(res);
+    size_t *rtt = ldns_resolver_rtt(res);
+
+    ldns_resolver_set_nameservers(res, &ns[nameserver]);
+    ldns_resolver_set_rtt(res, &rtt[nameserver]);
+    ldns_resolver_set_nameserver_count(res, 1);
+
+    status = ldns_resolver_prepare_query_pkt(&qpkt, res, name, t, c, flags);
+    if (status == LDNS_STATUS_OK && t == LDNS_RR_TYPE_IXFR)
+        status = ldns_pkt_push_rr_soa(qpkt,
+            LDNS_SECTION_AUTHORITY, name, c, ixfr_serial);
+    if (status == LDNS_STATUS_OK)
+        status = ldns_resolver_send_pkt(answer, res, qpkt);
+    ldns_pkt_free(qpkt);
+
+    ldns_resolver_set_nameservers(res, ns);
+    ldns_resolver_set_rtt(res, rtt);
+    ldns_resolver_set_nameserver_count(res, nscnt);
+    return status;
+}
+
+static void
+ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) {
+    int i, j, cnt;
+    ldns_rr_list *rrlist;
+    ldns_rr *rr;
+    ldns_rr_type rrtype;
+
+    rrlist = ldns_pkt_answer(pkt);
+    cnt = ldns_rr_list_rr_count(rrlist);
+    for (i = j = 0; i < cnt; i++) {
+        rr = ldns_rr_list_rr(rrlist, i);
+        rrtype = ldns_rr_get_type(rr);
+        if (type == LDNS_RR_TYPE_ANY ||
+            type == rrtype ||
+            type == LDNS_RR_TYPE_AXFR &&
+                (rrtype == LDNS_RR_TYPE_A ||
+                rrtype == LDNS_RR_TYPE_AAAA ||
+                rrtype == LDNS_RR_TYPE_NS ||
+                rrtype == LDNS_RR_TYPE_PTR))
+            ldns_rr_list_set_rr(rrlist, rr, j++);
+    }
+    ldns_rr_list_set_rr_count(rrlist, j);
+}
+
+/* Packet content printing.
+ */
+
+static struct {
+    ldns_rr_type type;
+    const char *text;
+} rr_types[] = {
+    {LDNS_RR_TYPE_A,        "has address"},
+    {LDNS_RR_TYPE_NS,       "name server"},
+    {LDNS_RR_TYPE_CNAME,    "is an alias for"},
+    {LDNS_RR_TYPE_WKS,      "has well known services"},
+    {LDNS_RR_TYPE_PTR,      "domain name pointer"},
+    {LDNS_RR_TYPE_HINFO,    "host information"},
+    {LDNS_RR_TYPE_MX,       "mail is handled by"},
+    {LDNS_RR_TYPE_TXT,      "descriptive text"},
+    {LDNS_RR_TYPE_X25,      "x25 address"},
+    {LDNS_RR_TYPE_ISDN,     "ISDN address"},
+    {LDNS_RR_TYPE_SIG,      "has signature"},
+    {LDNS_RR_TYPE_KEY,      "has key"},
+    {LDNS_RR_TYPE_AAAA,     "has IPv6 address"},
+    {LDNS_RR_TYPE_LOC,      "location"},
+};
+
+static void
+print_opcode(ldns_pkt_opcode opcode) {
+    ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
+
+    if (lt && lt->name)
+        printf("%s", lt->name);
+    else
+        printf("RESERVED%d", opcode);
+}
+
+static void
+print_rcode(uint8_t rcode) {
+    ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
+
+    if (lt && lt->name)
+        printf("%s", lt->name);
+    else
+        printf("RESERVED%d", rcode);
+}
+
+static int
+print_rr_type(ldns_rr_type type) {
+    char *str;
+    int n;
+    
+    str = ldns_rr_type2str(type);
+    n = printf("%s", str);
+    free(str);
+    return n;
+}
+
+static int
+print_rr_class(ldns_rr_class cls) {
+    char *str;
+    int n;
+
+    str = ldns_rr_class2str(cls);
+    n = printf("%s", str);
+    free(str);
+    return n;
+}
+
+static int
+print_rdf(ldns_rdf *rdf) {
+    char *str;
+    int n;
+
+    str = ldns_rdf2str(rdf);
+    n = printf("%s", str);
+    free(str);
+    return n;
+}
+
+static int
+print_rdf_nodot(ldns_rdf *rdf) {
+    char *str;
+    int len, n;
+
+    str = ldns_rdf2str(rdf);
+    len = strlen(str);
+    n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str);
+    free(str);
+    return n;
+}
+
+static int
+print_padding(int fromcol, int tocol) {
+    int col = fromcol, nextcol = fromcol + 8 - fromcol%8;
+
+    if (fromcol + 1 > tocol) tocol = fromcol + 1;
+    for (; nextcol <= tocol; col = nextcol, nextcol += 8)
+        printf("\t");
+    for (; col < tocol; col++)
+        printf(" ");
+    return col - fromcol;
+}
+
+static void
+print_rr_verbose(ldns_rr *rr) {
+    bool isq = ldns_rr_is_question(rr);
+    int rdcnt = ldns_rr_rd_count(rr);
+    int i, n;
+
+    /* bind9-host does not count the initial ';' here */
+    n = isq ? printf(";") : 0;
+    n = print_rdf(ldns_rr_owner(rr));
+    if (!isq) {
+        n += print_padding(n, 24);
+        n += printf("%d", ldns_rr_ttl(rr));
+    }
+    n += print_padding(n, 32);
+    n += print_rr_class(ldns_rr_get_class(rr));
+    n += print_padding(n, 40);
+    n += print_rr_type(ldns_rr_get_type(rr));
+    for (i = 0; i < rdcnt; i++) {
+        if (i == 0) print_padding(n, 48);
+        else printf(" ");
+        print_rdf(ldns_rr_rdf(rr, i));
+    }
+    printf("\n");
+}
+
+static void
+print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) {
+    int i, cnt = ldns_rr_list_rr_count(rrlist);
+
+    if (cnt == 0)
+        return;
+    printf(";; %s SECTION:\n", name);
+    for (i = 0; i < cnt; i++)
+        print_rr_verbose(ldns_rr_list_rr(rrlist, i));
+    printf("\n");
+}
+
+static void
+print_pkt_verbose(ldns_pkt *pkt) {
+    int got_flags = 0;
+
+    printf(";; ->>HEADER<<- opcode: ");
+    print_opcode(ldns_pkt_get_opcode(pkt));
+    printf(", status: ");
+    print_rcode(ldns_pkt_get_rcode(pkt));
+    printf(", id: %u\n", ldns_pkt_id(pkt));
+    printf(";; flags:");
+    if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1;
+    if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1;
+    if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1;
+    if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1;
+    if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1;
+    if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1;
+    if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1;
+    if (!got_flags) printf(" ");
+    printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n",
+        ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt),
+        ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt));
+    if (ldns_pkt_edns(pkt))
+        printf(";; EDNS: version: %u, udp=%u\n",
+            ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt));
+    printf("\n");
+    print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt));
+    print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt));
+    print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt));
+    print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt));
+}
+
+static void
+print_rr_short(ldns_rr *rr) {
+    ldns_rr_type type = ldns_rr_get_type(rr);
+    size_t i, rdcnt = ldns_rr_rd_count(rr);
+
+    print_rdf_nodot(ldns_rr_owner(rr));
+    printf(" ");
+    for (i = 0; i < countof(rr_types); i++) {
+        if (rr_types[i].type == type) {
+            printf("%s", rr_types[i].text);
+            goto found;
+        }
+    }
+
+    printf("has ");
+    print_rr_type(type);
+    printf(" record");
+
+found:
+    for (i = 0; i < rdcnt; i++) {
+        printf(" ");
+        print_rdf(ldns_rr_rdf(rr, i));
+    }
+    printf("\n");
+}
+
+static void
+print_pkt_short(ldns_pkt *pkt, bool print_rr_server) {
+    ldns_rr_list *rrlist = ldns_pkt_answer(pkt);
+    size_t i;
+
+    for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
+        if (print_rr_server) {
+            printf("Nameserver ");
+            print_rdf(ldns_pkt_answerfrom(pkt));
+            printf(":\n\t");
+        }
+        print_rr_short(ldns_rr_list_rr(rrlist, i));
+    }
+}
+
+static void
+print_received_line(ldns_resolver *res, ldns_pkt *pkt) {
+    char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
+
+    printf("Received %zu bytes from %s#%d in %d ms\n",
+            ldns_pkt_size(pkt), from, ldns_resolver_port(res),
+            ldns_pkt_querytime(pkt));
+    free(from);
+}
+
+/* Main program.
+ *
+ * Note that no memory is freed below this line by intention.
+ */
+
+#define DEFAULT_TCP_TIMEOUT 10
+#define DEFAULT_UDP_TIMEOUT 5
+
+enum operation_mode { M_AXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
+
+static enum operation_mode o_mode = M_DEFAULT_Q;
+static bool o_ignore_servfail = true;
+static bool o_ip6_int = false;
+static bool o_print_pkt_server = false;
+static bool o_print_rr_server = false;
+static bool o_recursive = true;
+static bool o_tcp = false;
+static bool o_verbose = false;
+static char *o_name = NULL;
+static char *o_server = NULL;
+static int o_ipversion = LDNS_RESOLV_INETANY;
+static int o_ndots = 1;
+static int o_retries = 1;
+static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
+static ldns_rr_type o_rrtype = LDNS_RR_TYPE_A;
+static time_t o_timeout = 0;
+static uint32_t o_ixfr_serial = 0;
+
+static void
+usage(void) {
+    fputs(
+    "Usage: ldns-host [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n"
+    "                 [-t type] [-W wait] name [server]\n"
+    "\t-a same as -v -t ANY\n"
+    "\t-C query SOA records from all authoritative name servers\n"
+    "\t-c use this query class (IN, CH, HS, etc)\n"
+    "\t-d produce verbose output, same as -v\n"
+    "\t-i use IP6.INT for IPv6 reverse lookups\n"
+    "\t-l list records in a zone via AXFR\n"
+    "\t-N consider names with at least this many dots as absolute\n"
+    "\t-R retry UDP queries this many times\n"
+    "\t-r disable recursive query\n"
+    "\t-s do not ignore SERVFAIL responses\n"
+    "\t-T send query via TCP\n"
+    "\t-t use this query type (A, AAAA, MX, etc)\n"
+    "\t-v produce verbose output\n"
+    "\t-w wait forever for a server reply\n"
+    "\t-W wait this many seconds for a reply\n"
+    "\t-4 use IPv4 only\n"
+    "\t-6 use IPv6 only\n",
+    stderr);
+    exit(1);
+}
+
+static void
+parse_args(int argc, char *argv[]) {
+    int ch;
+
+    progname = argv[0];
+    while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) {
+        switch (ch) {
+        case 'a':
+            if (o_mode != M_AXFR)
+                o_mode = M_SINGLE_Q;
+            o_rrtype = LDNS_RR_TYPE_ANY;
+            o_verbose = true;
+            break;
+        case 'C':
+            o_mode = M_SOA;
+            o_print_rr_server = true;
+            o_rrclass = LDNS_RR_CLASS_IN;
+            o_rrtype = LDNS_RR_TYPE_NS;
+            break;
+        case 'c':
+            /* bind9-host sets o_mode to M_SINGLE_Q here */
+            o_rrclass = ldns_get_rr_class_by_name(optarg);
+            if (o_rrclass <= 0)
+                die(2, "invalid class: %s\n", optarg);
+            break;
+        case 'd': o_verbose = true; break;
+        case 'i': o_ip6_int = true; break;
+        case 'l':
+            o_mode = M_AXFR;
+            o_rrtype = LDNS_RR_TYPE_AXFR;
+            o_tcp = true;
+            break;
+        case 'N':
+            o_ndots = atoi(optarg);
+            if (o_ndots < 0) o_ndots = 0;
+            break;
+        case 'n':
+            /* bind9-host accepts and ignores this option */
+            break;
+        case 'r': o_recursive = 0; break;
+        case 'R':
+            o_retries = atoi(optarg);
+            if (o_retries <= 0) o_retries = 1;
+            if (o_retries > 255) o_retries = 255;
+            break;
+        case 's': o_ignore_servfail = false; break;
+        case 'T': o_tcp = true; break;
+        case 't':
+            if (o_mode != M_AXFR)
+                o_mode = M_SINGLE_Q;
+            if (strncasecmp(optarg, "ixfr=", 5) == 0) {
+                o_rrtype = LDNS_RR_TYPE_IXFR;
+                o_ixfr_serial = atol(optarg + 5);
+            } else {
+                o_rrtype = ldns_get_rr_type_by_name(optarg);
+                if (o_rrtype <= 0)
+                    die(2, "invalid type: %s\n", optarg);
+            }
+            if (o_rrtype == LDNS_RR_TYPE_AXFR || o_rrtype == LDNS_RR_TYPE_IXFR)
+                o_tcp = true;
+            if (o_rrtype == LDNS_RR_TYPE_AXFR) {
+                o_mode = M_AXFR;
+                o_rrtype = LDNS_RR_TYPE_ANY;
+                o_verbose = true;
+            }
+            break;
+        case 'v': o_verbose = true; break;
+        case 'w':
+              o_timeout = (time_t)INT_MAX;
+              break;
+        case 'W':
+            o_timeout = atol(optarg);
+            if (o_timeout <= 0) o_timeout = 1;
+            break;
+        case '4': o_ipversion = LDNS_RESOLV_INET; break;
+        case '6': o_ipversion = LDNS_RESOLV_INET6; break;
+        default:
+            usage();
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    /* bind9-host ignores arguments after the 2-nd one */
+    if (argc < 1)
+        usage();
+    o_name = argv[0];
+    if (argc > 1) {
+        o_server = argv[1];
+        o_print_pkt_server = true;
+    }
+}
+
+static ldns_rdf*
+safe_str2rdf_dname(const char *name) {
+    ldns_rdf *dname;
+    ldns_status status;
+
+    if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) {
+        die(1, "'%s' is not a legal name (%s)",
+            name, ldns_get_errorstr_by_id(status));
+    }
+    return dname;
+}
+
+static ldns_rdf*
+safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) {
+    ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2);
+
+    if (!result)
+        die(1, "not enought memory for a domain name");
+    /* Why doesn't ldns_dname_cat_clone check this condition? */
+    if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN)
+        die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result),
+            ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW));
+    return result;
+}
+
+static bool
+query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt) {
+    ldns_status status;
+    ldns_pkt_rcode rcode;
+    int i, cnt;
+
+    if (o_verbose) {
+        printf("Trying \"");
+        print_rdf_nodot(domain);
+        printf("\"\n");
+    }
+    for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) {
+        status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
+            o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
+        if (status != LDNS_STATUS_OK) {
+            *pkt = NULL;
+            continue;
+        }
+        if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) {
+            if (o_verbose)
+                printf(";; Truncated, retrying in TCP mode.\n");
+            ldns_resolver_set_usevc(res, true);
+            status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
+                o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i);
+            ldns_resolver_set_usevc(res, false);
+            if (status != LDNS_STATUS_OK)
+                continue;
+        }
+        rcode = ldns_pkt_get_rcode(*pkt);
+        if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1)
+            continue;
+        return rcode == LDNS_RCODE_NOERROR;
+    }
+    if (*pkt == NULL) {
+        printf(";; connection timed out; no servers could be reached\n");
+        exit(1);
+    }
+    return false;
+}
+
+static ldns_rdf *
+search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool absolute) {
+    ldns_rdf *dname, **searchlist;
+    int i, n;
+
+    if (absolute && query(res, domain, pkt))
+        return domain;
+
+    if ((dname = ldns_resolver_domain(res)) != NULL) {
+        dname = safe_dname_cat_clone(domain, dname);
+        if (query(res, dname, pkt))
+            return dname;
+    }
+
+    searchlist = ldns_resolver_searchlist(res);
+    n = ldns_resolver_searchlist_count(res);
+    for (i = 0; i < n; i++) {
+        dname = safe_dname_cat_clone(domain, searchlist[i]);
+        if (query(res, dname, pkt))
+            return dname;
+    }
+
+    if (!absolute && query(res, domain, pkt))
+        return domain;
+
+    return NULL;
+}
+
+static void
+report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) {
+    ldns_pkt_rcode rcode;
+
+    if (o_print_pkt_server) {
+        printf("Using domain server:\nName: %s\nAddress: ", o_server);
+        print_rdf(ldns_pkt_answerfrom(pkt));
+        printf("#%d\nAliases: \n\n", ldns_resolver_port(res));
+        o_print_pkt_server = false;
+    }
+    rcode = ldns_pkt_get_rcode(pkt);
+    if (rcode != LDNS_RCODE_NOERROR) {
+        printf("Host ");
+        print_rdf_nodot(domain);
+        printf(" not found: %d(", rcode);
+        print_rcode(rcode);
+        printf(")\n");
+    } else {
+        if (o_verbose) {
+            print_pkt_verbose(pkt);
+        } else {
+            print_pkt_short(pkt, o_print_rr_server);
+            if (o_mode != M_DEFAULT_Q &&
+                ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) {
+                print_rdf_nodot(domain);
+                printf(" has no ");
+                print_rr_type(o_rrtype);
+                printf(" record\n");
+            }
+        }
+    }
+    if (o_verbose)
+        print_received_line(res, pkt);
+}
+
+static bool
+doquery(ldns_resolver *res, ldns_rdf *domain) {
+    ldns_pkt *pkt;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list