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