Home | History | Annotate | Download | only in c-ares
      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", 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 
    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 }
    844