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