"Fossies" - the Fresh Open Source Software Archive

Member "c-ares-1.17.2/src/lib/ares__parse_into_addrinfo.c" (8 Aug 2021, 7389 Bytes) of package /linux/misc/dns/c-ares-1.17.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ares__parse_into_addrinfo.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.17.1_vs_1.17.2.

    1 /* Copyright (C) 2019 by Andrew Selivanov
    2  *
    3  * Permission to use, copy, modify, and distribute this
    4  * software and its documentation for any purpose and without
    5  * fee is hereby granted, provided that the above copyright
    6  * notice appear in all copies and that both that copyright
    7  * notice and this permission notice appear in supporting
    8  * documentation, and that the name of M.I.T. not be used in
    9  * advertising or publicity pertaining to distribution of the
   10  * software without specific, written prior permission.
   11  * M.I.T. makes no representations about the suitability of
   12  * this software for any purpose.  It is provided "as is"
   13  * without express or implied warranty.
   14  */
   15 
   16 #include "ares_setup.h"
   17 
   18 #ifdef HAVE_NETINET_IN_H
   19 #  include <netinet/in.h>
   20 #endif
   21 #ifdef HAVE_NETDB_H
   22 #  include <netdb.h>
   23 #endif
   24 #ifdef HAVE_ARPA_INET_H
   25 #  include <arpa/inet.h>
   26 #endif
   27 
   28 #include "ares_nameser.h"
   29 
   30 #ifdef HAVE_STRINGS_H
   31 #  include <strings.h>
   32 #endif
   33 
   34 #ifdef HAVE_LIMITS_H
   35 #  include <limits.h>
   36 #endif
   37 
   38 #include "ares.h"
   39 #include "ares_dns.h"
   40 #include "ares_private.h"
   41 
   42 int ares__parse_into_addrinfo2(const unsigned char *abuf,
   43                                int alen,
   44                                char **question_hostname,
   45                                struct ares_addrinfo *ai)
   46 {
   47   unsigned int qdcount, ancount;
   48   int status, i, rr_type, rr_class, rr_len, rr_ttl;
   49   int got_a = 0, got_aaaa = 0, got_cname = 0;
   50   long len;
   51   const unsigned char *aptr;
   52   char *hostname, *rr_name = NULL, *rr_data;
   53   struct ares_addrinfo_cname *cname, *cnames = NULL;
   54   struct ares_addrinfo_node *node, *nodes = NULL;
   55   struct sockaddr_in *sin;
   56   struct sockaddr_in6 *sin6;
   57 
   58   *question_hostname = NULL;
   59 
   60   /* Give up if abuf doesn't have room for a header. */
   61   if (alen < HFIXEDSZ)
   62     return ARES_EBADRESP;
   63 
   64   /* Fetch the question and answer count from the header. */
   65   qdcount = DNS_HEADER_QDCOUNT(abuf);
   66   ancount = DNS_HEADER_ANCOUNT(abuf);
   67   if (qdcount != 1)
   68     return ARES_EBADRESP;
   69 
   70 
   71   /* Expand the name from the question, and skip past the question. */
   72   aptr = abuf + HFIXEDSZ;
   73   status = ares__expand_name_for_response(aptr, abuf, alen, question_hostname, &len, 0);
   74   if (status != ARES_SUCCESS)
   75     return status;
   76   if (aptr + len + QFIXEDSZ > abuf + alen)
   77     {
   78       return ARES_EBADRESP;
   79     }
   80 
   81   hostname = *question_hostname;
   82 
   83   aptr += len + QFIXEDSZ;
   84 
   85   /* Examine each answer resource record (RR) in turn. */
   86   for (i = 0; i < (int)ancount; i++)
   87     {
   88       /* Decode the RR up to the data field. */
   89       status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len, 0);
   90       if (status != ARES_SUCCESS)
   91         {
   92           rr_name = NULL;
   93           goto failed_stat;
   94         }
   95 
   96       aptr += len;
   97       if (aptr + RRFIXEDSZ > abuf + alen)
   98         {
   99           status = ARES_EBADRESP;
  100           goto failed_stat;
  101         }
  102       rr_type = DNS_RR_TYPE(aptr);
  103       rr_class = DNS_RR_CLASS(aptr);
  104       rr_len = DNS_RR_LEN(aptr);
  105       rr_ttl = DNS_RR_TTL(aptr);
  106       aptr += RRFIXEDSZ;
  107       if (aptr + rr_len > abuf + alen)
  108         {
  109           status = ARES_EBADRESP;
  110           goto failed_stat;
  111         }
  112 
  113       if (rr_class == C_IN && rr_type == T_A
  114           && rr_len == sizeof(struct in_addr)
  115           && strcasecmp(rr_name, hostname) == 0)
  116         {
  117           got_a = 1;
  118           if (aptr + sizeof(struct in_addr) > abuf + alen)
  119           {  /* LCOV_EXCL_START: already checked above */
  120             status = ARES_EBADRESP;
  121             goto failed_stat;
  122           }  /* LCOV_EXCL_STOP */
  123 
  124           node = ares__append_addrinfo_node(&nodes);
  125           if (!node)
  126             {
  127               status = ARES_ENOMEM;
  128               goto failed_stat;
  129             }
  130 
  131           sin = ares_malloc(sizeof(struct sockaddr_in));
  132           if (!sin)
  133             {
  134               status = ARES_ENOMEM;
  135               goto failed_stat;
  136             }
  137           memset(sin, 0, sizeof(struct sockaddr_in));
  138           memcpy(&sin->sin_addr.s_addr, aptr, sizeof(struct in_addr));
  139           sin->sin_family = AF_INET;
  140 
  141           node->ai_addr = (struct sockaddr *)sin;
  142           node->ai_family = AF_INET;
  143           node->ai_addrlen = sizeof(struct sockaddr_in);
  144 
  145           node->ai_ttl = rr_ttl;
  146 
  147           status = ARES_SUCCESS;
  148         }
  149       else if (rr_class == C_IN && rr_type == T_AAAA
  150           && rr_len == sizeof(struct ares_in6_addr)
  151           && strcasecmp(rr_name, hostname) == 0)
  152         {
  153           got_aaaa = 1;
  154           if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
  155           {  /* LCOV_EXCL_START: already checked above */
  156             status = ARES_EBADRESP;
  157             goto failed_stat;
  158           }  /* LCOV_EXCL_STOP */
  159 
  160           node = ares__append_addrinfo_node(&nodes);
  161           if (!node)
  162             {
  163               status = ARES_ENOMEM;
  164               goto failed_stat;
  165             }
  166 
  167           sin6 = ares_malloc(sizeof(struct sockaddr_in6));
  168           if (!sin6)
  169             {
  170               status = ARES_ENOMEM;
  171               goto failed_stat;
  172             }
  173 
  174           memset(sin6, 0, sizeof(struct sockaddr_in6));
  175           memcpy(&sin6->sin6_addr.s6_addr, aptr, sizeof(struct ares_in6_addr));
  176           sin6->sin6_family = AF_INET6;
  177 
  178           node->ai_addr = (struct sockaddr *)sin6;
  179           node->ai_family = AF_INET6;
  180           node->ai_addrlen = sizeof(struct sockaddr_in6);
  181 
  182           node->ai_ttl = rr_ttl;
  183 
  184           status = ARES_SUCCESS;
  185         }
  186 
  187       if (rr_class == C_IN && rr_type == T_CNAME)
  188         {
  189           got_cname = 1;
  190           status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
  191                                                   &len, 1);
  192           if (status != ARES_SUCCESS)
  193             {
  194               goto failed_stat;
  195             }
  196 
  197           /* Decode the RR data and replace the hostname with it. */
  198           /* SA: Seems wrong as it introduses order dependency. */
  199           hostname = rr_data;
  200 
  201           cname = ares__append_addrinfo_cname(&cnames);
  202           if (!cname)
  203             {
  204               status = ARES_ENOMEM;
  205               ares_free(rr_data);
  206               goto failed_stat;
  207             }
  208           cname->ttl = rr_ttl;
  209           cname->alias = rr_name;
  210           cname->name = rr_data;
  211         }
  212       else
  213         {
  214           ares_free(rr_name);
  215         }
  216 
  217 
  218       aptr += rr_len;
  219       if (aptr > abuf + alen)
  220         {  /* LCOV_EXCL_START: already checked above */
  221           status = ARES_EBADRESP;
  222           goto failed_stat;
  223         }  /* LCOV_EXCL_STOP */
  224     }
  225 
  226   if (status == ARES_SUCCESS)
  227     {
  228       ares__addrinfo_cat_nodes(&ai->nodes, nodes);
  229       if (got_cname)
  230         {
  231           ares__addrinfo_cat_cnames(&ai->cnames, cnames);
  232           return status;
  233         }
  234       else if (got_a == 0 && got_aaaa == 0)
  235         {
  236           /* the check for naliases to be zero is to make sure CNAME responses
  237              don't get caught here */
  238           status = ARES_ENODATA;
  239         }
  240     }
  241 
  242   return status;
  243 
  244 failed_stat:
  245   ares_free(rr_name);
  246   ares__freeaddrinfo_cnames(cnames);
  247   ares__freeaddrinfo_nodes(nodes);
  248   return status;
  249 }
  250 
  251 int ares__parse_into_addrinfo(const unsigned char *abuf,
  252                               int alen,
  253                               struct ares_addrinfo *ai)
  254 {
  255   int status;
  256   char *question_hostname;
  257   status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, ai);
  258   ares_free(question_hostname);
  259   return status;
  260 }