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 optmask |= ARES_OPT_TCP_PORT;
300 break;
301
302 case 'U':
303 /* Set the UDP port number. */
304 if (!ISDIGIT(*optarg))
305 usage();
306 options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
307 optmask |= ARES_OPT_UDP_PORT;
308 break;
309
310 case 'x':
311 use_ptr_helper++;
312 break;
313 }
314 }
315 argc -= optind;
316 argv += optind;
317 if (argc == 0)
318 usage();
319
320 status = ares_init_options(&channel, &options, optmask);
321
322 if (status != ARES_SUCCESS)
323 {
324 fprintf(stderr, "ares_init_options: %s\n",
325 ares_strerror(status));
326 return 1;
327 }
328
329 if(servers)
330 {
331 status = ares_set_servers(channel, servers);
332 destroy_addr_list(servers);
333 if (status != ARES_SUCCESS)
334 {
335 fprintf(stderr, "ares_init_options: %s\n",
336 ares_strerror(status));
337 return 1;
338 }
339 }
340
341 /* Initiate the queries, one per command-line argument. If there is
342 * only one query to do, supply NULL as the callback argument;
343 * otherwise, supply the query name as an argument so we can
344 * distinguish responses for the user when printing them out.
345 */
346 for (i = 1; *argv; i++, argv++)
347 {
348 char *query = *argv;
349
350 if (type == T_PTR && dnsclass == C_IN && use_ptr_helper)
351 if (!convert_query (&query, use_ptr_helper >= 2))
352 continue;
353
354 ares_query(channel, query, dnsclass, type, callback, i < argc-1 ? (void*)query : NULL);
355 }
356
357 /* Wait for all queries to complete. */
358 for (;;)
359 {
360 FD_ZERO(&read_fds);
361 FD_ZERO(&write_fds);
362 nfds = ares_fds(channel, &read_fds, &write_fds);
363 if (nfds == 0)
364 break;
365 tvp = ares_timeout(channel, NULL, &tv);
366 count = select(nfds, &read_fds, &write_fds, NULL, tvp);
367 if (count < 0 && (status = SOCKERRNO) != EINVAL)
368 {
369 printf("select fail: %d", status);
370 return 1;
371 }
372 ares_process(channel, &read_fds, &write_fds);
373 }
374
375 ares_destroy(channel);
376
377 ares_library_cleanup();
378
379 #ifdef USE_WINSOCK
380 WSACleanup();
381 #endif
382
383 return 0;
384 }
385
callback(void * arg,int status,int timeouts,unsigned char * abuf,int alen)386 static void callback(void *arg, int status, int timeouts,
387 unsigned char *abuf, int alen)
388 {
389 char *name = (char *) arg;
390 int id, qr, opcode, aa, tc, rd, ra, rcode;
391 unsigned int qdcount, ancount, nscount, arcount, i;
392 const unsigned char *aptr;
393
394 (void) timeouts;
395
396 /* Display the query name if given. */
397 if (name)
398 printf("Answer for query %s:\n", name);
399
400 /* Display an error message if there was an error, but only stop if
401 * we actually didn't get an answer buffer.
402 */
403 if (status != ARES_SUCCESS)
404 {
405 printf("%s\n", ares_strerror(status));
406 if (!abuf)
407 return;
408 }
409
410 /* Won't happen, but check anyway, for safety. */
411 if (alen < HFIXEDSZ)
412 return;
413
414 /* Parse the answer header. */
415 id = DNS_HEADER_QID(abuf);
416 qr = DNS_HEADER_QR(abuf);
417 opcode = DNS_HEADER_OPCODE(abuf);
418 aa = DNS_HEADER_AA(abuf);
419 tc = DNS_HEADER_TC(abuf);
420 rd = DNS_HEADER_RD(abuf);
421 ra = DNS_HEADER_RA(abuf);
422 rcode = DNS_HEADER_RCODE(abuf);
423 qdcount = DNS_HEADER_QDCOUNT(abuf);
424 ancount = DNS_HEADER_ANCOUNT(abuf);
425 nscount = DNS_HEADER_NSCOUNT(abuf);
426 arcount = DNS_HEADER_ARCOUNT(abuf);
427
428 /* Display the answer header. */
429 printf("id: %d\n", id);
430 printf("flags: %s%s%s%s%s\n",
431 qr ? "qr " : "",
432 aa ? "aa " : "",
433 tc ? "tc " : "",
434 rd ? "rd " : "",
435 ra ? "ra " : "");
436 printf("opcode: %s\n", opcodes[opcode]);
437 printf("rcode: %s\n", rcodes[rcode]);
438
439 /* Display the questions. */
440 printf("Questions:\n");
441 aptr = abuf + HFIXEDSZ;
442 for (i = 0; i < qdcount; i++)
443 {
444 aptr = display_question(aptr, abuf, alen);
445 if (aptr == NULL)
446 return;
447 }
448
449 /* Display the answers. */
450 printf("Answers:\n");
451 for (i = 0; i < ancount; i++)
452 {
453 aptr = display_rr(aptr, abuf, alen);
454 if (aptr == NULL)
455 return;
456 }
457
458 /* Display the NS records. */
459 printf("NS records:\n");
460 for (i = 0; i < nscount; i++)
461 {
462 aptr = display_rr(aptr, abuf, alen);
463 if (aptr == NULL)
464 return;
465 }
466
467 /* Display the additional records. */
468 printf("Additional records:\n");
469 for (i = 0; i < arcount; i++)
470 {
471 aptr = display_rr(aptr, abuf, alen);
472 if (aptr == NULL)
473 return;
474 }
475 }
476
display_question(const unsigned char * aptr,const unsigned char * abuf,int alen)477 static const unsigned char *display_question(const unsigned char *aptr,
478 const unsigned char *abuf,
479 int alen)
480 {
481 char *name;
482 int type, dnsclass, status;
483 long len;
484
485 /* Parse the question name. */
486 status = ares_expand_name(aptr, abuf, alen, &name, &len);
487 if (status != ARES_SUCCESS)
488 return NULL;
489 aptr += len;
490
491 /* Make sure there's enough data after the name for the fixed part
492 * of the question.
493 */
494 if (aptr + QFIXEDSZ > abuf + alen)
495 {
496 ares_free_string(name);
497 return NULL;
498 }
499
500 /* Parse the question type and class. */
501 type = DNS_QUESTION_TYPE(aptr);
502 dnsclass = DNS_QUESTION_CLASS(aptr);
503 aptr += QFIXEDSZ;
504
505 /* Display the question, in a format sort of similar to how we will
506 * display RRs.
507 */
508 printf("\t%-15s.\t", name);
509 if (dnsclass != C_IN)
510 printf("\t%s", class_name(dnsclass));
511 printf("\t%s\n", type_name(type));
512 ares_free_string(name);
513 return aptr;
514 }
515
display_rr(const unsigned char * aptr,const unsigned char * abuf,int alen)516 static const unsigned char *display_rr(const unsigned char *aptr,
517 const unsigned char *abuf, int alen)
518 {
519 const unsigned char *p;
520 int type, dnsclass, ttl, dlen, status, i;
521 long len;
522 int vlen;
523 char addr[46];
524 union {
525 unsigned char * as_uchar;
526 char * as_char;
527 } name;
528
529 /* Parse the RR name. */
530 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
531 if (status != ARES_SUCCESS)
532 return NULL;
533 aptr += len;
534
535 /* Make sure there is enough data after the RR name for the fixed
536 * part of the RR.
537 */
538 if (aptr + RRFIXEDSZ > abuf + alen)
539 {
540 ares_free_string(name.as_char);
541 return NULL;
542 }
543
544 /* Parse the fixed part of the RR, and advance to the RR data
545 * field. */
546 type = DNS_RR_TYPE(aptr);
547 dnsclass = DNS_RR_CLASS(aptr);
548 ttl = DNS_RR_TTL(aptr);
549 dlen = DNS_RR_LEN(aptr);
550 aptr += RRFIXEDSZ;
551 if (aptr + dlen > abuf + alen)
552 {
553 ares_free_string(name.as_char);
554 return NULL;
555 }
556
557 /* Display the RR name, class, and type. */
558 printf("\t%-15s.\t%d", name.as_char, ttl);
559 if (dnsclass != C_IN)
560 printf("\t%s", class_name(dnsclass));
561 printf("\t%s", type_name(type));
562 ares_free_string(name.as_char);
563
564 /* Display the RR data. Don't touch aptr. */
565 switch (type)
566 {
567 case T_CNAME:
568 case T_MB:
569 case T_MD:
570 case T_MF:
571 case T_MG:
572 case T_MR:
573 case T_NS:
574 case T_PTR:
575 /* For these types, the RR data is just a domain name. */
576 status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
577 if (status != ARES_SUCCESS)
578 return NULL;
579 printf("\t%s.", name.as_char);
580 ares_free_string(name.as_char);
581 break;
582
583 case T_HINFO:
584 /* The RR data is two length-counted character strings. */
585 p = aptr;
586 len = *p;
587 if (p + len + 1 > aptr + dlen)
588 return NULL;
589 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
590 if (status != ARES_SUCCESS)
591 return NULL;
592 printf("\t%s", name.as_char);
593 ares_free_string(name.as_char);
594 p += len;
595 len = *p;
596 if (p + len + 1 > aptr + dlen)
597 return NULL;
598 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
599 if (status != ARES_SUCCESS)
600 return NULL;
601 printf("\t%s", name.as_char);
602 ares_free_string(name.as_char);
603 break;
604
605 case T_MINFO:
606 /* The RR data is two domain names. */
607 p = aptr;
608 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
609 if (status != ARES_SUCCESS)
610 return NULL;
611 printf("\t%s.", name.as_char);
612 ares_free_string(name.as_char);
613 p += len;
614 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
615 if (status != ARES_SUCCESS)
616 return NULL;
617 printf("\t%s.", name.as_char);
618 ares_free_string(name.as_char);
619 break;
620
621 case T_MX:
622 /* The RR data is two bytes giving a preference ordering, and
623 * then a domain name.
624 */
625 if (dlen < 2)
626 return NULL;
627 printf("\t%d", (int)DNS__16BIT(aptr));
628 status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
629 if (status != ARES_SUCCESS)
630 return NULL;
631 printf("\t%s.", name.as_char);
632 ares_free_string(name.as_char);
633 break;
634
635 case T_SOA:
636 /* The RR data is two domain names and then five four-byte
637 * numbers giving the serial number and some timeouts.
638 */
639 p = aptr;
640 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
641 if (status != ARES_SUCCESS)
642 return NULL;
643 printf("\t%s.\n", name.as_char);
644 ares_free_string(name.as_char);
645 p += len;
646 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
647 if (status != ARES_SUCCESS)
648 return NULL;
649 printf("\t\t\t\t\t\t%s.\n", name.as_char);
650 ares_free_string(name.as_char);
651 p += len;
652 if (p + 20 > aptr + dlen)
653 return NULL;
654 printf("\t\t\t\t\t\t( %u %u %u %u %u )",
655 DNS__32BIT(p), DNS__32BIT(p+4),
656 DNS__32BIT(p+8), DNS__32BIT(p+12),
657 DNS__32BIT(p+16));
658 break;
659
660 case T_TXT:
661 /* The RR data is one or more length-counted character
662 * strings. */
663 p = aptr;
664 while (p < aptr + dlen)
665 {
666 len = *p;
667 if (p + len + 1 > aptr + dlen)
668 return NULL;
669 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
670 if (status != ARES_SUCCESS)
671 return NULL;
672 printf("\t%s", name.as_char);
673 ares_free_string(name.as_char);
674 p += len;
675 }
676 break;
677
678 case T_CAA:
679
680 p = aptr;
681
682 /* Flags */
683 printf(" %u", (int)*p);
684 p += 1;
685
686 /* Remainder of record */
687 vlen = (int)dlen - ((char)*p) - 2;
688
689 /* The Property identifier, one of:
690 - "issue",
691 - "iodef", or
692 - "issuewild" */
693 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
694 if (status != ARES_SUCCESS)
695 return NULL;
696 printf(" %s", name.as_char);
697 ares_free_string(name.as_char);
698 p += len;
699
700 if (p + vlen > abuf + alen)
701 return NULL;
702
703 /* A sequence of octets representing the Property Value */
704 printf(" %.*s", vlen, p);
705 break;
706
707 case T_A:
708 /* The RR data is a four-byte Internet address. */
709 if (dlen != 4)
710 return NULL;
711 printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
712 break;
713
714 case T_AAAA:
715 /* The RR data is a 16-byte IPv6 address. */
716 if (dlen != 16)
717 return NULL;
718 printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
719 break;
720
721 case T_WKS:
722 /* Not implemented yet */
723 break;
724
725 case T_SRV:
726 /* The RR data is three two-byte numbers representing the
727 * priority, weight, and port, followed by a domain name.
728 */
729
730 printf("\t%d", (int)DNS__16BIT(aptr));
731 printf(" %d", (int)DNS__16BIT(aptr + 2));
732 printf(" %d", (int)DNS__16BIT(aptr + 4));
733
734 status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
735 if (status != ARES_SUCCESS)
736 return NULL;
737 printf("\t%s.", name.as_char);
738 ares_free_string(name.as_char);
739 break;
740
741 case T_URI:
742 /* The RR data is two two-byte numbers representing the
743 * priority and weight, followed by a target.
744 */
745
746 printf("\t%d ", (int)DNS__16BIT(aptr));
747 printf("%d \t\t", (int)DNS__16BIT(aptr+2));
748 p = aptr +4;
749 for (i=0; i <dlen-4; ++i)
750 printf("%c",p[i]);
751 break;
752
753 case T_NAPTR:
754
755 printf("\t%d", (int)DNS__16BIT(aptr)); /* order */
756 printf(" %d\n", (int)DNS__16BIT(aptr + 2)); /* preference */
757
758 p = aptr + 4;
759 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
760 if (status != ARES_SUCCESS)
761 return NULL;
762 printf("\t\t\t\t\t\t%s\n", name.as_char);
763 ares_free_string(name.as_char);
764 p += len;
765
766 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
767 if (status != ARES_SUCCESS)
768 return NULL;
769 printf("\t\t\t\t\t\t%s\n", name.as_char);
770 ares_free_string(name.as_char);
771 p += len;
772
773 status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
774 if (status != ARES_SUCCESS)
775 return NULL;
776 printf("\t\t\t\t\t\t%s\n", name.as_char);
777 ares_free_string(name.as_char);
778 p += len;
779
780 status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
781 if (status != ARES_SUCCESS)
782 return NULL;
783 printf("\t\t\t\t\t\t%s", name.as_char);
784 ares_free_string(name.as_char);
785 break;
786
787 case T_DS:
788 case T_SSHFP:
789 case T_RRSIG:
790 case T_NSEC:
791 case T_DNSKEY:
792 printf("\t[RR type parsing unavailable]");
793 break;
794
795 default:
796 printf("\t[Unknown RR; cannot parse]");
797 break;
798 }
799 printf("\n");
800
801 return aptr + dlen;
802 }
803
804 /*
805 * With the '-x' (or '-xx') and '-t PTR' options, convert a query for an
806 * address into a more useful 'T_PTR' type question.
807 * Like with an input 'query':
808 * "a.b.c.d" -> "d.c.b.a".in-addr.arpa" for an IPv4 address.
809 * "a.b.c....x.y.z" -> "z.y.x....c.d.e.IP6.ARPA" for an IPv6 address.
810 *
811 * An example from 'dig -x PTR 2001:470:1:1b9::31':
812 *
813 * QUESTION SECTION:
814 * 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
815 *
816 * ANSWER SECTION:
817 * 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.
818 *
819 * If 'use_bitstring == 1', try to use the more compact RFC-2673 bitstring format.
820 * Thus the above 'dig' query should become:
821 * [x13000000000000009b10100007401002].IP6.ARPA. IN PTR
822 */
convert_query(char ** name_p,int use_bitstring)823 static int convert_query (char **name_p, int use_bitstring)
824 {
825 #ifndef MAX_IP6_RR
826 #define MAX_IP6_RR (16*sizeof(".x.x") + sizeof(".IP6.ARPA") + 1)
827 #endif
828
829 #ifdef HAVE_INET_PTON
830 #define ACCEPTED_RETVAL4 1
831 #define ACCEPTED_RETVAL6 1
832 #else
833 #define ACCEPTED_RETVAL4 32
834 #define ACCEPTED_RETVAL6 128
835 #endif
836
837 static char new_name [MAX_IP6_RR];
838 static const char hex_chars[] = "0123456789ABCDEF";
839
840 union {
841 struct in_addr addr4;
842 struct ares_in6_addr addr6;
843 } addr;
844
845 if (ares_inet_pton (AF_INET, *name_p, &addr.addr4) == 1)
846 {
847 unsigned long laddr = ntohl(addr.addr4.s_addr);
848 unsigned long a1 = (laddr >> 24UL) & 0xFFUL;
849 unsigned long a2 = (laddr >> 16UL) & 0xFFUL;
850 unsigned long a3 = (laddr >> 8UL) & 0xFFUL;
851 unsigned long a4 = laddr & 0xFFUL;
852
853 snprintf(new_name, sizeof(new_name), "%lu.%lu.%lu.%lu.in-addr.arpa", a4, a3, a2, a1);
854 *name_p = new_name;
855 return (1);
856 }
857
858 if (ares_inet_pton(AF_INET6, *name_p, &addr.addr6) == 1)
859 {
860 char *c = new_name;
861 const unsigned char *ip = (const unsigned char*) &addr.addr6;
862 int max_i = (int)sizeof(addr.addr6) - 1;
863 int i, hi, lo;
864
865 /* Use the more compact RFC-2673 notation?
866 * Currently doesn't work or unsupported by the DNS-servers I've tested against.
867 */
868 if (use_bitstring)
869 {
870 *c++ = '\\';
871 *c++ = '[';
872 *c++ = 'x';
873 for (i = max_i; i >= 0; i--)
874 {
875 hi = ip[i] >> 4;
876 lo = ip[i] & 15;
877 *c++ = hex_chars [lo];
878 *c++ = hex_chars [hi];
879 }
880 strcpy (c, "].IP6.ARPA");
881 }
882 else
883 {
884 for (i = max_i; i >= 0; i--)
885 {
886 hi = ip[i] >> 4;
887 lo = ip[i] & 15;
888 *c++ = hex_chars [lo];
889 *c++ = '.';
890 *c++ = hex_chars [hi];
891 *c++ = '.';
892 }
893 strcpy (c, "IP6.ARPA");
894 }
895 *name_p = new_name;
896 return (1);
897 }
898 printf("Address %s was not legal for this query.\n", *name_p);
899 return (0);
900 }
901
type_name(int type)902 static const char *type_name(int type)
903 {
904 int i;
905
906 for (i = 0; i < ntypes; i++)
907 {
908 if (types[i].value == type)
909 return types[i].name;
910 }
911 return "(unknown)";
912 }
913
class_name(int dnsclass)914 static const char *class_name(int dnsclass)
915 {
916 int i;
917
918 for (i = 0; i < nclasses; i++)
919 {
920 if (classes[i].value == dnsclass)
921 return classes[i].name;
922 }
923 return "(unknown)";
924 }
925
usage(void)926 static void usage(void)
927 {
928 fprintf(stderr, "usage: adig [-h] [-d] [-f flag] [-s server] [-c class] "
929 "[-t type] [-T|U port] [-x|-xx] name ...\n");
930 exit(1);
931 }
932
destroy_addr_list(struct ares_addr_node * head)933 static void destroy_addr_list(struct ares_addr_node *head)
934 {
935 while(head)
936 {
937 struct ares_addr_node *detached = head;
938 head = head->next;
939 free(detached);
940 }
941 }
942
append_addr_list(struct ares_addr_node ** head,struct ares_addr_node * node)943 static void append_addr_list(struct ares_addr_node **head,
944 struct ares_addr_node *node)
945 {
946 struct ares_addr_node *last;
947 node->next = NULL;
948 if(*head)
949 {
950 last = *head;
951 while(last->next)
952 last = last->next;
953 last->next = node;
954 }
955 else
956 *head = node;
957 }
958
959
960 /* Information from the man page. Formatting taken from man -h */
print_help_info_adig(void)961 static void print_help_info_adig(void) {
962 printf("adig, version %s \n\n", ARES_VERSION_STR);
963 printf("usage: adig [-h] [-d] [-f flag] [-s server] [-c class] [-t type] [-T|U port] [-x | -xx] name ...\n\n"
964 " d : Print some extra debugging output.\n"
965 " f : Add a flag. Possible values for flag are igntc, noaliases, norecurse, primary, stayopen, usevc.\n"
966 " h : Display this help and exit.\n\n"
967 " T port : Use specified TCP port to connect to DNS server.\n"
968 " U port : Use specified UDP port to connect to DNS server.\n"
969 " c class : Set the query class. Possible values for class are NY, CHAOS, HS, IN (default).\n"
970 " s server : Connect to specified DNS server, instead of the system's default one(s).\n"
971 " t type : Query records of specified type. \n"
972 " Possible values for type are A \n"
973 " (default), AAAA, AFSDB, ANY,\n"
974 " AXFR, CNAME, GPOS, HINFO, ISDN,\n"
975 " KEY, LOC, MAILA, MAILB, MB, MD,\n"
976 " MF, MG, MINFO, MR, MX, NAPTR, NS,\n"
977 " NSAP, NSAP_PTR, NULL, PTR, PX, RP,\n"
978 " RT, SIG, SOA, SRV, TXT, URI, WKS, X25\n\n"
979 " -x : For a '-t PTR a.b.c.d' lookup, query for 'd.c.b.a.in-addr.arpa.'\n"
980 " -xx : As above, but for IPv6, compact the format into a bitstring like\n"
981 " '[xabcdef00000000000000000000000000].IP6.ARPA.'\n");
982 exit(0);
983 }
984