]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ldns-host/ldns-host.c
Remove dead code.
[FreeBSD/FreeBSD.git] / contrib / ldns-host / ldns-host.c
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
21 static char *progname;
22
23 #define countof(array) (sizeof(array)/sizeof(*(array)))
24
25 static void
26 die(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
37 static int
38 ndots(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
48 static ldns_status
49 ldns_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
56 static ldns_status
57 ldns_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
72 static ldns_rdf *
73 ldns_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
81 static void
82 ldns_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
87 static ldns_rdf *
88 ldns_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
101 static ldns_rdf *
102 ldns_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
116 static ldns_status
117 ldns_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
154 memerr:
155     ldns_rr_free(rr);
156     return LDNS_STATUS_MEM_ERR;
157 }
158
159 static ldns_status
160 ldns_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  
202 error:
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
212 static ldns_status
213 ldns_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
240 error:
241     close(res->_socket);
242     res->_socket = 0;
243     return LDNS_STATUS_ERR;
244 }
245
246 static void
247 ldns_tcp_close(ldns_resolver *res) {
248     if (res->_socket > 0) {
249         close(res->_socket);
250         res->_socket = 0;
251     }
252 }
253
254 static ldns_status
255 ldns_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
302 done:
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
311 static void
312 ldns_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
338 static 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
358 static void
359 print_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
368 static void
369 print_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
378 static int
379 print_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
389 static int
390 print_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
400 static int
401 print_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
411 static int
412 print_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
423 static int
424 print_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
435 static void
436 print_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
460 static void
461 print_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
472 static void
473 print_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
503 static void
504 print_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
521 found:
522     for (i = 0; i < rdcnt; i++) {
523         printf(" ");
524         print_rdf(ldns_rr_rdf(rr, i));
525     }
526     printf("\n");
527 }
528
529 static void
530 print_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
544 static void
545 print_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
562 enum operation_mode { M_AXFR, M_IXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
563
564 static enum operation_mode o_mode = M_DEFAULT_Q;
565 static bool o_ignore_servfail = true;
566 static bool o_ip6_int = false;
567 static bool o_print_pkt_server = false;
568 static bool o_print_rr_server = false;
569 static bool o_recursive = true;
570 static bool o_tcp = false;
571 static bool o_verbose = false;
572 static char *o_name = NULL;
573 static char *o_server = NULL;
574 static int o_ipversion = LDNS_RESOLV_INETANY;
575 static int o_ndots = 1;
576 static int o_retries = 1;
577 static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
578 static ldns_rr_type o_rrtype = (ldns_rr_type)-1;
579 static time_t o_timeout = 0;
580 static uint32_t o_ixfr_serial = 0;
581
582 static void
583 usage(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
608 static void
609 parse_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
705 static ldns_rdf*
706 safe_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
717 static ldns_rdf*
718 safe_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
730 static bool
731 query(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
772 static ldns_rdf *
773 search(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
801 static void
802 report(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
836 static bool
837 doquery(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
846 static bool
847 doquery_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
857 static bool
858 dosearch(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
870 static bool
871 dozonetransfer(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
911 static bool
912 dosoa(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
951 static void
952 resolver_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
980 static void
981 resolver_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
993 int
994 main(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 }