• 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           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