update for beta universally
[external/c-ares.git] / adig.c
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_SYS_SOCKET_H
20 #  include <sys/socket.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 #  include <netinet/in.h>
24 #endif
25 #ifdef HAVE_ARPA_INET_H
26 #  include <arpa/inet.h>
27 #endif
28 #ifdef HAVE_NETDB_H
29 #  include <netdb.h>
30 #endif
31 #ifdef HAVE_ARPA_NAMESER_H
32 #  include <arpa/nameser.h>
33 #else
34 #  include "nameser.h"
35 #endif
36 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
37 #  include <arpa/nameser_compat.h>
38 #endif
39
40 #ifdef HAVE_SYS_TIME_H
41 #  include <sys/time.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 #  include <unistd.h>
45 #endif
46 #ifdef HAVE_STRINGS_H
47 #  include <strings.h>
48 #endif
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <ctype.h>
54 #include <errno.h>
55
56 #include "ares.h"
57 #include "ares_dns.h"
58 #include "inet_ntop.h"
59 #include "inet_net_pton.h"
60 #include "ares_getopt.h"
61
62 #ifndef HAVE_STRDUP
63 #  include "ares_strdup.h"
64 #  define strdup(ptr) ares_strdup(ptr)
65 #endif
66
67 #ifndef HAVE_STRCASECMP
68 #  include "ares_strcasecmp.h"
69 #  define strcasecmp(p1,p2) ares_strcasecmp(p1,p2)
70 #endif
71
72 #ifndef HAVE_STRNCASECMP
73 #  include "ares_strcasecmp.h"
74 #  define strncasecmp(p1,p2,n) ares_strncasecmp(p1,p2,n)
75 #endif
76
77 #ifdef WATT32
78 #undef WIN32  /* Redefined in MingW headers */
79 #endif
80
81 /* Mac OS X portability check */
82 #ifndef T_SRV
83 #define T_SRV 33 /* server selection */
84 #endif
85
86 /* AIX portability check */
87 #ifndef T_NAPTR
88 #define T_NAPTR 35 /* naming authority pointer */
89 #endif
90
91 struct nv {
92   const char *name;
93   int value;
94 };
95
96 static const struct nv flags[] = {
97   { "usevc",            ARES_FLAG_USEVC },
98   { "primary",          ARES_FLAG_PRIMARY },
99   { "igntc",            ARES_FLAG_IGNTC },
100   { "norecurse",        ARES_FLAG_NORECURSE },
101   { "stayopen",         ARES_FLAG_STAYOPEN },
102   { "noaliases",        ARES_FLAG_NOALIASES }
103 };
104 static const int nflags = sizeof(flags) / sizeof(flags[0]);
105
106 static const struct nv classes[] = {
107   { "IN",       C_IN },
108   { "CHAOS",    C_CHAOS },
109   { "HS",       C_HS },
110   { "ANY",      C_ANY }
111 };
112 static const int nclasses = sizeof(classes) / sizeof(classes[0]);
113
114 static const struct nv types[] = {
115   { "A",        T_A },
116   { "NS",       T_NS },
117   { "MD",       T_MD },
118   { "MF",       T_MF },
119   { "CNAME",    T_CNAME },
120   { "SOA",      T_SOA },
121   { "MB",       T_MB },
122   { "MG",       T_MG },
123   { "MR",       T_MR },
124   { "NULL",     T_NULL },
125   { "WKS",      T_WKS },
126   { "PTR",      T_PTR },
127   { "HINFO",    T_HINFO },
128   { "MINFO",    T_MINFO },
129   { "MX",       T_MX },
130   { "TXT",      T_TXT },
131   { "RP",       T_RP },
132   { "AFSDB",    T_AFSDB },
133   { "X25",      T_X25 },
134   { "ISDN",     T_ISDN },
135   { "RT",       T_RT },
136   { "NSAP",     T_NSAP },
137   { "NSAP_PTR", T_NSAP_PTR },
138   { "SIG",      T_SIG },
139   { "KEY",      T_KEY },
140   { "PX",       T_PX },
141   { "GPOS",     T_GPOS },
142   { "AAAA",     T_AAAA },
143   { "LOC",      T_LOC },
144   { "SRV",      T_SRV },
145   { "AXFR",     T_AXFR },
146   { "MAILB",    T_MAILB },
147   { "MAILA",    T_MAILA },
148   { "NAPTR",    T_NAPTR },
149   { "ANY",      T_ANY }
150 };
151 static const int ntypes = sizeof(types) / sizeof(types[0]);
152
153 static const char *opcodes[] = {
154   "QUERY", "IQUERY", "STATUS", "(reserved)", "NOTIFY",
155   "(unknown)", "(unknown)", "(unknown)", "(unknown)",
156   "UPDATEA", "UPDATED", "UPDATEDA", "UPDATEM", "UPDATEMA",
157   "ZONEINIT", "ZONEREF"
158 };
159
160 static const char *rcodes[] = {
161   "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
162   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
163   "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
164 };
165
166 static void callback(void *arg, int status, int timeouts,
167                      unsigned char *abuf, int alen);
168 static const unsigned char *display_question(const unsigned char *aptr,
169                                              const unsigned char *abuf,
170                                              int alen);
171 static const unsigned char *display_rr(const unsigned char *aptr,
172                                        const unsigned char *abuf, int alen);
173 static const char *type_name(int type);
174 static const char *class_name(int dnsclass);
175 static void usage(void);
176 static void destroy_addr_list(struct ares_addr_node *head);
177 static void append_addr_list(struct ares_addr_node **head,
178                              struct ares_addr_node *node);
179
180 int main(int argc, char **argv)
181 {
182   ares_channel channel;
183   int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A;
184   int status, nfds, count;
185   struct ares_options options;
186   struct hostent *hostent;
187   fd_set read_fds, write_fds;
188   struct timeval *tvp, tv;
189   struct ares_addr_node *srvr, *servers = NULL;
190
191 #ifdef USE_WINSOCK
192   WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK);
193   WSADATA wsaData;
194   WSAStartup(wVersionRequested, &wsaData);
195 #endif
196
197   status = ares_library_init(ARES_LIB_INIT_ALL);
198   if (status != ARES_SUCCESS)
199     {
200       fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status));
201       return 1;
202     }
203
204   options.flags = ARES_FLAG_NOCHECKRESP;
205   options.servers = NULL;
206   options.nservers = 0;
207   while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1)
208     {
209       switch (c)
210         {
211         case 'd':
212 #ifdef WATT32
213           dbug_init();
214 #endif
215           break;
216
217         case 'f':
218           /* Add a flag. */
219           for (i = 0; i < nflags; i++)
220             {
221               if (strcmp(flags[i].name, optarg) == 0)
222                 break;
223             }
224           if (i < nflags)
225             options.flags |= flags[i].value;
226           else
227             usage();
228           break;
229
230         case 's':
231           /* User-specified name servers override default ones. */
232           srvr = malloc(sizeof(struct ares_addr_node));
233           if (!srvr)
234             {
235               fprintf(stderr, "Out of memory!\n");
236               destroy_addr_list(servers);
237               return 1;
238             }
239           append_addr_list(&servers, srvr);
240           if (ares_inet_pton(AF_INET, optarg, &srvr->addr.addr4) > 0)
241             srvr->family = AF_INET;
242           else if (ares_inet_pton(AF_INET6, optarg, &srvr->addr.addr6) > 0)
243             srvr->family = AF_INET6;
244           else
245             {
246               hostent = gethostbyname(optarg);
247               if (!hostent)
248                 {
249                   fprintf(stderr, "adig: server %s not found.\n", optarg);
250                   destroy_addr_list(servers);
251                   return 1;
252                 }
253               switch (hostent->h_addrtype)
254                 {
255                   case AF_INET:
256                     srvr->family = AF_INET;
257                     memcpy(&srvr->addr.addr4, hostent->h_addr,
258                            sizeof(srvr->addr.addr4));
259                     break;
260                   case AF_INET6:
261                     srvr->family = AF_INET6;
262                     memcpy(&srvr->addr.addr6, hostent->h_addr,
263                            sizeof(srvr->addr.addr6));
264                     break;
265                   default:
266                     fprintf(stderr,
267                       "adig: server %s unsupported address family.\n", optarg);
268                     destroy_addr_list(servers);
269                     return 1;
270                 }
271             }
272           /* Notice that calling ares_init_options() without servers in the
273            * options struct and with ARES_OPT_SERVERS set simultaneously in
274            * the options mask, results in an initialization with no servers.
275            * When alternative name servers have been specified these are set
276            * later calling ares_set_servers() overriding any existing server
277            * configuration. To prevent initial configuration with default
278            * servers that will be discarded later, ARES_OPT_SERVERS is set.
279            * If this flag is not set here the result shall be the same but
280            * ares_init_options() will do needless work. */
281           optmask |= ARES_OPT_SERVERS;
282           break;
283
284         case 'c':
285           /* Set the query class. */
286           for (i = 0; i < nclasses; i++)
287             {
288               if (strcasecmp(classes[i].name, optarg) == 0)
289                 break;
290             }
291           if (i < nclasses)
292             dnsclass = classes[i].value;
293           else
294             usage();
295           break;
296
297         case 't':
298           /* Set the query type. */
299           for (i = 0; i < ntypes; i++)
300             {
301               if (strcasecmp(types[i].name, optarg) == 0)
302                 break;
303             }
304           if (i < ntypes)
305             type = types[i].value;
306           else
307             usage();
308           break;
309
310         case 'T':
311           /* Set the TCP port number. */
312           if (!ISDIGIT(*optarg))
313             usage();
314           options.tcp_port = (unsigned short)strtol(optarg, NULL, 0);
315           optmask |= ARES_OPT_TCP_PORT;
316           break;
317
318         case 'U':
319           /* Set the UDP port number. */
320           if (!ISDIGIT(*optarg))
321             usage();
322           options.udp_port = (unsigned short)strtol(optarg, NULL, 0);
323           optmask |= ARES_OPT_UDP_PORT;
324           break;
325         }
326     }
327   argc -= optind;
328   argv += optind;
329   if (argc == 0)
330     usage();
331
332   status = ares_init_options(&channel, &options, optmask);
333
334   if (status != ARES_SUCCESS)
335     {
336       fprintf(stderr, "ares_init_options: %s\n",
337               ares_strerror(status));
338       return 1;
339     }
340
341   if(servers)
342     {
343       status = ares_set_servers(channel, servers);
344       destroy_addr_list(servers);
345       if (status != ARES_SUCCESS)
346         {
347           fprintf(stderr, "ares_init_options: %s\n",
348                   ares_strerror(status));
349           return 1;
350         }
351     }
352
353   /* Initiate the queries, one per command-line argument.  If there is
354    * only one query to do, supply NULL as the callback argument;
355    * otherwise, supply the query name as an argument so we can
356    * distinguish responses for the user when printing them out.
357    */
358   if (argc == 1)
359     ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL);
360   else
361     {
362       for (; *argv; argv++)
363         ares_query(channel, *argv, dnsclass, type, callback, *argv);
364     }
365
366   /* Wait for all queries to complete. */
367   for (;;)
368     {
369       FD_ZERO(&read_fds);
370       FD_ZERO(&write_fds);
371       nfds = ares_fds(channel, &read_fds, &write_fds);
372       if (nfds == 0)
373         break;
374       tvp = ares_timeout(channel, NULL, &tv);
375       count = select(nfds, &read_fds, &write_fds, NULL, tvp);
376       if (count < 0 && SOCKERRNO != EINVAL)
377         {
378           perror("select");
379           return 1;
380         }
381       ares_process(channel, &read_fds, &write_fds);
382     }
383
384   ares_destroy(channel);
385
386   ares_library_cleanup();
387
388 #ifdef USE_WINSOCK
389   WSACleanup();
390 #endif
391
392   return 0;
393 }
394
395 static void callback(void *arg, int status, int timeouts,
396                      unsigned char *abuf, int alen)
397 {
398   char *name = (char *) arg;
399   int id, qr, opcode, aa, tc, rd, ra, rcode;
400   unsigned int qdcount, ancount, nscount, arcount, i;
401   const unsigned char *aptr;
402
403   (void) timeouts;
404
405   /* Display the query name if given. */
406   if (name)
407     printf("Answer for query %s:\n", name);
408
409   /* Display an error message if there was an error, but only stop if
410    * we actually didn't get an answer buffer.
411    */
412   if (status != ARES_SUCCESS)
413     {
414       printf("%s\n", ares_strerror(status));
415       if (!abuf)
416         return;
417     }
418
419   /* Won't happen, but check anyway, for safety. */
420   if (alen < HFIXEDSZ)
421     return;
422
423   /* Parse the answer header. */
424   id = DNS_HEADER_QID(abuf);
425   qr = DNS_HEADER_QR(abuf);
426   opcode = DNS_HEADER_OPCODE(abuf);
427   aa = DNS_HEADER_AA(abuf);
428   tc = DNS_HEADER_TC(abuf);
429   rd = DNS_HEADER_RD(abuf);
430   ra = DNS_HEADER_RA(abuf);
431   rcode = DNS_HEADER_RCODE(abuf);
432   qdcount = DNS_HEADER_QDCOUNT(abuf);
433   ancount = DNS_HEADER_ANCOUNT(abuf);
434   nscount = DNS_HEADER_NSCOUNT(abuf);
435   arcount = DNS_HEADER_ARCOUNT(abuf);
436
437   /* Display the answer header. */
438   printf("id: %d\n", id);
439   printf("flags: %s%s%s%s%s\n",
440          qr ? "qr " : "",
441          aa ? "aa " : "",
442          tc ? "tc " : "",
443          rd ? "rd " : "",
444          ra ? "ra " : "");
445   printf("opcode: %s\n", opcodes[opcode]);
446   printf("rcode: %s\n", rcodes[rcode]);
447
448   /* Display the questions. */
449   printf("Questions:\n");
450   aptr = abuf + HFIXEDSZ;
451   for (i = 0; i < qdcount; i++)
452     {
453       aptr = display_question(aptr, abuf, alen);
454       if (aptr == NULL)
455         return;
456     }
457
458   /* Display the answers. */
459   printf("Answers:\n");
460   for (i = 0; i < ancount; i++)
461     {
462       aptr = display_rr(aptr, abuf, alen);
463       if (aptr == NULL)
464         return;
465     }
466
467   /* Display the NS records. */
468   printf("NS records:\n");
469   for (i = 0; i < nscount; i++)
470     {
471       aptr = display_rr(aptr, abuf, alen);
472       if (aptr == NULL)
473         return;
474     }
475
476   /* Display the additional records. */
477   printf("Additional records:\n");
478   for (i = 0; i < arcount; i++)
479     {
480       aptr = display_rr(aptr, abuf, alen);
481       if (aptr == NULL)
482         return;
483     }
484 }
485
486 static const unsigned char *display_question(const unsigned char *aptr,
487                                              const unsigned char *abuf,
488                                              int alen)
489 {
490   char *name;
491   int type, dnsclass, status;
492   long len;
493
494   /* Parse the question name. */
495   status = ares_expand_name(aptr, abuf, alen, &name, &len);
496   if (status != ARES_SUCCESS)
497     return NULL;
498   aptr += len;
499
500   /* Make sure there's enough data after the name for the fixed part
501    * of the question.
502    */
503   if (aptr + QFIXEDSZ > abuf + alen)
504     {
505       ares_free_string(name);
506       return NULL;
507     }
508
509   /* Parse the question type and class. */
510   type = DNS_QUESTION_TYPE(aptr);
511   dnsclass = DNS_QUESTION_CLASS(aptr);
512   aptr += QFIXEDSZ;
513
514   /* Display the question, in a format sort of similar to how we will
515    * display RRs.
516    */
517   printf("\t%-15s.\t", name);
518   if (dnsclass != C_IN)
519     printf("\t%s", class_name(dnsclass));
520   printf("\t%s\n", type_name(type));
521   ares_free_string(name);
522   return aptr;
523 }
524
525 static const unsigned char *display_rr(const unsigned char *aptr,
526                                        const unsigned char *abuf, int alen)
527 {
528   const unsigned char *p;
529   int type, dnsclass, ttl, dlen, status;
530   long len;
531   char addr[46];
532   union {
533     unsigned char * as_uchar;
534              char * as_char;
535   } name;
536
537   /* Parse the RR name. */
538   status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
539   if (status != ARES_SUCCESS)
540     return NULL;
541   aptr += len;
542
543   /* Make sure there is enough data after the RR name for the fixed
544    * part of the RR.
545    */
546   if (aptr + RRFIXEDSZ > abuf + alen)
547     {
548       ares_free_string(name.as_char);
549       return NULL;
550     }
551
552   /* Parse the fixed part of the RR, and advance to the RR data
553    * field. */
554   type = DNS_RR_TYPE(aptr);
555   dnsclass = DNS_RR_CLASS(aptr);
556   ttl = DNS_RR_TTL(aptr);
557   dlen = DNS_RR_LEN(aptr);
558   aptr += RRFIXEDSZ;
559   if (aptr + dlen > abuf + alen)
560     {
561       ares_free_string(name.as_char);
562       return NULL;
563     }
564
565   /* Display the RR name, class, and type. */
566   printf("\t%-15s.\t%d", name.as_char, ttl);
567   if (dnsclass != C_IN)
568     printf("\t%s", class_name(dnsclass));
569   printf("\t%s", type_name(type));
570   ares_free_string(name.as_char);
571
572   /* Display the RR data.  Don't touch aptr. */
573   switch (type)
574     {
575     case T_CNAME:
576     case T_MB:
577     case T_MD:
578     case T_MF:
579     case T_MG:
580     case T_MR:
581     case T_NS:
582     case T_PTR:
583       /* For these types, the RR data is just a domain name. */
584       status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
585       if (status != ARES_SUCCESS)
586         return NULL;
587       printf("\t%s.", name.as_char);
588       ares_free_string(name.as_char);
589       break;
590
591     case T_HINFO:
592       /* The RR data is two length-counted character strings. */
593       p = aptr;
594       len = *p;
595       if (p + len + 1 > aptr + dlen)
596         return NULL;
597       status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
598       if (status != ARES_SUCCESS)
599         return NULL;
600       printf("\t%s", name.as_char);
601       ares_free_string(name.as_char);
602       p += len;
603       len = *p;
604       if (p + len + 1 > aptr + dlen)
605         return NULL;
606       status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
607       if (status != ARES_SUCCESS)
608         return NULL;
609       printf("\t%s", name.as_char);
610       ares_free_string(name.as_char);
611       break;
612
613     case T_MINFO:
614       /* The RR data is two domain names. */
615       p = aptr;
616       status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
617       if (status != ARES_SUCCESS)
618         return NULL;
619       printf("\t%s.", name.as_char);
620       ares_free_string(name.as_char);
621       p += len;
622       status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
623       if (status != ARES_SUCCESS)
624         return NULL;
625       printf("\t%s.", name.as_char);
626       ares_free_string(name.as_char);
627       break;
628
629     case T_MX:
630       /* The RR data is two bytes giving a preference ordering, and
631        * then a domain name.
632        */
633       if (dlen < 2)
634         return NULL;
635       printf("\t%d", DNS__16BIT(aptr));
636       status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
637       if (status != ARES_SUCCESS)
638         return NULL;
639       printf("\t%s.", name.as_char);
640       ares_free_string(name.as_char);
641       break;
642
643     case T_SOA:
644       /* The RR data is two domain names and then five four-byte
645        * numbers giving the serial number and some timeouts.
646        */
647       p = aptr;
648       status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
649       if (status != ARES_SUCCESS)
650         return NULL;
651       printf("\t%s.\n", name.as_char);
652       ares_free_string(name.as_char);
653       p += len;
654       status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
655       if (status != ARES_SUCCESS)
656         return NULL;
657       printf("\t\t\t\t\t\t%s.\n", name.as_char);
658       ares_free_string(name.as_char);
659       p += len;
660       if (p + 20 > aptr + dlen)
661         return NULL;
662       printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
663              (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
664              (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
665              (unsigned long)DNS__32BIT(p+16));
666       break;
667
668     case T_TXT:
669       /* The RR data is one or more length-counted character
670        * strings. */
671       p = aptr;
672       while (p < aptr + dlen)
673         {
674           len = *p;
675           if (p + len + 1 > aptr + dlen)
676             return NULL;
677           status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
678           if (status != ARES_SUCCESS)
679             return NULL;
680           printf("\t%s", name.as_char);
681           ares_free_string(name.as_char);
682           p += len;
683         }
684       break;
685
686     case T_A:
687       /* The RR data is a four-byte Internet address. */
688       if (dlen != 4)
689         return NULL;
690       printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
691       break;
692
693     case T_AAAA:
694       /* The RR data is a 16-byte IPv6 address. */
695       if (dlen != 16)
696         return NULL;
697       printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
698       break;
699
700     case T_WKS:
701       /* Not implemented yet */
702       break;
703
704     case T_SRV:
705       /* The RR data is three two-byte numbers representing the
706        * priority, weight, and port, followed by a domain name.
707        */
708
709       printf("\t%d", DNS__16BIT(aptr));
710       printf(" %d", DNS__16BIT(aptr + 2));
711       printf(" %d", DNS__16BIT(aptr + 4));
712
713       status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
714       if (status != ARES_SUCCESS)
715         return NULL;
716       printf("\t%s.", name.as_char);
717       ares_free_string(name.as_char);
718       break;
719
720     case T_NAPTR:
721
722       printf("\t%d", DNS__16BIT(aptr)); /* order */
723       printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */
724
725       p = aptr + 4;
726       status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
727       if (status != ARES_SUCCESS)
728         return NULL;
729       printf("\t\t\t\t\t\t%s\n", name.as_char);
730       ares_free_string(name.as_char);
731       p += len;
732
733       status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
734       if (status != ARES_SUCCESS)
735         return NULL;
736       printf("\t\t\t\t\t\t%s\n", name.as_char);
737       ares_free_string(name.as_char);
738       p += len;
739
740       status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
741       if (status != ARES_SUCCESS)
742         return NULL;
743       printf("\t\t\t\t\t\t%s\n", name.as_char);
744       ares_free_string(name.as_char);
745       p += len;
746
747       status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
748       if (status != ARES_SUCCESS)
749         return NULL;
750       printf("\t\t\t\t\t\t%s", name.as_char);
751       ares_free_string(name.as_char);
752       break;
753
754
755     default:
756       printf("\t[Unknown RR; cannot parse]");
757       break;
758     }
759   printf("\n");
760
761   return aptr + dlen;
762 }
763
764 static const char *type_name(int type)
765 {
766   int i;
767
768   for (i = 0; i < ntypes; i++)
769     {
770       if (types[i].value == type)
771         return types[i].name;
772     }
773   return "(unknown)";
774 }
775
776 static const char *class_name(int dnsclass)
777 {
778   int i;
779
780   for (i = 0; i < nclasses; i++)
781     {
782       if (classes[i].value == dnsclass)
783         return classes[i].name;
784     }
785   return "(unknown)";
786 }
787
788 static void usage(void)
789 {
790   fprintf(stderr, "usage: adig [-f flag] [-s server] [-c class] "
791           "[-t type] [-p port] name ...\n");
792   exit(1);
793 }
794
795 static void destroy_addr_list(struct ares_addr_node *head)
796 {
797   while(head)
798     {
799       struct ares_addr_node *detached = head;
800       head = head->next;
801       free(detached);
802     }
803 }
804
805 static void append_addr_list(struct ares_addr_node **head,
806                              struct ares_addr_node *node)
807 {
808   struct ares_addr_node *last;
809   node->next = NULL;
810   if(*head)
811     {
812       last = *head;
813       while(last->next)
814         last = last->next;
815       last->next = node;
816     }
817   else
818     *head = node;
819 }