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
103struct nv {
104  const char *name;
105  int value;
106};
107
108static 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};
116static const int nflags = sizeof(flags) / sizeof(flags[0]);
117
118static const struct nv classes[] = {
119  { "IN",       C_IN },
120  { "CHAOS",    C_CHAOS },
121  { "HS",       C_HS },
122  { "ANY",      C_ANY }
123};
124static const int nclasses = sizeof(classes) / sizeof(classes[0]);
125
126static 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};
168static const int ntypes = sizeof(types) / sizeof(types[0]);
169
170static 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
177static const char *rcodes[] = {
178  "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED",
179  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "(unknown)",
180  "(unknown)", "(unknown)", "(unknown)", "(unknown)", "NOCHANGE"
181};
182
183static void callback(void *arg, int status, int timeouts,
184                     unsigned char *abuf, int alen);
185static const unsigned char *display_question(const unsigned char *aptr,
186                                             const unsigned char *abuf,
187                                             int alen);
188static const unsigned char *display_rr(const unsigned char *aptr,
189                                       const unsigned char *abuf, int alen);
190static const char *type_name(int type);
191static const char *class_name(int dnsclass);
192static void usage(void);
193static void destroy_addr_list(struct ares_addr_node *head);
194static void append_addr_list(struct ares_addr_node **head,
195                             struct ares_addr_node *node);
196
197int 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
412static 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
503static 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
542static 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", 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( %lu %lu %lu %lu %lu )",
680             (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
681             (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
682             (unsigned long)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", DNS__16BIT(aptr));
727      printf(" %d", DNS__16BIT(aptr + 2));
728      printf(" %d", 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", DNS__16BIT(aptr)); /* order */
740      printf(" %d\n", 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
788static 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
800static 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
812static 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
819static 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
829static 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}
844