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