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