• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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