1/*-
2 * (c) Magerya Vitaly
3 *
4 * Copying and distribution of this file, with or without modification,
5 * are permitted in any medium without royalty provided the copyright
6 * notice and this notice are preserved. This file is offered as-is,
7 * without any warranty.
8 */
9
10#include <ldns/ldns.h>
11#include <limits.h>
12#include <netdb.h>
13#include <netinet/in.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17
18/* General utilities.
19 */
20
21static char *progname;
22
23#define countof(array) (sizeof(array)/sizeof(*(array)))
24
25static void
26die(int code, const char *fmt, ...) {
27    va_list args;
28
29    va_start(args, fmt);
30    fprintf(stderr, "%s: ", progname);
31    vfprintf(stderr, fmt, args);
32    fprintf(stderr, "\n");
33    va_end(args);
34    exit(code);
35}
36
37static int
38ndots(const char *name) {
39    int n;
40
41    for (n = 0; (name = strchr(name, '.')); n++, name++);
42    return n;
43}
44
45/* General LDNS-specific utilities.
46 */
47
48static ldns_status
49ldns_resolver_new_default(ldns_resolver **res) {
50    if (ldns_resolver_new_frm_file(res, NULL) == LDNS_STATUS_OK ||
51        (*res = ldns_resolver_new()) != NULL)
52        return LDNS_STATUS_OK;
53    return LDNS_STATUS_MEM_ERR;
54}
55
56static ldns_status
57ldns_resolver_push_default_servers(ldns_resolver *res) {
58    ldns_status status;
59    ldns_rdf *addr;
60
61    if ((status = ldns_str2rdf_a(&addr, "127.0.0.1")) != LDNS_STATUS_OK ||
62        (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
63        return ldns_rdf_deep_free(addr), status;
64    ldns_rdf_deep_free(addr);
65    if ((status = ldns_str2rdf_aaaa(&addr, "::1")) != LDNS_STATUS_OK ||
66        (status = ldns_resolver_push_nameserver(res, addr)) != LDNS_STATUS_OK)
67        return ldns_rdf_deep_free(addr), status;
68    ldns_rdf_deep_free(addr);
69    return LDNS_STATUS_OK;
70}
71
72static ldns_rdf *
73ldns_rdf_new_addr_frm_str(const char *str) {
74    ldns_rdf *addr;
75
76    if ((addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str)) == NULL)
77        addr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
78    return addr;
79}
80
81static void
82ldns_resolver_remove_nameservers(ldns_resolver *res) {
83    while (ldns_resolver_nameserver_count(res) > 0)
84        ldns_rdf_deep_free(ldns_resolver_pop_nameserver(res));
85}
86
87static ldns_rdf *
88ldns_rdf_reverse_a(ldns_rdf *addr, const char *base) {
89    char *buf;
90    int i, len;
91
92    len = strlen(base);
93    buf = alloca(LDNS_IP4ADDRLEN*4 + len + 1);
94    for (len = i = 0; i < LDNS_IP4ADDRLEN; i++)
95        len += sprintf(&buf[len], "%d.",
96            (int)ldns_rdf_data(addr)[LDNS_IP4ADDRLEN - i - 1]);
97    sprintf(&buf[len], "%s", base);
98    return ldns_dname_new_frm_str(buf);
99}
100
101static ldns_rdf *
102ldns_rdf_reverse_aaaa(ldns_rdf *addr, const char *base) {
103    char *buf;
104    int i, len;
105
106    len = strlen(base);
107    buf = alloca(LDNS_IP6ADDRLEN*4 + len + 1);
108    for (i = 0; i < LDNS_IP6ADDRLEN; i++) {
109        uint8_t byte = ldns_rdf_data(addr)[LDNS_IP6ADDRLEN - i - 1];
110        sprintf(&buf[i*4], "%x.%x.", byte & 0x0F, byte >> 4);
111    }
112    sprintf(&buf[LDNS_IP6ADDRLEN*4], "%s", base);
113    return ldns_dname_new_frm_str(buf);
114}
115
116static ldns_status
117ldns_pkt_push_rr_soa(ldns_pkt *pkt, ldns_pkt_section sec,
118    const ldns_rdf *name, ldns_rr_class c, uint32_t serial) {
119    ldns_rdf *rdf;
120    ldns_rr *rr;
121    uint32_t n;
122
123    if ((rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_SOA)) == NULL)
124        return LDNS_STATUS_MEM_ERR;
125    ldns_rr_set_class(rr, c);
126    ldns_rr_set_owner(rr, ldns_rdf_clone(name));
127    ldns_rr_set_ttl(rr, 0);
128
129    n = 0;
130    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, &n)) == NULL)
131        goto memerr;
132    ldns_rr_set_rdf(rr, rdf, 0);
133    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 1);
134
135    n = htonl(serial);
136    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_INT32, 4, &n)) == NULL)
137        goto memerr;
138    ldns_rr_set_rdf(rr, rdf, 2);
139
140    n = 0;
141    if ((rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_PERIOD, 4, &n)) == NULL)
142        goto memerr;
143    ldns_rr_set_rdf(rr, rdf, 3);
144    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 4);
145    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 5);
146    ldns_rr_set_rdf(rr, ldns_rdf_clone(rdf), 6);
147
148    if (ldns_rr_rdf(rr, 1) == NULL || ldns_rr_rdf(rr, 4) == NULL ||
149        ldns_rr_rdf(rr, 5) == NULL || ldns_rr_rdf(rr, 6) == NULL ||
150        !ldns_pkt_push_rr(pkt, sec, rr))
151        goto memerr;
152    return LDNS_STATUS_OK;
153
154memerr:
155    ldns_rr_free(rr);
156    return LDNS_STATUS_MEM_ERR;
157}
158
159static uint32_t
160ldns_rr_soa_get_serial(const ldns_rr *rr)
161{
162    const ldns_rdf *rdf;
163
164    if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) return 0;
165    if (ldns_rr_rd_count(rr) != 7) return 0;
166    rdf = ldns_rr_rdf(rr, 2);
167    if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_INT32) return 0;
168    if (ldns_rdf_size(rdf) != 4) return 0;
169    return ldns_rdf2native_int32(rdf);
170}
171
172static ldns_status
173ldns_tcp_start(ldns_resolver *res, ldns_pkt *qpkt, int nameserver) {
174    /* This routine is based on ldns_axfr_start, with the major
175     * difference in that it takes a query packet explicitly.
176     */
177    struct sockaddr_storage *ns = NULL;
178    size_t ns_len = 0;
179    ldns_buffer *qbuf = NULL;
180    ldns_status status;
181
182    ns = ldns_rdf2native_sockaddr_storage(
183            res->_nameservers[nameserver], ldns_resolver_port(res), &ns_len);
184    if (ns == NULL) {
185        status = LDNS_STATUS_MEM_ERR;
186        goto error;
187    }
188
189    res->_socket = ldns_tcp_connect(
190            ns, (socklen_t)ns_len, ldns_resolver_timeout(res));
191    if (res->_socket <= 0) {
192        status = LDNS_STATUS_ADDRESS_ERR;
193        goto error;
194    }
195
196    qbuf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
197    if (qbuf == NULL) {
198        status = LDNS_STATUS_MEM_ERR;
199        goto error;
200    }
201
202    status = ldns_pkt2buffer_wire(qbuf, qpkt);
203    if (status != LDNS_STATUS_OK)
204        goto error;
205
206    if (ldns_tcp_send_query(qbuf, res->_socket, ns, (socklen_t)ns_len) == 0) {
207        status = LDNS_STATUS_NETWORK_ERR;
208        goto error;
209    }
210
211    ldns_buffer_free(qbuf);
212    free(ns);
213    return LDNS_STATUS_OK;
214
215error:
216    ldns_buffer_free(qbuf);
217    free(ns);
218    if (res->_socket > 0) {
219        close(res->_socket);
220        res->_socket = 0;
221    }
222    return status;
223}
224
225static ldns_status
226ldns_tcp_read(ldns_pkt **answer, ldns_resolver *res) {
227    ldns_status status;
228    struct timeval t1, t2;
229    uint8_t *data;
230    size_t size;
231
232    if (res->_socket <= 0)
233        return LDNS_STATUS_ERR;
234
235    gettimeofday(&t1, NULL);
236    data = ldns_tcp_read_wire_timeout(
237            res->_socket, &size, ldns_resolver_timeout(res));
238    if (data == NULL)
239        goto error;
240
241    status = ldns_wire2pkt(answer, data, size);
242    free(data);
243    if (status != LDNS_STATUS_OK)
244        goto error;
245
246    gettimeofday(&t2, NULL);
247    ldns_pkt_set_querytime(*answer,
248            (uint32_t)((t2.tv_sec - t1.tv_sec)*1000) +
249                (t2.tv_usec - t1.tv_usec)/1000);
250    ldns_pkt_set_timestamp(*answer, t2);
251    return status;
252
253error:
254    close(res->_socket);
255    res->_socket = 0;
256    return LDNS_STATUS_ERR;
257}
258
259static void
260ldns_tcp_close(ldns_resolver *res) {
261    if (res->_socket > 0) {
262        close(res->_socket);
263        res->_socket = 0;
264    }
265}
266
267static ldns_status
268ldns_resolver_send_to(ldns_pkt **answer, ldns_resolver *res,
269    const ldns_rdf *name, ldns_rr_type t, ldns_rr_class c,
270    uint16_t flags, uint32_t ixfr_serial, int nameserver,
271    bool close_tcp) {
272    ldns_status status = LDNS_STATUS_OK;
273    ldns_pkt *qpkt;
274    struct timeval now;
275
276    int nscnt = ldns_resolver_nameserver_count(res);
277    ldns_rdf **ns = ldns_resolver_nameservers(res);
278    size_t *rtt = ldns_resolver_rtt(res);
279
280    ldns_resolver_set_nameservers(res, &ns[nameserver]);
281    ldns_resolver_set_rtt(res, &rtt[nameserver]);
282    ldns_resolver_set_nameserver_count(res, 1);
283
284    /* The next fragment should have been a call to
285     * ldns_resolver_prepare_query_pkt(), but starting with ldns
286     * version 1.6.17 that function tries to add it's own SOA
287     * records when rr_type is LDNS_RR_TYPE_IXFR, and we don't
288     * want that.
289     */
290    qpkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags);
291    if (qpkt == NULL) {
292        status = LDNS_STATUS_ERR;
293        goto done;
294    }
295    now.tv_sec = time(NULL);
296    now.tv_usec = 0;
297    ldns_pkt_set_timestamp(qpkt, now);
298    ldns_pkt_set_random_id(qpkt);
299
300    if (t == LDNS_RR_TYPE_IXFR) {
301        status = ldns_pkt_push_rr_soa(qpkt,
302            LDNS_SECTION_AUTHORITY, name, c, ixfr_serial);
303        if (status != LDNS_STATUS_OK) goto done;
304    }
305    if (close_tcp) {
306        status = ldns_resolver_send_pkt(answer, res, qpkt);
307    } else {
308        status = ldns_tcp_start(res, qpkt, 0);
309        if (status != LDNS_STATUS_OK) goto done;
310        status = ldns_tcp_read(answer, res);
311        if (status != LDNS_STATUS_OK) goto done;
312        ldns_pkt_set_answerfrom(*answer, ldns_rdf_clone(ns[0]));
313    }
314
315done:
316    ldns_pkt_free(qpkt);
317
318    ldns_resolver_set_nameservers(res, ns);
319    ldns_resolver_set_rtt(res, rtt);
320    ldns_resolver_set_nameserver_count(res, nscnt);
321    return status;
322}
323
324static void
325ldns_pkt_filter_answer(ldns_pkt *pkt, ldns_rr_type type) {
326    int i, j, cnt;
327    ldns_rr_list *rrlist;
328    ldns_rr *rr;
329    ldns_rr_type rrtype;
330
331    rrlist = ldns_pkt_answer(pkt);
332    cnt = ldns_rr_list_rr_count(rrlist);
333    for (i = j = 0; i < cnt; i++) {
334        rr = ldns_rr_list_rr(rrlist, i);
335        rrtype = ldns_rr_get_type(rr);
336        if (type == LDNS_RR_TYPE_ANY ||
337            type == rrtype ||
338            (type == LDNS_RR_TYPE_AXFR &&
339                (rrtype == LDNS_RR_TYPE_A ||
340                rrtype == LDNS_RR_TYPE_AAAA ||
341                rrtype == LDNS_RR_TYPE_NS ||
342                rrtype == LDNS_RR_TYPE_PTR)))
343            ldns_rr_list_set_rr(rrlist, rr, j++);
344    }
345    ldns_rr_list_set_rr_count(rrlist, j);
346}
347
348/* Packet content printing.
349 */
350
351static struct {
352    ldns_rr_type type;
353    const char *text;
354} rr_types[] = {
355    {LDNS_RR_TYPE_A,        "has address"},
356    {LDNS_RR_TYPE_NS,       "name server"},
357    {LDNS_RR_TYPE_CNAME,    "is an alias for"},
358    {LDNS_RR_TYPE_WKS,      "has well known services"},
359    {LDNS_RR_TYPE_PTR,      "domain name pointer"},
360    {LDNS_RR_TYPE_HINFO,    "host information"},
361    {LDNS_RR_TYPE_MX,       "mail is handled by"},
362    {LDNS_RR_TYPE_TXT,      "descriptive text"},
363    {LDNS_RR_TYPE_X25,      "x25 address"},
364    {LDNS_RR_TYPE_ISDN,     "ISDN address"},
365    {LDNS_RR_TYPE_SIG,      "has signature"},
366    {LDNS_RR_TYPE_KEY,      "has key"},
367    {LDNS_RR_TYPE_AAAA,     "has IPv6 address"},
368    {LDNS_RR_TYPE_LOC,      "location"},
369};
370
371static void
372print_opcode(ldns_pkt_opcode opcode) {
373    ldns_lookup_table *lt = ldns_lookup_by_id(ldns_opcodes, opcode);
374
375    if (lt && lt->name)
376        printf("%s", lt->name);
377    else
378        printf("RESERVED%d", opcode);
379}
380
381static void
382print_rcode(uint8_t rcode) {
383    ldns_lookup_table *lt = ldns_lookup_by_id(ldns_rcodes, rcode);
384
385    if (lt && lt->name)
386        printf("%s", lt->name);
387    else
388        printf("RESERVED%d", rcode);
389}
390
391static int
392print_rr_type(ldns_rr_type type) {
393    char *str;
394    int n;
395
396    str = ldns_rr_type2str(type);
397    n = printf("%s", str);
398    free(str);
399    return n;
400}
401
402static int
403print_rr_class(ldns_rr_class cls) {
404    char *str;
405    int n;
406
407    str = ldns_rr_class2str(cls);
408    n = printf("%s", str);
409    free(str);
410    return n;
411}
412
413static int
414print_rdf(ldns_rdf *rdf) {
415    char *str;
416    int n;
417
418    str = ldns_rdf2str(rdf);
419    n = printf("%s", str);
420    free(str);
421    return n;
422}
423
424static int
425print_rdf_nodot(ldns_rdf *rdf) {
426    char *str;
427    int len, n;
428
429    str = ldns_rdf2str(rdf);
430    len = strlen(str);
431    n = printf("%.*s", str[len-1] == '.' ? len-1 : len, str);
432    free(str);
433    return n;
434}
435
436static int
437print_padding(int fromcol, int tocol) {
438    int col = fromcol, nextcol = fromcol + 8 - fromcol%8;
439
440    if (fromcol + 1 > tocol) tocol = fromcol + 1;
441    for (; nextcol <= tocol; col = nextcol, nextcol += 8)
442        printf("\t");
443    for (; col < tocol; col++)
444        printf(" ");
445    return col - fromcol;
446}
447
448static void
449print_rr_verbose(ldns_rr *rr) {
450    bool isq = ldns_rr_is_question(rr);
451    int rdcnt = ldns_rr_rd_count(rr);
452    int i, n;
453
454    /* bind9-host does not count the initial ';' here */
455    n = isq ? printf(";") : 0;
456    n = print_rdf(ldns_rr_owner(rr));
457    if (!isq) {
458        n += print_padding(n, 24);
459        n += printf("%d", ldns_rr_ttl(rr));
460    }
461    n += print_padding(n, 32);
462    n += print_rr_class(ldns_rr_get_class(rr));
463    n += print_padding(n, 40);
464    n += print_rr_type(ldns_rr_get_type(rr));
465    for (i = 0; i < rdcnt; i++) {
466        if (i == 0) print_padding(n, 48);
467        else printf(" ");
468        print_rdf(ldns_rr_rdf(rr, i));
469    }
470    printf("\n");
471}
472
473static void
474print_pkt_section_verbose(const char *name, ldns_rr_list *rrlist) {
475    int i, cnt = ldns_rr_list_rr_count(rrlist);
476
477    if (cnt == 0)
478        return;
479    printf(";; %s SECTION:\n", name);
480    for (i = 0; i < cnt; i++)
481        print_rr_verbose(ldns_rr_list_rr(rrlist, i));
482    printf("\n");
483}
484
485static void
486print_pkt_verbose(ldns_pkt *pkt) {
487    int got_flags = 0;
488
489    printf(";; ->>HEADER<<- opcode: ");
490    print_opcode(ldns_pkt_get_opcode(pkt));
491    printf(", status: ");
492    print_rcode(ldns_pkt_get_rcode(pkt));
493    printf(", id: %u\n", ldns_pkt_id(pkt));
494    printf(";; flags:");
495    if (ldns_pkt_qr(pkt)) printf(" qr"), got_flags = 1;
496    if (ldns_pkt_aa(pkt)) printf(" aa"), got_flags = 1;
497    if (ldns_pkt_tc(pkt)) printf(" tc"), got_flags = 1;
498    if (ldns_pkt_rd(pkt)) printf(" rd"), got_flags = 1;
499    if (ldns_pkt_ra(pkt)) printf(" ra"), got_flags = 1;
500    if (ldns_pkt_ad(pkt)) printf(" ad"), got_flags = 1;
501    if (ldns_pkt_cd(pkt)) printf(" cd"), got_flags = 1;
502    if (!got_flags) printf(" ");
503    printf("; QUERY: %u, ANSWER: %u, AUTHORITY: %u, ADDITIONAL: %u\n",
504        ldns_pkt_qdcount(pkt), ldns_pkt_ancount(pkt),
505        ldns_pkt_nscount(pkt), ldns_pkt_arcount(pkt));
506    if (ldns_pkt_edns(pkt))
507        printf(";; EDNS: version: %u, udp=%u\n",
508            ldns_pkt_edns_version(pkt), ldns_pkt_edns_udp_size(pkt));
509    printf("\n");
510    print_pkt_section_verbose("QUESTION", ldns_pkt_question(pkt));
511    print_pkt_section_verbose("ANSWER", ldns_pkt_answer(pkt));
512    print_pkt_section_verbose("AUTHORITY", ldns_pkt_authority(pkt));
513    print_pkt_section_verbose("ADDITIONAL", ldns_pkt_additional(pkt));
514}
515
516static void
517print_rr_short(ldns_rr *rr) {
518    ldns_rr_type type = ldns_rr_get_type(rr);
519    size_t i, rdcnt = ldns_rr_rd_count(rr);
520
521    print_rdf_nodot(ldns_rr_owner(rr));
522    printf(" ");
523    for (i = 0; i < countof(rr_types); i++) {
524        if (rr_types[i].type == type) {
525            printf("%s", rr_types[i].text);
526            goto found;
527        }
528    }
529
530    printf("has ");
531    print_rr_type(type);
532    printf(" record");
533
534found:
535    for (i = 0; i < rdcnt; i++) {
536        printf(" ");
537        print_rdf(ldns_rr_rdf(rr, i));
538    }
539    printf("\n");
540}
541
542static void
543print_pkt_short(ldns_pkt *pkt, bool print_rr_server) {
544    ldns_rr_list *rrlist = ldns_pkt_answer(pkt);
545    size_t i;
546
547    for (i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
548        if (print_rr_server) {
549            printf("Nameserver ");
550            print_rdf(ldns_pkt_answerfrom(pkt));
551            printf(":\n\t");
552        }
553        print_rr_short(ldns_rr_list_rr(rrlist, i));
554    }
555}
556
557static void
558print_received_line(ldns_resolver *res, ldns_pkt *pkt) {
559    char *from = ldns_rdf2str(ldns_pkt_answerfrom(pkt));
560
561    printf("Received %zu bytes from %s#%d in %d ms\n",
562            ldns_pkt_size(pkt), from, ldns_resolver_port(res),
563            ldns_pkt_querytime(pkt));
564    free(from);
565}
566
567/* Main program.
568 *
569 * Note that no memory is freed below this line by intention.
570 */
571
572#define DEFAULT_TCP_TIMEOUT 10
573#define DEFAULT_UDP_TIMEOUT 5
574
575enum operation_mode { M_AXFR, M_IXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
576
577static enum operation_mode o_mode = M_DEFAULT_Q;
578static bool o_ignore_servfail = true;
579static bool o_ip6_int = false;
580static bool o_print_pkt_server = false;
581static bool o_print_rr_server = false;
582static bool o_recursive = true;
583static bool o_tcp = false;
584static bool o_verbose = false;
585static char *o_name = NULL;
586static char *o_server = NULL;
587static int o_ipversion = LDNS_RESOLV_INETANY;
588static int o_ndots = 1;
589static int o_retries = 1;
590static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
591static ldns_rr_type o_rrtype = (ldns_rr_type)-1;
592static time_t o_timeout = 0;
593static uint32_t o_ixfr_serial = 0;
594
595static void
596usage(void) {
597    fprintf(stderr,
598    "Usage: %s [-aCdilrsTvw46] [-c class] [-N ndots] [-R number]\n"
599    "       %*c [-t type] [-W wait] name [server]\n"
600    "\t-a same as -v -t ANY\n"
601    "\t-C query SOA records from all authoritative name servers\n"
602    "\t-c use this query class (IN, CH, HS, etc)\n"
603    "\t-d produce verbose output, same as -v\n"
604    "\t-i use IP6.INT for IPv6 reverse lookups\n"
605    "\t-l list records in a zone via AXFR\n"
606    "\t-N consider names with at least this many dots as absolute\n"
607    "\t-R retry UDP queries this many times\n"
608    "\t-r disable recursive query\n"
609    "\t-s do not ignore SERVFAIL responses\n"
610    "\t-T send query via TCP\n"
611    "\t-t use this query type (A, AAAA, MX, etc)\n"
612    "\t-v produce verbose output\n"
613    "\t-w wait forever for a server reply\n"
614    "\t-W wait this many seconds for a reply\n"
615    "\t-4 use IPv4 only\n"
616    "\t-6 use IPv6 only\n",
617    progname, (int)strlen(progname), ' ');
618    exit(1);
619}
620
621static void
622parse_args(int argc, char *argv[]) {
623    int ch;
624
625    progname = argv[0];
626    while ((ch = getopt(argc, argv, "aCdilrsTvw46c:N:R:t:W:")) != -1) {
627        switch (ch) {
628        case 'a':
629            if (o_mode != M_AXFR)
630                o_mode = M_SINGLE_Q;
631            o_rrtype = LDNS_RR_TYPE_ANY;
632            o_verbose = true;
633            break;
634        case 'C':
635            o_mode = M_SOA;
636            o_print_rr_server = true;
637            o_rrclass = LDNS_RR_CLASS_IN;
638            o_rrtype = LDNS_RR_TYPE_NS;
639            break;
640        case 'c':
641            /* bind9-host sets o_mode to M_SINGLE_Q here */
642            o_rrclass = ldns_get_rr_class_by_name(optarg);
643            if (o_rrclass <= 0)
644                die(2, "invalid class: %s\n", optarg);
645            break;
646        case 'd': o_verbose = true; break;
647        case 'i': o_ip6_int = true; break;
648        case 'l':
649            o_mode = M_AXFR;
650            if (o_rrtype == (ldns_rr_type)-1)
651                o_rrtype = LDNS_RR_TYPE_AXFR;
652            o_tcp = true;
653            break;
654        case 'N':
655            o_ndots = atoi(optarg);
656            if (o_ndots < 0) o_ndots = 0;
657            break;
658        case 'n':
659            /* bind9-host accepts and ignores this option */
660            break;
661        case 'r': o_recursive = 0; break;
662        case 'R':
663            o_retries = atoi(optarg);
664            if (o_retries <= 0) o_retries = 1;
665            if (o_retries > 255) o_retries = 255;
666            break;
667        case 's': o_ignore_servfail = false; break;
668        case 'T': o_tcp = true; break;
669        case 't':
670            if (o_mode != M_AXFR)
671                o_mode = M_SINGLE_Q;
672            if (strncasecmp(optarg, "ixfr=", 5) == 0) {
673                o_rrtype = LDNS_RR_TYPE_IXFR;
674                o_ixfr_serial = atol(optarg + 5);
675            } else {
676                o_rrtype = ldns_get_rr_type_by_name(optarg);
677                if (o_rrtype <= 0)
678                    die(2, "invalid type: %s\n", optarg);
679            }
680            if (o_rrtype == LDNS_RR_TYPE_AXFR) {
681                o_mode = M_AXFR;
682                o_rrtype = LDNS_RR_TYPE_ANY;
683                o_verbose = true;
684            }
685            if (o_rrtype == LDNS_RR_TYPE_IXFR) {
686                o_mode = M_IXFR;
687                o_rrtype = LDNS_RR_TYPE_ANY;
688            }
689            break;
690        case 'v': o_verbose = true; break;
691        case 'w':
692              o_timeout = (time_t)INT_MAX;
693              break;
694        case 'W':
695            o_timeout = atol(optarg);
696            if (o_timeout <= 0) o_timeout = 1;
697            break;
698        case '4': o_ipversion = LDNS_RESOLV_INET; break;
699        case '6': o_ipversion = LDNS_RESOLV_INET6; break;
700        default:
701            usage();
702        }
703    }
704    argc -= optind;
705    argv += optind;
706    /* bind9-host ignores arguments after the 2-nd one */
707    if (argc < 1)
708        usage();
709    o_name = argv[0];
710    if (argc > 1) {
711        o_server = argv[1];
712        o_print_pkt_server = true;
713    }
714    if (o_rrtype == (ldns_rr_type)-1)
715        o_rrtype = LDNS_RR_TYPE_A;
716}
717
718static ldns_rdf*
719safe_str2rdf_dname(const char *name) {
720    ldns_rdf *dname;
721    ldns_status status;
722
723    if ((status = ldns_str2rdf_dname(&dname, name)) != LDNS_STATUS_OK) {
724        die(1, "'%s' is not a legal name (%s)",
725            name, ldns_get_errorstr_by_id(status));
726    }
727    return dname;
728}
729
730static ldns_rdf*
731safe_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) {
732    ldns_rdf *result = ldns_dname_cat_clone(rd1, rd2);
733
734    if (!result)
735        die(1, "not enought memory for a domain name");
736    /* Why doesn't ldns_dname_cat_clone check this condition? */
737    if (ldns_rdf_size(result) > LDNS_MAX_DOMAINLEN)
738        die(1, "'%s' is not a legal name (%s)\n", ldns_rdf2str(result),
739            ldns_get_errorstr_by_id(LDNS_STATUS_DOMAINNAME_OVERFLOW));
740    return result;
741}
742
743static bool
744query(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt, bool close_tcp) {
745    ldns_status status;
746    ldns_pkt_rcode rcode;
747    int i, cnt;
748
749    if (o_verbose) {
750        printf("Trying \"");
751        print_rdf_nodot(domain);
752        printf("\"\n");
753    }
754    for (cnt = ldns_resolver_nameserver_count(res), i = 0; i < cnt; i++) {
755        status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
756            o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i,
757            close_tcp);
758        if (status != LDNS_STATUS_OK) {
759            *pkt = NULL;
760            continue;
761        }
762        if (ldns_pkt_tc(*pkt) && !ldns_resolver_usevc(res)) {
763            if (o_verbose)
764                printf(";; Truncated, retrying in TCP mode.\n");
765            ldns_resolver_set_usevc(res, true);
766            status = ldns_resolver_send_to(pkt, res, domain, o_rrtype,
767                o_rrclass, o_recursive ? LDNS_RD : 0, o_ixfr_serial, i,
768                close_tcp);
769            ldns_resolver_set_usevc(res, false);
770            if (status != LDNS_STATUS_OK)
771                continue;
772        }
773        rcode = ldns_pkt_get_rcode(*pkt);
774        if (o_ignore_servfail && rcode == LDNS_RCODE_SERVFAIL && cnt > 1)
775            continue;
776        return rcode == LDNS_RCODE_NOERROR;
777    }
778    if (*pkt == NULL) {
779        printf(";; connection timed out; no servers could be reached\n");
780        exit(1);
781    }
782    return false;
783}
784
785static ldns_rdf *
786search(ldns_resolver *res, ldns_rdf *domain, ldns_pkt **pkt,
787    bool absolute, bool close_tcp) {
788    ldns_rdf *dname, **searchlist;
789    int i, n;
790
791    if (absolute && query(res, domain, pkt, close_tcp))
792        return domain;
793
794    if ((dname = ldns_resolver_domain(res)) != NULL) {
795        dname = safe_dname_cat_clone(domain, dname);
796        if (query(res, dname, pkt, close_tcp))
797            return dname;
798    }
799
800    searchlist = ldns_resolver_searchlist(res);
801    n = ldns_resolver_searchlist_count(res);
802    for (i = 0; i < n; i++) {
803        dname = safe_dname_cat_clone(domain, searchlist[i]);
804        if (query(res, dname, pkt, close_tcp))
805            return dname;
806    }
807
808    if (!absolute && query(res, domain, pkt, close_tcp))
809        return domain;
810
811    return NULL;
812}
813
814static void
815report(ldns_resolver *res, ldns_rdf *domain, ldns_pkt *pkt) {
816    ldns_pkt_rcode rcode;
817
818    if (o_print_pkt_server) {
819        printf("Using domain server:\nName: %s\nAddress: ", o_server);
820        print_rdf(ldns_pkt_answerfrom(pkt));
821        printf("#%d\nAliases: \n\n", ldns_resolver_port(res));
822        o_print_pkt_server = false;
823    }
824    rcode = ldns_pkt_get_rcode(pkt);
825    if (rcode != LDNS_RCODE_NOERROR) {
826        printf("Host ");
827        print_rdf_nodot(domain);
828        printf(" not found: %d(", rcode);
829        print_rcode(rcode);
830        printf(")\n");
831    } else {
832        if (o_verbose) {
833            print_pkt_verbose(pkt);
834        } else {
835            print_pkt_short(pkt, o_print_rr_server);
836            if (o_mode == M_SINGLE_Q &&
837                ldns_rr_list_rr_count(ldns_pkt_answer(pkt)) == 0) {
838                print_rdf_nodot(domain);
839                printf(" has no ");
840                print_rr_type(o_rrtype);
841                printf(" record\n");
842            }
843        }
844    }
845    if (o_verbose)
846        print_received_line(res, pkt);
847}
848
849static bool
850doquery(ldns_resolver *res, ldns_rdf *domain) {
851    ldns_pkt *pkt;
852    bool q;
853
854    q = query(res, domain, &pkt, true);
855    report(res, domain, pkt);
856    return q;
857}
858
859static bool
860doquery_filtered(ldns_resolver *res, ldns_rdf *domain) {
861    ldns_pkt *pkt;
862    bool q;
863
864    q = query(res, domain, &pkt, true);
865    ldns_pkt_filter_answer(pkt, o_rrtype);
866    report(res, domain, pkt);
867    return q;
868}
869
870static bool
871dosearch(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
872    ldns_pkt *pkt;
873    ldns_rdf *dname;
874
875    dname = search(res, domain, &pkt, absolute, true);
876    report(res, dname != NULL ? dname : domain, pkt);
877    return o_mode != M_DEFAULT_Q ? (dname != NULL) :
878        (dname != NULL) &&
879        (o_rrtype = LDNS_RR_TYPE_AAAA, doquery_filtered(res, dname)) &&
880        (o_rrtype = LDNS_RR_TYPE_MX, doquery_filtered(res, dname));
881}
882
883static bool
884dozonetransfer(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
885    ldns_pkt *pkt, *nextpkt;
886    ldns_rdf *dname;
887    ldns_rr_type rrtype;
888    ldns_rr_list *rrl;
889    ldns_rr *rr;
890    size_t i, nsoa = 0;
891    uint32_t first_serial = 0;
892
893    rrtype = o_rrtype;
894    o_rrtype = (o_mode == M_AXFR) ? LDNS_RR_TYPE_AXFR : LDNS_RR_TYPE_IXFR;
895    dname = search(res, domain, &pkt, absolute, false);
896
897    for (;;) {
898        rrl = ldns_rr_list_clone(ldns_pkt_answer(pkt));
899        ldns_pkt_filter_answer(pkt, rrtype);
900        report(res, dname != NULL ? dname : domain, pkt);
901        if ((dname == NULL) ||
902                (ldns_pkt_get_rcode(pkt) != LDNS_RCODE_NOERROR)) {
903            printf("; Transfer failed.\n");
904            ldns_tcp_close(res);
905            return false;
906        }
907        for (i = 0; i < ldns_rr_list_rr_count(rrl); i++) {
908            rr = ldns_rr_list_rr(rrl, i);
909            if (nsoa == 0) {
910                if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_SOA) {
911                    printf("; Transfer failed. "
912                           "Didn't start with SOA answer.\n");
913                    ldns_tcp_close(res);
914                    return false;
915                }
916                first_serial = ldns_rr_soa_get_serial(rr);
917                if ((o_mode == M_IXFR) && (first_serial <= o_ixfr_serial)) {
918                    ldns_tcp_close(res);
919                    return true;
920                }
921            }
922            if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
923                nsoa = nsoa < 2 ? nsoa + 1 : 1;
924                if ((nsoa == 2) &&
925                        (ldns_rr_soa_get_serial(rr) == first_serial)) {
926                    ldns_tcp_close(res);
927                    return true;
928                }
929            }
930        }
931        if (ldns_tcp_read(&nextpkt, res) != LDNS_STATUS_OK) {
932            printf("; Transfer failed.\n");
933            return false;
934        }
935        ldns_pkt_set_answerfrom(nextpkt,
936                ldns_rdf_clone(ldns_pkt_answerfrom(pkt)));
937        ldns_pkt_free(pkt);
938        ldns_rr_list_free(rrl);
939        pkt = nextpkt;
940    }
941}
942
943static bool
944dosoa(ldns_resolver *res, ldns_rdf *domain, bool absolute) {
945    ldns_rr_list *answer, **nsaddrs;
946    ldns_rdf *dname, *addr;
947    ldns_pkt *pkt;
948    ldns_rr *rr;
949    size_t i, j, n, cnt;
950
951    if ((dname = search(res, domain, &pkt, absolute, true)) == NULL)
952        return false;
953
954    answer = ldns_pkt_answer(pkt);
955    cnt = ldns_rr_list_rr_count(answer);
956    nsaddrs = alloca(cnt*sizeof(*nsaddrs));
957    for (n = 0, i = 0; i < cnt; i++)
958        if ((addr = ldns_rr_ns_nsdname(ldns_rr_list_rr(answer, i))) != NULL)
959            nsaddrs[n++] = ldns_get_rr_list_addr_by_name(res,
960                addr, LDNS_RR_CLASS_IN, 0);
961
962    o_print_pkt_server = false;
963    o_recursive = false;
964    o_rrtype = LDNS_RR_TYPE_SOA;
965    for (i = 0; i < n; i++) {
966        cnt = ldns_rr_list_rr_count(nsaddrs[i]);
967        for (j = 0; j < cnt; j++) {
968            ldns_resolver_remove_nameservers(res);
969            rr = ldns_rr_list_rr(nsaddrs[i], j);
970            if ((ldns_resolver_ip6(res) == LDNS_RESOLV_INET &&
971                ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) ||
972                (ldns_resolver_ip6(res) == LDNS_RESOLV_INET6 &&
973                ldns_rr_get_type(rr) == LDNS_RR_TYPE_A))
974                continue;
975            if (ldns_resolver_push_nameserver_rr(res, rr) == LDNS_STATUS_OK)
976                /* bind9-host queries for domain, not dname here */
977                doquery(res, dname);
978        }
979    }
980    return 0;
981}
982
983static void
984resolver_set_nameserver_hostname(ldns_resolver *res, const char *server) {
985    struct addrinfo hints, *ailist, *ai;
986    ldns_status status;
987    ldns_rdf *rdf;
988    int err;
989
990    memset(&hints, 0, sizeof hints);
991    switch (ldns_resolver_ip6(res)) {
992    case LDNS_RESOLV_INET: hints.ai_family = PF_INET; break;
993    case LDNS_RESOLV_INET6: hints.ai_family = PF_INET6; break;
994    default: hints.ai_family = PF_UNSPEC; break;
995    }
996    hints.ai_socktype = SOCK_STREAM;
997    do err = getaddrinfo(server, NULL, &hints, &ailist);
998    while (err == EAI_AGAIN);
999    if (err != 0)
1000        die(1, "couldn't get address for '%s': %s", server, gai_strerror(err));
1001    for (ai = ailist; ai != NULL; ai = ai->ai_next) {
1002        if ((rdf = ldns_sockaddr_storage2rdf((void*)ai->ai_addr, NULL)) == NULL)
1003            die(1, "couldn't allocate an rdf: %s",
1004                ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
1005        status = ldns_resolver_push_nameserver(res, rdf);
1006        if (status != LDNS_STATUS_OK)
1007            die(1, "couldn't push a nameserver address: %s",
1008                ldns_get_errorstr_by_id(status));
1009    }
1010}
1011
1012static void
1013resolver_set_nameserver_str(ldns_resolver *res, const char *server) {
1014    ldns_rdf *addr;
1015
1016    ldns_resolver_remove_nameservers(res);
1017    addr = ldns_rdf_new_addr_frm_str(server);
1018    if (addr) {
1019        if (ldns_resolver_push_nameserver(res, addr) != LDNS_STATUS_OK)
1020            die(1, "couldn't push a nameserver address");
1021    } else
1022        resolver_set_nameserver_hostname(res, server);
1023}
1024
1025int
1026main(int argc, char *argv[]) {
1027    ldns_rdf *addr, *dname;
1028    ldns_resolver *res;
1029    ldns_status status;
1030    struct timeval restimeout;
1031
1032    parse_args(argc, argv);
1033
1034    status = ldns_resolver_new_default(&res);
1035    if (status != LDNS_STATUS_OK)
1036        die(1, "error creating resolver: %s", ldns_get_errorstr_by_id(status));
1037    if (ldns_resolver_nameserver_count(res) == 0)
1038        ldns_resolver_push_default_servers(res);
1039
1040    ldns_resolver_set_usevc(res, o_tcp);
1041    restimeout.tv_sec = o_timeout > 0 ? o_timeout :
1042        o_tcp ? DEFAULT_TCP_TIMEOUT : DEFAULT_UDP_TIMEOUT;
1043    restimeout.tv_usec = 0;
1044    ldns_resolver_set_timeout(res, restimeout);
1045    ldns_resolver_set_retry(res, o_retries+1);
1046    ldns_resolver_set_ip6(res, o_ipversion);
1047    ldns_resolver_set_defnames(res, false);
1048    ldns_resolver_set_fallback(res, false);
1049
1050    if (o_server)
1051        resolver_set_nameserver_str(res, o_server);
1052
1053    if (ldns_str2rdf_a(&addr, o_name) == LDNS_STATUS_OK) {
1054        dname = ldns_rdf_reverse_a(addr, "in-addr.arpa");
1055        if (dname == NULL)
1056            die(1, "can't reverse '%s': %s", o_name,
1057                ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
1058        o_mode = M_SINGLE_Q;
1059        o_rrtype = LDNS_RR_TYPE_PTR;
1060        return !doquery(res, dname);
1061    } else if (ldns_str2rdf_aaaa(&addr, o_name) == LDNS_STATUS_OK) {
1062        dname = ldns_rdf_reverse_aaaa(addr, o_ip6_int ? "ip6.int" : "ip6.arpa");
1063        if (dname == NULL)
1064            die(1, "can't reverse '%s': %s", o_name,
1065                ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
1066        o_mode = M_SINGLE_Q;
1067        o_rrtype = LDNS_RR_TYPE_PTR;
1068        return !doquery(res, dname);
1069    }
1070    return !(o_mode == M_SOA ? dosoa :
1071             o_mode == M_AXFR ? dozonetransfer :
1072             o_mode == M_IXFR ? dozonetransfer :
1073             dosearch)
1074        (res, safe_str2rdf_dname(o_name), ndots(o_name) >= o_ndots);
1075}
1076