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