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