• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 2023 Brad House
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * SPDX-License-Identifier: MIT
25  */
26 
27 #include "ares_private.h"
28 
29 #ifdef HAVE_NETINET_IN_H
30 #  include <netinet/in.h>
31 #endif
32 #ifdef HAVE_NETDB_H
33 #  include <netdb.h>
34 #endif
35 #ifdef HAVE_ARPA_INET_H
36 #  include <arpa/inet.h>
37 #endif
38 
ares_parse_ns_reply(const unsigned char * abuf,int alen_int,struct hostent ** host)39 int ares_parse_ns_reply(const unsigned char *abuf, int alen_int,
40                         struct hostent **host)
41 {
42   ares_status_t      status;
43   size_t             alen;
44   size_t             nscount  = 0;
45   struct hostent    *hostent  = NULL;
46   const char        *hostname = NULL;
47   ares_dns_record_t *dnsrec   = NULL;
48   size_t             i;
49   size_t             ancount;
50 
51   *host = NULL;
52 
53   if (alen_int < 0) {
54     return ARES_EBADRESP;
55   }
56 
57   alen = (size_t)alen_int;
58 
59   status = ares_dns_parse(abuf, alen, 0, &dnsrec);
60   if (status != ARES_SUCCESS) {
61     goto done;
62   }
63 
64   ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER);
65   if (ancount == 0) {
66     status = ARES_ENODATA;
67     goto done;
68   }
69 
70   /* Response structure */
71   hostent = ares_malloc(sizeof(*hostent));
72   if (hostent == NULL) {
73     status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
74     goto done;            /* LCOV_EXCL_LINE: OutOfMemory */
75   }
76 
77   memset(hostent, 0, sizeof(*hostent));
78 
79   hostent->h_addr_list = ares_malloc(sizeof(*hostent->h_addr_list));
80   if (hostent->h_addr_list == NULL) {
81     status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
82     goto done;            /* LCOV_EXCL_LINE: OutOfMemory */
83   }
84   hostent->h_addr_list[0] = NULL;
85   hostent->h_addrtype     = AF_INET;
86   hostent->h_length       = sizeof(struct in_addr);
87 
88   /* Fill in hostname */
89   status = ares_dns_record_query_get(dnsrec, 0, &hostname, NULL, NULL);
90   if (status != ARES_SUCCESS) {
91     goto done; /* LCOV_EXCL_LINE: DefensiveCoding */
92   }
93   hostent->h_name = ares_strdup(hostname);
94   if (hostent->h_name == NULL) {
95     status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
96     goto done;            /* LCOV_EXCL_LINE: OutOfMemory */
97   }
98 
99   /* Preallocate the maximum number + 1 */
100   hostent->h_aliases = ares_malloc((ancount + 1) * sizeof(*hostent->h_aliases));
101   if (hostent->h_aliases == NULL) {
102     status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
103     goto done;            /* LCOV_EXCL_LINE: OutOfMemory */
104   }
105   memset(hostent->h_aliases, 0, (ancount + 1) * sizeof(*hostent->h_aliases));
106 
107   for (i = 0; i < ancount; i++) {
108     const ares_dns_rr_t *rr =
109       ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i);
110 
111     if (rr == NULL) {
112       /* Shouldn't be possible */
113       status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */
114       goto done;              /* LCOV_EXCL_LINE: DefensiveCoding */
115     }
116 
117     if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN ||
118         ares_dns_rr_get_type(rr) != ARES_REC_TYPE_NS) {
119       continue;
120     }
121 
122     hostname = ares_dns_rr_get_str(rr, ARES_RR_NS_NSDNAME);
123     if (hostname == NULL) {
124       status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */
125       goto done;              /* LCOV_EXCL_LINE: DefensiveCoding */
126     }
127 
128     hostent->h_aliases[nscount] = ares_strdup(hostname);
129     if (hostent->h_aliases[nscount] == NULL) {
130       status = ARES_ENOMEM;
131       goto done;
132     }
133     nscount++;
134   }
135 
136   if (nscount == 0) {
137     status = ARES_ENODATA;
138   } else {
139     status = ARES_SUCCESS;
140   }
141 
142 done:
143   if (status != ARES_SUCCESS) {
144     ares_free_hostent(hostent);
145     /* Compatibility */
146     if (status == ARES_EBADNAME) {
147       status = ARES_EBADRESP;
148     }
149   } else {
150     *host = hostent;
151   }
152   ares_dns_record_destroy(dnsrec);
153   return (int)status;
154 }
155