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