1968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
2968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold/* Copyright 1998 by the Massachusetts Institute of Technology.
3968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold *
4968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * Permission to use, copy, modify, and distribute this
5968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software and its documentation for any purpose and without
6968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * fee is hereby granted, provided that the above copyright
7968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice appear in all copies and that both that copyright
8968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * notice and this permission notice appear in supporting
9968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * documentation, and that the name of M.I.T. not be used in
10968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * advertising or publicity pertaining to distribution of the
11968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * software without specific, written prior permission.
12968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * M.I.T. makes no representations about the suitability of
13968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * this software for any purpose.  It is provided "as is"
14968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold * without express or implied warranty.
15968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold */
16968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
17968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_setup.h"
18968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
19968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_SYS_SOCKET_H
20968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <sys/socket.h>
21968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
22968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETINET_IN_H
23968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netinet/in.h>
24968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
25968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_NETDB_H
26968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <netdb.h>
27968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
28968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_H
29968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser.h>
30968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#else
31968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include "nameser.h"
32968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
33968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_ARPA_NAMESER_COMPAT_H
34968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <arpa/nameser_compat.h>
35968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
36968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
37968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#ifdef HAVE_STRINGS_H
38968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#  include <strings.h>
39968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#endif
40968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
41968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <stdlib.h>
42968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include <string.h>
43968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares.h"
44968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_dns.h"
45968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold#include "ares_private.h"
46968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
47968bf19396ad404e89420f5d67900fce13f4186cGilad Arnoldint ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
48968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                         int addrlen, int family, struct hostent **host)
49968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold{
50968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  unsigned int qdcount, ancount;
51968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int status, i, rr_type, rr_class, rr_len;
52968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  long len;
53968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  const unsigned char *aptr;
54968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char *ptrname, *hostname, *rr_name, *rr_data;
55968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  struct hostent *hostent;
56968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int aliascnt = 0;
57968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  int alias_alloc = 8;
58968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  char ** aliases;
59968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
60968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Set *host to NULL for all failure cases. */
61968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  *host = NULL;
62968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
63968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Give up if abuf doesn't have room for a header. */
64968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (alen < HFIXEDSZ)
65968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return ARES_EBADRESP;
66968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
67968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Fetch the question and answer count from the header. */
68968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  qdcount = DNS_HEADER_QDCOUNT(abuf);
69968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  ancount = DNS_HEADER_ANCOUNT(abuf);
70968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (qdcount != 1)
71968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return ARES_EBADRESP;
72968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
73968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Expand the name from the question, and skip past the question. */
74968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  aptr = abuf + HFIXEDSZ;
75968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len);
76968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status != ARES_SUCCESS)
77968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    return status;
78968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (aptr + len + QFIXEDSZ > abuf + alen)
79968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
80968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(ptrname);
81968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return ARES_EBADRESP;
82968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
83968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  aptr += len + QFIXEDSZ;
84968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
85968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  /* Examine each answer resource record (RR) in turn. */
86968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  hostname = NULL;
87968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  aliases = malloc(alias_alloc * sizeof(char *));
88968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (!aliases)
89968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
90968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(ptrname);
91968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      return ARES_ENOMEM;
92968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
93968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  for (i = 0; i < (int)ancount; i++)
94968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
95968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* Decode the RR up to the data field. */
96968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
97968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (status != ARES_SUCCESS)
98968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        break;
99968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += len;
100968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (aptr + RRFIXEDSZ > abuf + alen)
101968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
102968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          free(rr_name);
103968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          status = ARES_EBADRESP;
104968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          break;
105968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
106968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_type = DNS_RR_TYPE(aptr);
107968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_class = DNS_RR_CLASS(aptr);
108968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      rr_len = DNS_RR_LEN(aptr);
109968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += RRFIXEDSZ;
110968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
111968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (rr_class == C_IN && rr_type == T_PTR
112968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          && strcasecmp(rr_name, ptrname) == 0)
113968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
114968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Decode the RR data and set hostname to it. */
115968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
116968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                                  &len);
117968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (status != ARES_SUCCESS)
118968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
119968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              free(rr_name);
120968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
121968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
122968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (hostname)
123968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            free(hostname);
124968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          hostname = rr_data;
125968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char));
126968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (!aliases[aliascnt])
127968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
128968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              free(rr_name);
129968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              status = ARES_ENOMEM;
130968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
131968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
132968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1);
133968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          aliascnt++;
134968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (aliascnt >= alias_alloc) {
135968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            char **ptr;
136968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            alias_alloc *= 2;
137968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            ptr = realloc(aliases, alias_alloc * sizeof(char *));
138968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            if(!ptr) {
139968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              free(rr_name);
140968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              status = ARES_ENOMEM;
141968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
142968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
143968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            aliases = ptr;
144968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          }
145968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
146968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
147968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (rr_class == C_IN && rr_type == T_CNAME)
148968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
149968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          /* Decode the RR data and replace ptrname with it. */
150968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
151968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                                                  &len);
152968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (status != ARES_SUCCESS)
153968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
154968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              free(rr_name);
155968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              break;
156968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
157968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          free(ptrname);
158968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          ptrname = rr_data;
159968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
160968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
161968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(rr_name);
162968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      aptr += rr_len;
163968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (aptr > abuf + alen)
164968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
165968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          status = ARES_EBADRESP;
166968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          break;
167968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
168968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
169968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold
170968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status == ARES_SUCCESS && !hostname)
171968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    status = ARES_ENODATA;
172968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (status == ARES_SUCCESS)
173968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    {
174968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      /* We got our answer.  Allocate memory to build the host entry. */
175968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      hostent = malloc(sizeof(struct hostent));
176968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      if (hostent)
177968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        {
178968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          hostent->h_addr_list = malloc(2 * sizeof(char *));
179968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          if (hostent->h_addr_list)
180968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            {
181968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              hostent->h_addr_list[0] = malloc(addrlen);
182968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              if (hostent->h_addr_list[0])
183968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                {
184968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                  hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *));
185968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                  if (hostent->h_aliases)
186968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                    {
187968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      /* Fill in the hostent and return successfully. */
188968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      hostent->h_name = hostname;
189968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      for (i=0 ; i<aliascnt ; i++)
190968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                        hostent->h_aliases[i] = aliases[i];
191968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      hostent->h_aliases[aliascnt] = NULL;
192968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      hostent->h_addrtype = family;
193968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      hostent->h_length = addrlen;
194968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      memcpy(hostent->h_addr_list[0], addr, addrlen);
195968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      hostent->h_addr_list[1] = NULL;
196968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      *host = hostent;
197968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      free(aliases);
198968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      free(ptrname);
199968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                      return ARES_SUCCESS;
200968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                    }
201968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                  free(hostent->h_addr_list[0]);
202968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold                }
203968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold              free(hostent->h_addr_list);
204968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold            }
205968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold          free(hostent);
206968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold        }
207968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      status = ARES_ENOMEM;
208968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    }
209968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  for (i=0 ; i<aliascnt ; i++)
210968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    if (aliases[i])
211968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold      free(aliases[i]);
212968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  free(aliases);
213968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  if (hostname)
214968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold    free(hostname);
215968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  free(ptrname);
216968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold  return status;
217968bf19396ad404e89420f5d67900fce13f4186cGilad Arnold}
218