Coverage Report

Created: 2023-09-25 07:14

/src/c-ares/src/lib/ares_parse_ns_reply.c
Line
Count
Source (jump to first uncovered 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
 * SPDX-License-Identifier: MIT
16
 */
17
18
/*
19
 * ares_parse_ns_reply created by Vlad Dinulescu <vlad.dinulescu@avira.com>
20
 *      on behalf of AVIRA Gmbh - http://www.avira.com
21
 */
22
23
#include "ares_setup.h"
24
25
#ifdef HAVE_NETINET_IN_H
26
#  include <netinet/in.h>
27
#endif
28
#ifdef HAVE_NETDB_H
29
#  include <netdb.h>
30
#endif
31
#ifdef HAVE_ARPA_INET_H
32
#  include <arpa/inet.h>
33
#endif
34
35
#include "ares_nameser.h"
36
37
#include "ares.h"
38
#include "ares_dns.h"
39
#include "ares_private.h"
40
41
int ares_parse_ns_reply( const unsigned char* abuf, int alen,
42
                         struct hostent** host )
43
1.62k
{
44
1.62k
  unsigned int qdcount, ancount;
45
1.62k
  int status, i, rr_type, rr_class, rr_len;
46
1.62k
  int nameservers_num;
47
1.62k
  long len;
48
1.62k
  const unsigned char *aptr;
49
1.62k
  char* hostname, *rr_name, *rr_data, **nameservers;
50
1.62k
  struct hostent *hostent;
51
52
  /* Set *host to NULL for all failure cases. */
53
1.62k
  *host = NULL;
54
55
  /* Give up if abuf doesn't have room for a header. */
56
1.62k
  if ( alen < HFIXEDSZ )
57
6
    return ARES_EBADRESP;
58
59
  /* Fetch the question and answer count from the header. */
60
1.61k
  qdcount = DNS_HEADER_QDCOUNT( abuf );
61
1.61k
  ancount = DNS_HEADER_ANCOUNT( abuf );
62
1.61k
  if ( qdcount != 1 )
63
18
    return ARES_EBADRESP;
64
65
  /* Expand the name from the question, and skip past the question. */
66
1.59k
  aptr = abuf + HFIXEDSZ;
67
1.59k
  status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len, 0);
68
1.59k
  if ( status != ARES_SUCCESS )
69
100
    return status;
70
1.49k
  if ( aptr + len + QFIXEDSZ > abuf + alen )
71
63
  {
72
63
    ares_free( hostname );
73
63
    return ARES_EBADRESP;
74
63
  }
75
1.43k
  aptr += len + QFIXEDSZ;
76
77
  /* Allocate nameservers array; ancount gives an upper bound */
78
1.43k
  nameservers = ares_malloc( ( ancount + 1 ) * sizeof( char * ) );
79
1.43k
  if ( !nameservers )
80
0
  {
81
0
    ares_free( hostname );
82
0
    return ARES_ENOMEM;
83
0
  }
84
1.43k
  nameservers_num = 0;
85
86
  /* Examine each answer resource record (RR) in turn. */
87
224k
  for ( i = 0; i < ( int ) ancount; i++ )
88
224k
  {
89
    /* Decode the RR up to the data field. */
90
224k
    status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len, 0);
91
224k
    if ( status != ARES_SUCCESS )
92
871
      break;
93
223k
    aptr += len;
94
223k
    if ( aptr + RRFIXEDSZ > abuf + alen )
95
160
    {
96
160
      status = ARES_EBADRESP;
97
160
      ares_free(rr_name);
98
160
      break;
99
160
    }
100
223k
    rr_type = DNS_RR_TYPE( aptr );
101
223k
    rr_class = DNS_RR_CLASS( aptr );
102
223k
    rr_len = DNS_RR_LEN( aptr );
103
223k
    aptr += RRFIXEDSZ;
104
223k
    if (aptr + rr_len > abuf + alen)
105
20
      {
106
20
        ares_free(rr_name);
107
20
        status = ARES_EBADRESP;
108
20
        break;
109
20
      }
110
111
223k
    if ( rr_class == C_IN && rr_type == T_NS )
112
37.1k
    {
113
      /* Decode the RR data and add it to the nameservers list */
114
37.1k
      status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data,
115
37.1k
                                               &len, 1);
116
37.1k
      if ( status != ARES_SUCCESS )
117
20
      {
118
20
        ares_free(rr_name);
119
20
        break;
120
20
      }
121
122
37.1k
      nameservers[nameservers_num] = ares_malloc(strlen(rr_data)+1);
123
124
37.1k
      if (nameservers[nameservers_num]==NULL)
125
0
      {
126
0
        ares_free(rr_name);
127
0
        ares_free(rr_data);
128
0
        status=ARES_ENOMEM;
129
0
        break;
130
0
      }
131
37.1k
      strcpy(nameservers[nameservers_num],rr_data);
132
37.1k
      ares_free(rr_data);
133
134
37.1k
      nameservers_num++;
135
37.1k
    }
136
137
223k
    ares_free( rr_name );
138
139
223k
    aptr += rr_len;
140
223k
    if ( aptr > abuf + alen )
141
0
    {  /* LCOV_EXCL_START: already checked above */
142
0
      status = ARES_EBADRESP;
143
0
      break;
144
0
    }  /* LCOV_EXCL_STOP */
145
223k
  }
146
147
1.43k
  if ( status == ARES_SUCCESS && nameservers_num == 0 )
148
342
  {
149
342
    status = ARES_ENODATA;
150
342
  }
151
1.43k
  if ( status == ARES_SUCCESS )
152
23
  {
153
    /* We got our answer.  Allocate memory to build the host entry. */
154
23
    nameservers[nameservers_num] = NULL;
155
23
    hostent = ares_malloc( sizeof( struct hostent ) );
156
23
    if ( hostent )
157
23
    {
158
23
      hostent->h_addr_list = ares_malloc( 1 * sizeof( char * ) );
159
23
      if ( hostent->h_addr_list )
160
23
      {
161
        /* Fill in the hostent and return successfully. */
162
23
        hostent->h_name = hostname;
163
23
        hostent->h_aliases = nameservers;
164
23
        hostent->h_addrtype = AF_INET;
165
23
        hostent->h_length = sizeof( struct in_addr );
166
23
        hostent->h_addr_list[0] = NULL;
167
23
        *host = hostent;
168
23
        return ARES_SUCCESS;
169
23
      }
170
0
      ares_free( hostent );
171
0
    }
172
0
    status = ARES_ENOMEM;
173
0
  }
174
18.5k
  for ( i = 0; i < nameservers_num; i++ )
175
17.1k
    ares_free( nameservers[i] );
176
1.41k
  ares_free( nameservers );
177
1.41k
  ares_free( hostname );
178
1.41k
  return status;
179
1.43k
}