Home | History | Annotate | Download | only in c-ares
      1 
      2 /* Copyright 1998 by the Massachusetts Institute of Technology.
      3  * Copyright 2005 Dominick Meglio
      4  *
      5  * Permission to use, copy, modify, and distribute this
      6  * software and its documentation for any purpose and without
      7  * fee is hereby granted, provided that the above copyright
      8  * notice appear in all copies and that both that copyright
      9  * notice and this permission notice appear in supporting
     10  * documentation, and that the name of M.I.T. not be used in
     11  * advertising or publicity pertaining to distribution of the
     12  * software without specific, written prior permission.
     13  * M.I.T. makes no representations about the suitability of
     14  * this software for any purpose.  It is provided "as is"
     15  * without express or implied warranty.
     16  */
     17 
     18 #include "ares_setup.h"
     19 
     20 #ifdef HAVE_SYS_SOCKET_H
     21 #  include <sys/socket.h>
     22 #endif
     23 #ifdef HAVE_NETINET_IN_H
     24 #  include <netinet/in.h>
     25 #endif
     26 #ifdef HAVE_NETDB_H
     27 #  include <netdb.h>
     28 #endif
     29 #ifdef HAVE_ARPA_INET_H
     30 #  include <arpa/inet.h>
     31 #endif
     32 #ifdef HAVE_ARPA_NAMESER_H
     33 #  include <arpa/nameser.h>
     34 #else
     35 #  include "nameser.h"
     36 #endif
     37 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
     38 #  include <arpa/nameser_compat.h>
     39 #endif
     40 
     41 #ifdef HAVE_STRINGS_H
     42 #  include <strings.h>
     43 #endif
     44 
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #ifdef HAVE_LIMITS_H
     48 #  include <limits.h>
     49 #endif
     50 
     51 #include "ares.h"
     52 #include "ares_dns.h"
     53 #include "inet_net_pton.h"
     54 #include "ares_private.h"
     55 
     56 int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
     57                           struct hostent **host, struct ares_addr6ttl *addrttls,
     58                           int *naddrttls)
     59 {
     60   unsigned int qdcount, ancount;
     61   int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs;
     62   int cname_ttl = INT_MAX;  /* the TTL imposed by the CNAME chain */
     63   int naliases;
     64   long len;
     65   const unsigned char *aptr;
     66   char *hostname, *rr_name, *rr_data, **aliases;
     67   struct ares_in6_addr *addrs;
     68   struct hostent *hostent;
     69   const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
     70 
     71   /* Set *host to NULL for all failure cases. */
     72   if (host)
     73     *host = NULL;
     74   /* Same with *naddrttls. */
     75   if (naddrttls)
     76     *naddrttls = 0;
     77 
     78   /* Give up if abuf doesn't have room for a header. */
     79   if (alen < HFIXEDSZ)
     80     return ARES_EBADRESP;
     81 
     82   /* Fetch the question and answer count from the header. */
     83   qdcount = DNS_HEADER_QDCOUNT(abuf);
     84   ancount = DNS_HEADER_ANCOUNT(abuf);
     85   if (qdcount != 1)
     86     return ARES_EBADRESP;
     87 
     88   /* Expand the name from the question, and skip past the question. */
     89   aptr = abuf + HFIXEDSZ;
     90   status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len);
     91   if (status != ARES_SUCCESS)
     92     return status;
     93   if (aptr + len + QFIXEDSZ > abuf + alen)
     94     {
     95       free(hostname);
     96       return ARES_EBADRESP;
     97     }
     98   aptr += len + QFIXEDSZ;
     99 
    100   /* Allocate addresses and aliases; ancount gives an upper bound for both. */
    101   if (host)
    102     {
    103       addrs = malloc(ancount * sizeof(struct ares_in6_addr));
    104       if (!addrs)
    105         {
    106           free(hostname);
    107           return ARES_ENOMEM;
    108         }
    109       aliases = malloc((ancount + 1) * sizeof(char *));
    110       if (!aliases)
    111         {
    112           free(hostname);
    113           free(addrs);
    114           return ARES_ENOMEM;
    115         }
    116     }
    117   else
    118     {
    119       addrs = NULL;
    120       aliases = NULL;
    121     }
    122   naddrs = 0;
    123   naliases = 0;
    124 
    125   /* Examine each answer resource record (RR) in turn. */
    126   for (i = 0; i < (int)ancount; i++)
    127     {
    128       /* Decode the RR up to the data field. */
    129       status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
    130       if (status != ARES_SUCCESS)
    131         break;
    132       aptr += len;
    133       if (aptr + RRFIXEDSZ > abuf + alen)
    134         {
    135           free(rr_name);
    136           status = ARES_EBADRESP;
    137           break;
    138         }
    139       rr_type = DNS_RR_TYPE(aptr);
    140       rr_class = DNS_RR_CLASS(aptr);
    141       rr_len = DNS_RR_LEN(aptr);
    142       rr_ttl = DNS_RR_TTL(aptr);
    143       aptr += RRFIXEDSZ;
    144 
    145       if (rr_class == C_IN && rr_type == T_AAAA
    146           && rr_len == sizeof(struct ares_in6_addr)
    147           && strcasecmp(rr_name, hostname) == 0)
    148         {
    149           if (addrs)
    150             {
    151               if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
    152               {
    153                 free(rr_name);
    154                 status = ARES_EBADRESP;
    155                 break;
    156               }
    157               memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr));
    158             }
    159           if (naddrs < max_addr_ttls)
    160             {
    161               struct ares_addr6ttl * const at = &addrttls[naddrs];
    162               if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
    163               {
    164                 free(rr_name);
    165                 status = ARES_EBADRESP;
    166                 break;
    167               }
    168               memcpy(&at->ip6addr, aptr,  sizeof(struct ares_in6_addr));
    169               at->ttl = rr_ttl;
    170             }
    171           naddrs++;
    172           status = ARES_SUCCESS;
    173         }
    174 
    175       if (rr_class == C_IN && rr_type == T_CNAME)
    176         {
    177           /* Record the RR name as an alias. */
    178           if (aliases)
    179             aliases[naliases] = rr_name;
    180           else
    181             free(rr_name);
    182           naliases++;
    183 
    184           /* Decode the RR data and replace the hostname with it. */
    185           status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
    186                                                   &len);
    187           if (status != ARES_SUCCESS)
    188             break;
    189           free(hostname);
    190           hostname = rr_data;
    191 
    192           /* Take the min of the TTLs we see in the CNAME chain. */
    193           if (cname_ttl > rr_ttl)
    194             cname_ttl = rr_ttl;
    195         }
    196       else
    197         free(rr_name);
    198 
    199       aptr += rr_len;
    200       if (aptr > abuf + alen)
    201         {
    202           status = ARES_EBADRESP;
    203           break;
    204         }
    205     }
    206 
    207   if (status == ARES_SUCCESS && naddrs == 0)
    208     status = ARES_ENODATA;
    209   if (status == ARES_SUCCESS)
    210     {
    211       /* We got our answer. */
    212       if (naddrttls)
    213         {
    214           const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls;
    215           for (i = 0; i < n; i++)
    216             {
    217               /* Ensure that each A TTL is no larger than the CNAME TTL. */
    218               if (addrttls[i].ttl > cname_ttl)
    219                 addrttls[i].ttl = cname_ttl;
    220             }
    221           *naddrttls = n;
    222         }
    223       if (aliases)
    224         aliases[naliases] = NULL;
    225       if (host)
    226         {
    227           /* Allocate memory to build the host entry. */
    228           hostent = malloc(sizeof(struct hostent));
    229           if (hostent)
    230             {
    231               hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *));
    232               if (hostent->h_addr_list)
    233                 {
    234                   /* Fill in the hostent and return successfully. */
    235                   hostent->h_name = hostname;
    236                   hostent->h_aliases = aliases;
    237                   hostent->h_addrtype = AF_INET6;
    238                   hostent->h_length = sizeof(struct ares_in6_addr);
    239                   for (i = 0; i < naddrs; i++)
    240                     hostent->h_addr_list[i] = (char *) &addrs[i];
    241                   hostent->h_addr_list[naddrs] = NULL;
    242                   *host = hostent;
    243                   return ARES_SUCCESS;
    244                 }
    245               free(hostent);
    246             }
    247           status = ARES_ENOMEM;
    248         }
    249     }
    250   if (aliases)
    251     {
    252       for (i = 0; i < naliases; i++)
    253         free(aliases[i]);
    254       free(aliases);
    255     }
    256   free(addrs);
    257   free(hostname);
    258   return status;
    259 }
    260