ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/vendor/ldns-host/dist/ldns-host.c
Revision: 11597
Committed: Sun Jul 8 16:01:51 2018 UTC (5 years, 9 months ago) by laffer1
Content type: text/plain
File size: 26638 byte(s)
Log Message:
import ldns-host

File Contents

# Content
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
23 static char *progname;
24
25 #define countof(array) (sizeof(array)/sizeof(*(array)))
26
27 static void
28 die(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
39 static int
40 ndots(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
50 static ldns_status
51 ldns_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
58 static ldns_status
59 ldns_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
74 static ldns_rdf *
75 ldns_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
83 static void
84 ldns_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
89 static ldns_rdf *
90 ldns_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
103 static ldns_rdf *
104 ldns_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
118 static ldns_status
119 ldns_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
156 memerr:
157 ldns_rr_free(rr);
158 return LDNS_STATUS_MEM_ERR;
159 }
160
161 static ldns_status
162 ldns_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
190 static void
191 ldns_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
217 static 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
237 static void
238 print_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
247 static void
248 print_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
257 static int
258 print_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
268 static int
269 print_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
279 static int
280 print_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
290 static int
291 print_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
302 static int
303 print_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
314 static void
315 print_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
339 static void
340 print_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
351 static void
352 print_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
382 static void
383 print_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
400 found:
401 for (i = 0; i < rdcnt; i++) {
402 printf(" ");
403 print_rdf(ldns_rr_rdf(rr, i));
404 }
405 printf("\n");
406 }
407
408 static void
409 print_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
423 static void
424 print_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
441 enum operation_mode { M_AXFR, M_DEFAULT_Q, M_SINGLE_Q, M_SOA };
442
443 static enum operation_mode o_mode = M_DEFAULT_Q;
444 static bool o_ignore_servfail = true;
445 static bool o_ip6_int = false;
446 static bool o_print_pkt_server = false;
447 static bool o_print_rr_server = false;
448 static bool o_recursive = true;
449 static bool o_tcp = false;
450 static bool o_verbose = false;
451 static char *o_name = NULL;
452 static char *o_server = NULL;
453 static int o_ipversion = LDNS_RESOLV_INETANY;
454 static int o_ndots = 1;
455 static int o_retries = 1;
456 static ldns_rr_class o_rrclass = LDNS_RR_CLASS_IN;
457 static ldns_rr_type o_rrtype = LDNS_RR_TYPE_A;
458 static time_t o_timeout = 0;
459 static uint32_t o_ixfr_serial = 0;
460
461 static void
462 usage(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
487 static void
488 parse_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
579 static ldns_rdf*
580 safe_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
591 static ldns_rdf*
592 safe_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
604 static bool
605 query(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
644 static ldns_rdf *
645 search(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
672 static void
673 report(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
707 static bool
708 doquery(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
717 static bool
718 doquery_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
728 static bool
729 dosearch(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
741 static bool
742 doaxfr(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
755 static bool
756 dosoa(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
795 static void
796 resolver_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
824 static void
825 resolver_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
837 int
838 main(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 }