1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 *
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of M.I.T. not be used in
10 * advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.
12 * M.I.T. makes no representations about the suitability of
13 * this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
15 */
16
17 #include "ares_setup.h"
18
19 #ifdef HAVE_NETINET_IN_H
20 # include <netinet/in.h>
21 #endif
22 #ifdef HAVE_ARPA_INET_H
23 # include <arpa/inet.h>
24 #endif
25 #ifdef HAVE_NETDB_H
26 # include <netdb.h>
27 #endif
28
29 #include "ares_nameser.h"
30
31 #ifdef HAVE_STRINGS_H
32 # include <strings.h>
33 #endif
34
35 #include "ares.h"
36 #include "ares_dns.h"
37 #include "ares_getopt.h"
38 #include "ares_nowarn.h"
39
40 #ifndef HAVE_STRDUP
41 # include "ares_strdup.h"
42 # define strdup(ptr) ares_strdup(ptr)
43 #endif
44
45 #ifndef HAVE_STRCASECMP
46 # include "ares_strcasecmp.h"
47 # define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
48 #endif
49
50 #ifndef HAVE_STRNCASECMP
51 # include "ares_strcasecmp.h"
52 # define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
53 #endif
54
55 #ifdef WATT32
56 #undef WIN32 /* Redefined in MingW headers */
57 #endif
58
59
60 struct nv {
61 const char *name;
62 int value;
63 };
64
65 static const struct nv flags[] = {
66 { "usevc", ARES_FLAG_USEVC },
67 { "primary", ARES_FLAG_PRIMARY },
68 { "igntc", ARES_FLAG_IGNTC },
69 { "norecurse", ARES_FLAG_NORECURSE },
70 { "stayopen", ARES_FLAG_STAYOPEN },
71 { "noaliases", ARES_FLAG_NOALIASES }
72 };
73 static const int nflags = sizeof(flags) / sizeof(flags[0]);
74
75 static const struct nv classes[] = {
76 { "IN", C_IN },
77 { "CHAOS", C_CHAOS },
78 { "HS", C_HS },
79 { "ANY", C_ANY }
80 };
81 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
82
83 static const struct nv types[] = {
84 { "A", T_A },
85 { "NS", T_NS },
86 { "MD", T_MD },
87 { "MF", T_MF },
88 { "CNAME", T_CNAME },
89 { "SOA", T_SOA },
90 { "MB", T_MB },
91 { "MG", T_MG },
92 { "MR", T_MR },
93 { "NULL", T_NULL },
94 { "WKS", T_WKS },
95 { "PTR", T_PTR },
96 { "HINFO", T_HINFO },
97 { "MINFO", T_MINFO },
98 { "MX", T_MX },
99 { "TXT", T_TXT },
100 { "RP", T_RP },
101 { "AFSDB", T_AFSDB },
102 { "X25", T_X25 },
103 { "ISDN", T_ISDN },
104 { "RT", T_RT },
105 { "NSAP", T_NSAP },
106 { "NSAP_PTR", T_NSAP_PTR },
107 { "SIG", T_SIG },
108 { "KEY", T_KEY },
109 { "PX", T_PX },
110 { "GPOS", T_GPOS },
111 { "AAAA", T_AAAA },
112 { "LOC", T_LOC },
113 { "SRV", T_SRV },
114 { "AXFR", T_AXFR },
115 { "MAILB", T_MAILB },
116 { "MAILA", T_MAILA },
117 { "NAPTR", T_NAPTR },
118 { "DS", T_DS },
119 { "SSHFP", T_SSHFP },
120 { "RRSIG", T_RRSIG },
121 { "NSEC", T_NSEC },
122 { "DNSKEY", T_DNSKEY },
123 { "CAA", T_CAA },
124 { "URI", T_URI },
125 { "ANY", T_ANY }
126 };
127 static const int ntypes = sizeof(types) / sizeof(types[0]);
128
129 static const char *opcodes[] = {
130 "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
131 "(unknown)", "(unknown)", "(unknown)", "(unknown)",
132 "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
133 "ZONEINIT", "ZONEREF"
134 };
135
136 static const char *rcodes[] = {
137 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
138 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
139 "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
140 };
141
142 static void callback(void *arg, int status, int timeouts,
143 unsigned char *abuf, int alen);
144 static const unsigned char *display_question(const unsigned char *aptr,
145 const unsigned char *abuf,
146 int alen);
147 static const unsigned char *display_rr(const unsigned char *aptr,
148 const unsigned char *abuf, int alen);
149 static int convert_query (char **name, int use_bitstring);
150 static const char *type_name(int type);
151 static const char *class_name(int dnsclass);
152 static void usage(void);
153 static void destroy_addr_list(struct ares_addr_node *head);
154 static void append_addr_list(struct ares_addr_node **head,
155 struct ares_addr_node *node);
156 static void print_help_info_adig(void);
157
main(int argc,char ** argv)158 int main(int argc, char **argv)
159 {
160 ares_channel channel;
161 int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
162 int status, nfds, count;
163 int use_ptr_helper = 0;
164 struct ares_options options;
165 struct hostent *hostent;
166 fd_set read_fds, write_fds;
167 struct timeval *tvp, tv;
168 struct ares_addr_node *srvr, *servers = NULL;
169
170 #ifdef USE_WINSOCK
171 WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
172 WSADATA wsaData;
173 WSAStartup(wVersionRequested, &wsaData);
174 #endif
175
176 status = ares_library_init(ARES_LIB_INIT_ALL);
177 if (status != ARES_SUCCESS)
178 {
179 fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status));
180 return 1;
181 }
182
183 options.flags = ARES_FLAG_NOCHECKRESP;
184 options.servers = NULL;
185 options.nservers = 0;
186 while ((c = ares_getopt(argc, argv, "dh?f:s:c:t:T:U:x")) != -1)
187 {
188 switch (c)
189 {
190 case 'd':
191 #ifdef WATT32
192 dbug_init();
193 #endif
194 break;
195 case 'h':
196 print_help_info_adig();
197 break;
198 case '?':
199 print_help_info_adig();
200 break;
201 case 'f':
202 /* Add a flag. */
203 for (i = 0; i < nflags; i++)
204 {
205 if (strcmp(flags[i].name, optarg) == 0)
206 break;
207 }
208 if (i < nflags)
209 options.flags |= flags[i].value;
210 else
211 usage();
212 break;
213
214 case 's':
215 /* User-specified name servers override default ones. */
216 srvr = malloc(sizeof(struct ares_addr_node));
217 if (!srvr)
218 {
219 fprintf(stderr, "Out of memory!\n");
220 destroy_addr_list(servers);
221 return 1;
222 }
223 append_addr_list(&servers, srvr);
224 if (ares_inet_pton(AF_INET, optarg, &srvr->addr.addr4) > 0)
225 srvr->family = AF_INET;
226 else if (ares_inet_pton(AF_INET6, optarg, &srvr->addr.addr6) > 0)
227 srvr->family = AF_INET6;
228 else
229 {
230 hostent = gethostbyname(optarg);
231 if (!hostent)
232 {
233 fprintf(stderr, "adig: server %s not found.\n", optarg);
234 destroy_addr_list(servers);
235 return 1;
236 }
237 switch (hostent->h_addrtype)
238 {
239 case AF_INET:
240 srvr->family = AF_INET;
241 memcpy(&srvr->addr.addr4, hostent->h_addr,
242 sizeof(srvr->addr.addr4));
243 break;
244 case AF_INET6:
245 srvr->family = AF_INET6;
246 memcpy(&srvr->addr.addr6, hostent->h_addr,
247 sizeof(srvr->addr.addr6));
248 break;
249 default:
250 fprintf(stderr,
251 "adig: server %s unsupported address family.\n", optarg);
252 destroy_addr_list(servers);
253 return 1;
254 }
255 }
256 /* Notice that calling ares_init_options() without servers in the
257 * options struct and with ARES_OPT_SERVERS set simultaneously in
258 * the options mask, results in an initialization with no servers.
259 * When alternative name servers have been specified these are set
260 * later calling ares_set_servers() overriding any existing server
261 * configuration. To prevent initial configuration with default
262 * servers that will be discarded later, ARES_OPT_SERVERS is set.
263 * If this flag is not set here the result shall be the same but
264 * ares_init_options() will do needless work. */
265 optmask |= ARES_OPT_SERVERS;
266 break;
267
268 case 'c':
269 /* Set the query class. */
270 for (i = 0; i < nclasses; i++)
271 {
272 if (strcasecmp(classes[i].name, optarg) == 0)
273 break;
274 }
275 if (i < nclasses)
276 dnsclass = classes[i].value;
277 else
278 usage();
279 break;
280
281 case 't':
282 /* Set the query type. */
283 for (i = 0; i < ntypes; i++)
284 {
285 if (strcasecmp(types[i].name, optarg) == 0)
286 break;
287 }
288 if (i < ntypes)
289 type = types[i].value;
290 else
291 usage();
292 break;
293
294 case 'T':
295 /* Set the TCP port number. */
296 if (!ISDIGIT(*optarg))
297 usage();
298 options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
299 options.flags |= ARES_FLAG_USEVC;
300 optmask |= ARES_OPT_TCP_PORT;
301 break;
302
303 case 'U':
304 /* Set the UDP port number. */
305 if (!ISDIGIT(*optarg))
306 usage();
307 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
308 optmask |= ARES_OPT_UDP_PORT;
309 break;
310
311 case 'x':
312 use_ptr_helper++;
313 break;
314 }
315 }
316 argc -= optind;
317 argv += optind;
318 if (argc == 0)
319 usage();
320
321 status = ares_init_options(&channel, &options, optmask);
322
323 if (status != ARES_SUCCESS)
324 {
325 fprintf(stderr, "ares_init_options: %s\n",
326 ares_strerror(status));
327 return 1;
328 }
329
330 if(servers)
331 {
332 status = ares_set_servers(channel, servers);
333 destroy_addr_list(servers);
334 if (status != ARES_SUCCESS)
335 {
336 fprintf(stderr, "ares_init_options: %s\n",
337 ares_strerror(status));
338 return 1;
339 }
340 }
341
342 /* Initiate the queries, one per command-line argument. If there is
343 * only one query to do, supply NULL as the callback argument;
344 * otherwise, supply the query name as an argument so we can
345 * distinguish responses for the user when printing them out.
346 */
347 for (i = 1; *argv; i++, argv++)
348 {
349 char *query = *argv;
350
351 if (type == T_PTR && dnsclass == C_IN && use_ptr_helper)
352 if (!convert_query (&query, use_ptr_helper >= 2))
353 continue;
354
355 ares_query(channel, query, dnsclass, type, callback, i < argc-1 ? (void*)query : NULL);
356 }
357
358 /* Wait for all queries to complete. */
359 for (;;)
360 {
361 FD_ZERO(&read_fds);
362 FD_ZERO(&write_fds);
363 nfds = ares_fds(channel, &read_fds, &write_fds);
364 if (nfds == 0)
365 break;
366 tvp = ares_timeout(channel, NULL, &tv);
367 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
368 if (count < 0 && (status = SOCKERRNO) != EINVAL)
369 {
370 printf("select fail: %d", status);
371 return 1;
372 }
373 ares_process(channel, &read_fds, &write_fds);
374 }
375
376 ares_destroy(channel);
377
378 ares_library_cleanup();
379
380 #ifdef USE_WINSOCK
381 WSACleanup();
382 #endif
383
384 return 0;
385 }
386
callback(void * arg,int status,int timeouts,unsigned char * abuf,int alen)387 static void callback(void *arg, int status, int timeouts,
388 unsigned char *abuf, int alen)
389 {
390 char *name = (char *) arg;
391 int id, qr, opcode, aa, tc, rd, ra, rcode;
392 unsigned int qdcount, ancount, nscount, arcount, i;
393 const unsigned char *aptr;
394
395 (void) timeouts;
396
397 /* Display the query name if given. */
398 if (name)
399 printf("Answer for query %s:\n", name);
400
401 /* Display an error message if there was an error, but only stop if
402 * we actually didn't get an answer buffer.
403 */
404 if (status != ARES_SUCCESS)
405 {
406 printf("%s\n", ares_strerror(status));
407 if (!abuf)
408 return;
409 }
410
411 /* Won't happen, but check anyway, for safety. */
412 if (alen < HFIXEDSZ)
413 return;
414
415 /* Parse the answer header. */
416 id = DNS_HEADER_QID(abuf);
417 qr = DNS_HEADER_QR(abuf);
418 opcode = DNS_HEADER_OPCODE(abuf);
419 aa = DNS_HEADER_AA(abuf);
420 tc = DNS_HEADER_TC(abuf);
421 rd = DNS_HEADER_RD(abuf);
422 ra = DNS_HEADER_RA(abuf);
423 rcode = DNS_HEADER_RCODE(abuf);
424 qdcount = DNS_HEADER_QDCOUNT(abuf);
425 ancount = DNS_HEADER_ANCOUNT(abuf);
426 nscount = DNS_HEADER_NSCOUNT(abuf);
427 arcount = DNS_HEADER_ARCOUNT(abuf);
428
429 /* Display the answer header. */
430 printf("id: %d\n", id);
431 printf("flags: %s%s%s%s%s\n",
432 qr ? "qr " : "",
433 aa ? "aa " : "",
434 tc ? "tc " : "",
435 rd ? "rd " : "",
436 ra ? "ra " : "");
437 printf("opcode: %s\n", opcodes[opcode]);
438 printf("rcode: %s\n", rcodes[rcode]);
439
440 /* Display the questions. */
441 printf("Questions:\n");
442 aptr = abuf + HFIXEDSZ;
443 for (i = 0; i < qdcount; i++)
444 {
445 aptr = display_question(aptr, abuf, alen);
446 if (aptr == NULL)
447 return;
448 }
449
450 /* Display the answers. */
451 printf("Answers:\n");
452 for (i = 0; i < ancount; i++)
453 {
454 aptr = display_rr(aptr, abuf, alen);
455 if (aptr == NULL)
456 return;
457 }
458
459 /* Display the NS records. */
460 printf("NS records:\n");
461 for (i = 0; i < nscount; i++)
462 {
463 aptr = display_rr(aptr, abuf, alen);
464 if (aptr == NULL)
465 return;
466 }
467
468 /* Display the additional records. */
469 printf("Additional records:\n");
470 for (i = 0; i < arcount; i++)
471 {
472 aptr = display_rr(aptr, abuf, alen);
473 if (aptr == NULL)
474 return;
475 }
476 }
477
display_question(const unsigned char * aptr,const unsigned char * abuf,int alen)478 static const unsigned char *display_question(const unsigned char *aptr,
479 const unsigned char *abuf,
480 int alen)
481 {
482 char *name;
483 int type, dnsclass, status;
484 long len;
485
486 /* Parse the question name. */
487 status = ares_expand_name(aptr, abuf, alen, &name, &len);
488 if (status != ARES_SUCCESS)
489 return NULL;
490 aptr += len;
491
492 /* Make sure there's enough data after the name for the fixed part
493 * of the question.
494 */
495 if (aptr + QFIXEDSZ > abuf + alen)
496 {
497 ares_free_string(name);
498 return NULL;
499 }
500
501 /* Parse the question type and class. */
502 type = DNS_QUESTION_TYPE(aptr);
503 dnsclass = DNS_QUESTION_CLASS(aptr);
504 aptr += QFIXEDSZ;
505
506 /* Display the question, in a format sort of similar to how we will
507 * display RRs.
508 */
509 printf("\t%-15s.\t", name);
510 if (dnsclass != C_IN)
511 printf("\t%s", class_name(dnsclass));
512 printf("\t%s\n", type_name(type));
513 ares_free_string(name);
514 return aptr;
515 }
516
display_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)517 static const unsigned char *display_rr(const unsigned char *aptr,
518 const unsigned char *abuf, int alen)
519 {
520 const unsigned char *p;
521 int type, dnsclass, ttl, dlen, status, i;
522 long len;
523 int vlen;
524 char addr[46];
525 union {
526 unsigned char * as_uchar;
527 char * as_char;
528 } name;
529
530 /* Parse the RR name. */
531 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
532 if (status != ARES_SUCCESS)
533 return NULL;
534 aptr += len;
535
536 /* Make sure there is enough data after the RR name for the fixed
537 * part of the RR.
538 */
539 if (aptr + RRFIXEDSZ > abuf + alen)
540 {
541 ares_free_string(name.as_char);
542 return NULL;
543 }
544
545 /* Parse the fixed part of the RR, and advance to the RR data
546 * field. */
547 type = DNS_RR_TYPE(aptr);
548 dnsclass = DNS_RR_CLASS(aptr);
549 ttl = DNS_RR_TTL(aptr);
550 dlen = DNS_RR_LEN(aptr);
551 aptr += RRFIXEDSZ;
552 if (aptr + dlen > abuf + alen)
553 {
554 ares_free_string(name.as_char);
555 return NULL;
556 }
557
558 /* Display the RR name, class, and type. */
559 printf("\t%-15s.\t%d", name.as_char, ttl);
560 if (dnsclass != C_IN)
561 printf("\t%s", class_name(dnsclass));
562 printf("\t%s", type_name(type));
563 ares_free_string(name.as_char);
564
565 /* Display the RR data. Don't touch aptr. */
566 switch (type)
567 {
568 case T_CNAME:
569 case T_MB:
570 case T_MD:
571 case T_MF:
572 case T_MG:
573 case T_MR:
574 case T_NS:
575 case T_PTR:
576 /* For these types, the RR data is just a domain name. */
577 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
578 if (status != ARES_SUCCESS)
579 return NULL;
580 printf("\t%s.", name.as_char);
581 ares_free_string(name.as_char);
582 break;
583
584 case T_HINFO:
585 /* The RR data is two length-counted character strings. */
586 p = aptr;
587 len = *p;
588 if (p + len + 1 > aptr + dlen)
589 return NULL;
590 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
591 if (status != ARES_SUCCESS)
592 return NULL;
593 printf("\t%s", name.as_char);
594 ares_free_string(name.as_char);
595 p += len;
596 len = *p;
597 if (p + len + 1 > aptr + dlen)
598 return NULL;
599 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
600 if (status != ARES_SUCCESS)
601 return NULL;
602 printf("\t%s", name.as_char);
603 ares_free_string(name.as_char);
604 break;
605
606 case T_MINFO:
607 /* The RR data is two domain names. */
608 p = aptr;
609 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
610 if (status != ARES_SUCCESS)
611 return NULL;
612 printf("\t%s.", name.as_char);
613 ares_free_string(name.as_char);
614 p += len;
615 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
616 if (status != ARES_SUCCESS)
617 return NULL;
618 printf("\t%s.", name.as_char);
619 ares_free_string(name.as_char);
620 break;
621
622 case T_MX:
623 /* The RR data is two bytes giving a preference ordering, and
624 * then a domain name.
625 */
626 if (dlen < 2)
627 return NULL;
628 printf("\t%d", (int)DNS__16BIT(aptr));
629 status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
630 if (status != ARES_SUCCESS)
631 return NULL;
632 printf("\t%s.", name.as_char);
633 ares_free_string(name.as_char);
634 break;
635
636 case T_SOA:
637 /* The RR data is two domain names and then five four-byte
638 * numbers giving the serial number and some timeouts.
639 */
640 p = aptr;
641 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
642 if (status != ARES_SUCCESS)
643 return NULL;
644 printf("\t%s.\n", name.as_char);
645 ares_free_string(name.as_char);
646 p += len;
647 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
648 if (status != ARES_SUCCESS)
649 return NULL;
650 printf("\t\t\t\t\t\t%s.\n", name.as_char);
651 ares_free_string(name.as_char);
652 p += len;
653 if (p + 20 > aptr + dlen)
654 return NULL;
655 printf("\t\t\t\t\t\t( %u %u %u %u %u )",
656 DNS__32BIT(p), DNS__32BIT(p+4),
657 DNS__32BIT(p+8), DNS__32BIT(p+12),
658 DNS__32BIT(p+16));
659 break;
660
661 case T_TXT:
662 /* The RR data is one or more length-counted character
663 * strings. */
664 p = aptr;
665 while (p < aptr + dlen)
666 {
667 len = *p;
668 if (p + len + 1 > aptr + dlen)
669 return NULL;
670 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
671 if (status != ARES_SUCCESS)
672 return NULL;
673 printf("\t%s", name.as_char);
674 ares_free_string(name.as_char);
675 p += len;
676 }
677 break;
678
679 case T_CAA:
680
681 p = aptr;
682
683 /* Flags */
684 printf(" %u", (int)*p);
685 p += 1;
686
687 /* Remainder of record */
688 vlen = (int)dlen - ((char)*p) - 2;
689
690 /* The Property identifier, one of:
691 - "issue",
692 - "iodef", or
693 - "issuewild" */
694 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
695 if (status != ARES_SUCCESS)
696 return NULL;
697 printf(" %s", name.as_char);
698 ares_free_string(name.as_char);
699 p += len;
700
701 if (p + vlen > abuf + alen)
702 return NULL;
703
704 /* A sequence of octets representing the Property Value */
705 printf(" %.*s", vlen, p);
706 break;
707
708 case T_A:
709 /* The RR data is a four-byte Internet address. */
710 if (dlen != 4)
711 return NULL;
712 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
713 break;
714
715 case T_AAAA:
716 /* The RR data is a 16-byte IPv6 address. */
717 if (dlen != 16)
718 return NULL;
719 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
720 break;
721
722 case T_WKS:
723 /* Not implemented yet */
724 break;
725
726 case T_SRV:
727 /* The RR data is three two-byte numbers representing the
728 * priority, weight, and port, followed by a domain name.
729 */
730
731 printf("\t%d", (int)DNS__16BIT(aptr));
732 printf(" %d", (int)DNS__16BIT(aptr + 2));
733 printf(" %d", (int)DNS__16BIT(aptr + 4));
734
735 status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
736 if (status != ARES_SUCCESS)
737 return NULL;
738 printf("\t%s.", name.as_char);
739 ares_free_string(name.as_char);
740 break;
741
742 case T_URI:
743 /* The RR data is two two-byte numbers representing the
744 * priority and weight, followed by a target.
745 */
746
747 printf("\t%d ", (int)DNS__16BIT(aptr));
748 printf("%d \t\t", (int)DNS__16BIT(aptr+2));
749 p = aptr +4;
750 for (i=0; i <dlen-4; ++i)
751 printf("%c",p[i]);
752 break;
753
754 case T_NAPTR:
755
756 printf("\t%d", (int)DNS__16BIT(aptr)); /* order */
757 printf(" %d\n", (int)DNS__16BIT(aptr + 2)); /* preference */
758
759 p = aptr + 4;
760 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
761 if (status != ARES_SUCCESS)
762 return NULL;
763 printf("\t\t\t\t\t\t%s\n", name.as_char);
764 ares_free_string(name.as_char);
765 p += len;
766
767 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
768 if (status != ARES_SUCCESS)
769 return NULL;
770 printf("\t\t\t\t\t\t%s\n", name.as_char);
771 ares_free_string(name.as_char);
772 p += len;
773
774 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
775 if (status != ARES_SUCCESS)
776 return NULL;
777 printf("\t\t\t\t\t\t%s\n", name.as_char);
778 ares_free_string(name.as_char);
779 p += len;
780
781 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
782 if (status != ARES_SUCCESS)
783 return NULL;
784 printf("\t\t\t\t\t\t%s", name.as_char);
785 ares_free_string(name.as_char);
786 break;
787
788 case T_DS:
789 case T_SSHFP:
790 case T_RRSIG:
791 case T_NSEC:
792 case T_DNSKEY:
793 printf("\t[RR type parsing unavailable]");
794 break;
795
796 default:
797 printf("\t[Unknown RR; cannot parse]");
798 break;
799 }
800 printf("\n");
801
802 return aptr + dlen;
803 }
804
805 /*
806 * With the '-x' (or '-xx') and '-t PTR' options, convert a query for an
807 * address into a more useful 'T_PTR' type question.
808 * Like with an input 'query':
809 * "a.b.c.d" -> "d.c.b.a".in-addr.arpa" for an IPv4 address.
810 * "a.b.c....x.y.z" -> "z.y.x....c.d.e.IP6.ARPA" for an IPv6 address.
811 *
812 * An example from 'dig -x PTR 2001:470:1:1b9::31':
813 *
814 * QUESTION SECTION:
815 * 1.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.b.1.0.1.0.0.0.0.7.4.0.1.0.0.2.IP6.ARPA. IN PTR
816 *
817 * ANSWER SECTION:
818 * 1.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.9.b.1.0.1.0.0.0.0.7.4.0.1.0.0.2.IP6.ARPA. 254148 IN PTR ipv6.cybernode.com.
819 *
820 * If 'use_bitstring == 1', try to use the more compact RFC-2673 bitstring format.
821 * Thus the above 'dig' query should become:
822 * [x13000000000000009b10100007401002].IP6.ARPA. IN PTR
823 */
convert_query(char ** name_p,int use_bitstring)824 static int convert_query (char **name_p, int use_bitstring)
825 {
826 #ifndef MAX_IP6_RR
827 #define MAX_IP6_RR (16*sizeof(".x.x") + sizeof(".IP6.ARPA") + 1)
828 #endif
829
830 #ifdef HAVE_INET_PTON
831 #define ACCEPTED_RETVAL4 1
832 #define ACCEPTED_RETVAL6 1
833 #else
834 #define ACCEPTED_RETVAL4 32
835 #define ACCEPTED_RETVAL6 128
836 #endif
837
838 static char new_name [MAX_IP6_RR];
839 static const char hex_chars[] = "0123456789ABCDEF";
840
841 union {
842 struct in_addr addr4;
843 struct ares_in6_addr addr6;
844 } addr;
845
846 if (ares_inet_pton (AF_INET, *name_p, &addr.addr4) == 1)
847 {
848 unsigned long laddr = ntohl(addr.addr4.s_addr);
849 unsigned long a1 = (laddr >> 24UL) & 0xFFUL;
850 unsigned long a2 = (laddr >> 16UL) & 0xFFUL;
851 unsigned long a3 = (laddr >> 8UL) & 0xFFUL;
852 unsigned long a4 = laddr & 0xFFUL;
853
854 snprintf(new_name, sizeof(new_name), "%lu.%lu.%lu.%lu.in-addr.arpa", a4, a3, a2, a1);
855 *name_p = new_name;
856 return (1);
857 }
858
859 if (ares_inet_pton(AF_INET6, *name_p, &addr.addr6) == 1)
860 {
861 char *c = new_name;
862 const unsigned char *ip = (const unsigned char*) &addr.addr6;
863 int max_i = (int)sizeof(addr.addr6) - 1;
864 int i, hi, lo;
865
866 /* Use the more compact RFC-2673 notation?
867 * Currently doesn't work or unsupported by the DNS-servers I've tested against.
868 */
869 if (use_bitstring)
870 {
871 *c++ = '\\';
872 *c++ = '[';
873 *c++ = 'x';
874 for (i = max_i; i >= 0; i--)
875 {
876 hi = ip[i] >> 4;
877 lo = ip[i] & 15;
878 *c++ = hex_chars [lo];
879 *c++ = hex_chars [hi];
880 }
881 strcpy (c, "].IP6.ARPA");
882 }
883 else
884 {
885 for (i = max_i; i >= 0; i--)
886 {
887 hi = ip[i] >> 4;
888 lo = ip[i] & 15;
889 *c++ = hex_chars [lo];
890 *c++ = '.';
891 *c++ = hex_chars [hi];
892 *c++ = '.';
893 }
894 strcpy (c, "IP6.ARPA");
895 }
896 *name_p = new_name;
897 return (1);
898 }
899 printf("Address %s was not legal for this query.\n", *name_p);
900 return (0);
901 }
902
type_name(int type)903 static const char *type_name(int type)
904 {
905 int i;
906
907 for (i = 0; i < ntypes; i++)
908 {
909 if (types[i].value == type)
910 return types[i].name;
911 }
912 return "(unknown)";
913 }
914
class_name(int dnsclass)915 static const char *class_name(int dnsclass)
916 {
917 int i;
918
919 for (i = 0; i < nclasses; i++)
920 {
921 if (classes[i].value == dnsclass)
922 return classes[i].name;
923 }
924 return "(unknown)";
925 }
926
usage(void)927 static void usage(void)
928 {
929 fprintf(stderr, "usage: adig [-h] [-d] [-f flag] [-s server] [-c class] "
930 "[-t type] [-T|U port] [-x|-xx] name ...\n");
931 exit(1);
932 }
933
destroy_addr_list(struct ares_addr_node * head)934 static void destroy_addr_list(struct ares_addr_node *head)
935 {
936 while(head)
937 {
938 struct ares_addr_node *detached = head;
939 head = head->next;
940 free(detached);
941 }
942 }
943
append_addr_list(struct ares_addr_node ** head,struct ares_addr_node * node)944 static void append_addr_list(struct ares_addr_node **head,
945 struct ares_addr_node *node)
946 {
947 struct ares_addr_node *last;
948 node->next = NULL;
949 if(*head)
950 {
951 last = *head;
952 while(last->next)
953 last = last->next;
954 last->next = node;
955 }
956 else
957 *head = node;
958 }
959
960
961 /* Information from the man page. Formatting taken from man -h */
print_help_info_adig(void)962 static void print_help_info_adig(void) {
963 printf("adig, version %s\n\n", ARES_VERSION_STR);
964 printf("usage: adig [-h] [-d] [-f flag] [[-s server] ...] [-T|U port] [-c class] [-t type] [-x|-xx] name ...\n\n"
965 " h : Display this help and exit.\n"
966 " d : Print some extra debugging output.\n\n"
967 " f flag : Add a behavior control flag. Possible values are\n"
968 " igntc - ignore to query in TCP to get truncated UDP answer,\n"
969 " noaliases - don't honor the HOSTALIASES environment variable,\n"
970 " norecurse - don't query upstream servers recursively,\n"
971 " primary - use the first server,\n"
972 " stayopen - don't close the communication sockets, and\n"
973 " usevc - use TCP only.\n"
974 " s server : Connect to the specified DNS server, instead of the system's default one(s).\n"
975 " Servers are tried in round-robin, if the previous one failed.\n"
976 " T port : Connect to the specified TCP port of DNS server.\n"
977 " U port : Connect to the specified UDP port of DNS server.\n"
978 " c class : Set the query class. Possible values for class are ANY, CHAOS, HS and IN (default)\n"
979 " t type : Query records of the specified type.\n"
980 " Possible values for type are A (default), AAAA, AFSDB, ANY, AXFR,\n"
981 " CNAME, GPOS, HINFO, ISDN, KEY, LOC, MAILA, MAILB, MB, MD, MF, MG,\n"
982 " MINFO, MR, MX, NAPTR, NS, NSAP, NSAP_PTR, NULL, PTR, PX, RP, RT,\n"
983 " SIG, SOA, SRV, TXT, URI, WKS and X25.\n\n"
984 " -x : For a '-t PTR a.b.c.d' lookup, query for 'd.c.b.a.in-addr.arpa.'\n"
985 " -xx : As above, but for IPv6, compact the format into a bitstring like\n"
986 " '[xabcdef00000000000000000000000000].IP6.ARPA.'\n");
987 exit(0);
988 }
989