Home | History | Annotate | Download | only in c-ares
      1 
      2 /* Copyright 1998 by the Massachusetts Institute of Technology.
      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_NETDB_H
     26 #  include <netdb.h>
     27 #endif
     28 #ifdef HAVE_ARPA_NAMESER_H
     29 #  include <arpa/nameser.h>
     30 #else
     31 #  include "nameser.h"
     32 #endif
     33 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
     34 #  include <arpa/nameser_compat.h>
     35 #endif
     36 
     37 #ifdef HAVE_STRINGS_H
     38 #  include <strings.h>
     39 #endif
     40 
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include "ares.h"
     44 #include "ares_dns.h"
     45 #include "ares_private.h"
     46 
     47 int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
     48                          int addrlen, int family, struct hostent **host)
     49 {
     50   unsigned int qdcount, ancount;
     51   int status, i, rr_type, rr_class, rr_len;
     52   long len;
     53   const unsigned char *aptr;
     54   char *ptrname, *hostname, *rr_name, *rr_data;
     55   struct hostent *hostent;
     56   int aliascnt = 0;
     57   int alias_alloc = 8;
     58   char ** aliases;
     59 
     60   /* Set *host to NULL for all failure cases. */
     61   *host = NULL;
     62 
     63   /* Give up if abuf doesn't have room for a header. */
     64   if (alen < HFIXEDSZ)
     65     return ARES_EBADRESP;
     66 
     67   /* Fetch the question and answer count from the header. */
     68   qdcount = DNS_HEADER_QDCOUNT(abuf);
     69   ancount = DNS_HEADER_ANCOUNT(abuf);
     70   if (qdcount != 1)
     71     return ARES_EBADRESP;
     72 
     73   /* Expand the name from the question, and skip past the question. */
     74   aptr = abuf + HFIXEDSZ;
     75   status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len);
     76   if (status != ARES_SUCCESS)
     77     return status;
     78   if (aptr + len + QFIXEDSZ > abuf + alen)
     79     {
     80       free(ptrname);
     81       return ARES_EBADRESP;
     82     }
     83   aptr += len + QFIXEDSZ;
     84 
     85   /* Examine each answer resource record (RR) in turn. */
     86   hostname = NULL;
     87   aliases = malloc(alias_alloc * sizeof(char *));
     88   if (!aliases)
     89     {
     90       free(ptrname);
     91       return ARES_ENOMEM;
     92     }
     93   for (i = 0; i < (int)ancount; i++)
     94     {
     95       /* Decode the RR up to the data field. */
     96       status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
     97       if (status != ARES_SUCCESS)
     98         break;
     99       aptr += len;
    100       if (aptr + RRFIXEDSZ > abuf + alen)
    101         {
    102           free(rr_name);
    103           status = ARES_EBADRESP;
    104           break;
    105         }
    106       rr_type = DNS_RR_TYPE(aptr);
    107       rr_class = DNS_RR_CLASS(aptr);
    108       rr_len = DNS_RR_LEN(aptr);
    109       aptr += RRFIXEDSZ;
    110 
    111       if (rr_class == C_IN && rr_type == T_PTR
    112           && strcasecmp(rr_name, ptrname) == 0)
    113         {
    114           /* Decode the RR data and set hostname to it. */
    115           status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
    116                                                   &len);
    117           if (status != ARES_SUCCESS)
    118             {
    119               free(rr_name);
    120               break;
    121             }
    122           if (hostname)
    123             free(hostname);
    124           hostname = rr_data;
    125           aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char));
    126           if (!aliases[aliascnt])
    127             {
    128               free(rr_name);
    129               status = ARES_ENOMEM;
    130               break;
    131             }
    132           strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1);
    133           aliascnt++;
    134           if (aliascnt >= alias_alloc) {
    135             char **ptr;
    136             alias_alloc *= 2;
    137             ptr = realloc(aliases, alias_alloc * sizeof(char *));
    138             if(!ptr) {
    139               free(rr_name);
    140               status = ARES_ENOMEM;
    141               break;
    142             }
    143             aliases = ptr;
    144           }
    145         }
    146 
    147       if (rr_class == C_IN && rr_type == T_CNAME)
    148         {
    149           /* Decode the RR data and replace ptrname with it. */
    150           status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
    151                                                   &len);
    152           if (status != ARES_SUCCESS)
    153             {
    154               free(rr_name);
    155               break;
    156             }
    157           free(ptrname);
    158           ptrname = rr_data;
    159         }
    160 
    161       free(rr_name);
    162       aptr += rr_len;
    163       if (aptr > abuf + alen)
    164         {
    165           status = ARES_EBADRESP;
    166           break;
    167         }
    168     }
    169 
    170   if (status == ARES_SUCCESS && !hostname)
    171     status = ARES_ENODATA;
    172   if (status == ARES_SUCCESS)
    173     {
    174       /* We got our answer.  Allocate memory to build the host entry. */
    175       hostent = malloc(sizeof(struct hostent));
    176       if (hostent)
    177         {
    178           hostent->h_addr_list = malloc(2 * sizeof(char *));
    179           if (hostent->h_addr_list)
    180             {
    181               hostent->h_addr_list[0] = malloc(addrlen);
    182               if (hostent->h_addr_list[0])
    183                 {
    184                   hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *));
    185                   if (hostent->h_aliases)
    186                     {
    187                       /* Fill in the hostent and return successfully. */
    188                       hostent->h_name = hostname;
    189                       for (i=0 ; i<aliascnt ; i++)
    190                         hostent->h_aliases[i] = aliases[i];
    191                       hostent->h_aliases[aliascnt] = NULL;
    192                       hostent->h_addrtype = family;
    193                       hostent->h_length = addrlen;
    194                       memcpy(hostent->h_addr_list[0], addr, addrlen);
    195                       hostent->h_addr_list[1] = NULL;
    196                       *host = hostent;
    197                       free(aliases);
    198                       free(ptrname);
    199                       return ARES_SUCCESS;
    200                     }
    201                   free(hostent->h_addr_list[0]);
    202                 }
    203               free(hostent->h_addr_list);
    204             }
    205           free(hostent);
    206         }
    207       status = ARES_ENOMEM;
    208     }
    209   for (i=0 ; i<aliascnt ; i++)
    210     if (aliases[i])
    211       free(aliases[i]);
    212   free(aliases);
    213   if (hostname)
    214     free(hostname);
    215   free(ptrname);
    216   return status;
    217 }
    218