source: trunk/athena/lib/ares/ares_parse_a_reply.c @ 23901

Revision 23901, 4.3 KB checked in by ghudson, 15 years ago (diff)
In the ares upstream sources, plug some memory leaks found by Mark Manley.
Line 
1/* Copyright 1998 by the Massachusetts Institute of Technology.
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
16static const char rcsid[] = "$Id: ares_parse_a_reply.c,v 1.3 2003-09-12 00:25:17 mwhitson Exp $";
17
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <arpa/nameser.h>
23#include <stdlib.h>
24#include <string.h>
25#include <netdb.h>
26#include "ares.h"
27
28int ares_parse_a_reply(const unsigned char *abuf, int alen,
29                       struct hostent **host)
30{
31  int status, i, len, naddrs;
32  int naliases;
33  char *hostname, *rr_data, **aliases;
34  struct ares_dns_message *message;
35  struct ares_dns_rr *rr;
36  struct in_addr *addrs;
37  struct hostent *hostent;
38
39  /* Set *host to NULL for all failure cases. */
40  *host = NULL;
41
42  status = ares_parse_message(abuf, alen, &message);
43  if (status != ARES_SUCCESS)
44    return status;
45
46  if (message->qcount != 1)
47    {
48      ares_free_dns_message(message);
49      return ARES_EBADRESP;
50    }
51
52  hostname = strdup(message->questions[0].name);
53  if (!hostname)
54    {
55      ares_free_dns_message(message);
56      return ARES_ENOMEM;
57    }
58
59  /* Allocate addresses and aliases; message->answers.count gives an
60   * upper bound for both.
61   */
62  addrs = malloc(message->answers.count * sizeof(struct in_addr));
63  if (!addrs)
64    {
65      ares_free_dns_message(message);
66      free(hostname);
67      return ARES_ENOMEM;
68    }
69  aliases = malloc((message->answers.count + 1) * sizeof(char *));
70  if (!aliases)
71    {
72      ares_free_dns_message(message);
73      free(hostname);
74      free(addrs);
75      return ARES_ENOMEM;
76    }
77  naddrs = 0;
78  naliases = 0;
79
80  /* Examine each answer resource record (RR) in turn. */
81  for (i = 0; i < message->answers.count; i++)
82    {
83      rr = &message->answers.records[i];
84      if (rr->dnsclass == C_IN && rr->type == T_A
85          && rr->len == sizeof(struct in_addr)
86          && strcasecmp(rr->name, hostname) == 0)
87        {
88          memcpy(&addrs[naddrs], rr->data, sizeof(struct in_addr));
89          naddrs++;
90          status = ARES_SUCCESS;
91        }
92
93      if (rr->dnsclass == C_IN && rr->type == T_CNAME)
94        {
95          /* Record the RR name as an alias. */
96          aliases[naliases] = strdup(rr->name);
97          if (aliases[naliases] == NULL)
98            {
99              status = ARES_ENOMEM;
100              break;
101            }
102          naliases++;
103
104          /* Decode the RR data and replace the hostname with it. */
105
106          /* ares_parse_message() resolves compression pointers in the
107           * RR data, but the data still need to be expanded.  Since
108           * we know there is no indirection, use the data buffer
109           * itself as the containing buffer.
110           */
111          status = ares_expand_name(rr->data, rr->data, rr->len,
112                                    &rr_data, &len);
113          if (status != ARES_SUCCESS)
114            break;
115          free(hostname);
116          hostname = rr_data;
117        }
118    }
119
120  if (status == ARES_SUCCESS && naddrs == 0)
121    status = ARES_ENODATA;
122  if (status == ARES_SUCCESS)
123    {
124      /* We got our answer.  Allocate memory to build the host entry. */
125      aliases[naliases] = NULL;
126      hostent = malloc(sizeof(struct hostent));
127      if (hostent)
128        {
129          hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *));
130          if (hostent->h_addr_list)
131            {
132              /* Fill in the hostent and return successfully. */
133              hostent->h_name = hostname;
134              hostent->h_aliases = aliases;
135              hostent->h_addrtype = AF_INET;
136              hostent->h_length = sizeof(struct in_addr);
137              for (i = 0; i < naddrs; i++)
138                hostent->h_addr_list[i] = (char *) &addrs[i];
139              hostent->h_addr_list[naddrs] = NULL;
140              *host = hostent;
141              ares_free_dns_message(message);
142              return ARES_SUCCESS;
143            }
144          free(hostent);
145        }
146      status = ARES_ENOMEM;
147    }
148  for (i = 0; i < naliases; i++)
149    free(aliases[i]);
150  free(aliases);
151  free(addrs);
152  free(hostname);
153  ares_free_dns_message(message);
154  return status;
155}
Note: See TracBrowser for help on using the repository browser.