1 /* MIT License
2 *
3 * Copyright (c) 1998 Massachusetts Institute of Technology
4 * Copyright (c) The c-ares project and its contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * SPDX-License-Identifier: MIT
26 */
27
28 #include "ares_setup.h"
29
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33 #ifdef HAVE_NETDB_H
34 # include <netdb.h>
35 #endif
36 #ifdef HAVE_ARPA_INET_H
37 # include <arpa/inet.h>
38 #endif
39
40 #include "ares_nameser.h"
41
42 #include "ares.h"
43 #include "ares_inet_net_pton.h"
44 #include "ares_platform.h"
45 #include "ares_private.h"
46
47 #ifdef WATT32
48 # undef WIN32
49 #endif
50
51 struct addr_query {
52 /* Arguments passed to ares_gethostbyaddr() */
53 ares_channel_t *channel;
54 struct ares_addr addr;
55 ares_host_callback callback;
56 void *arg;
57 char *lookups; /* duplicate memory from channel for ares_reinit() */
58 const char *remaining_lookups;
59 size_t timeouts;
60 };
61
62 static void next_lookup(struct addr_query *aquery);
63 static void addr_callback(void *arg, int status, int timeouts,
64 unsigned char *abuf, int alen);
65 static void end_aquery(struct addr_query *aquery, ares_status_t status,
66 struct hostent *host);
67 static ares_status_t file_lookup(ares_channel_t *channel,
68 const struct ares_addr *addr,
69 struct hostent **host);
70
ares_gethostbyaddr_int(ares_channel_t * channel,const void * addr,int addrlen,int family,ares_host_callback callback,void * arg)71 static void ares_gethostbyaddr_int(ares_channel_t *channel, const void *addr,
72 int addrlen, int family,
73 ares_host_callback callback, void *arg)
74 {
75 struct addr_query *aquery;
76
77 if (family != AF_INET && family != AF_INET6) {
78 callback(arg, ARES_ENOTIMP, 0, NULL);
79 return;
80 }
81
82 if ((family == AF_INET && addrlen != sizeof(aquery->addr.addr.addr4)) ||
83 (family == AF_INET6 && addrlen != sizeof(aquery->addr.addr.addr6))) {
84 callback(arg, ARES_ENOTIMP, 0, NULL);
85 return;
86 }
87
88 aquery = ares_malloc(sizeof(struct addr_query));
89 if (!aquery) {
90 callback(arg, ARES_ENOMEM, 0, NULL);
91 return;
92 }
93 aquery->lookups = ares_strdup(channel->lookups);
94 if (aquery->lookups == NULL) {
95 ares_free(aquery);
96 callback(arg, ARES_ENOMEM, 0, NULL);
97 return;
98 }
99 aquery->channel = channel;
100 if (family == AF_INET) {
101 memcpy(&aquery->addr.addr.addr4, addr, sizeof(aquery->addr.addr.addr4));
102 } else {
103 memcpy(&aquery->addr.addr.addr6, addr, sizeof(aquery->addr.addr.addr6));
104 }
105 aquery->addr.family = family;
106 aquery->callback = callback;
107 aquery->arg = arg;
108 aquery->remaining_lookups = aquery->lookups;
109 aquery->timeouts = 0;
110
111 next_lookup(aquery);
112 }
113
ares_gethostbyaddr(ares_channel_t * channel,const void * addr,int addrlen,int family,ares_host_callback callback,void * arg)114 void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen,
115 int family, ares_host_callback callback, void *arg)
116 {
117 if (channel == NULL) {
118 return;
119 }
120 ares__channel_lock(channel);
121 ares_gethostbyaddr_int(channel, addr, addrlen, family, callback, arg);
122 ares__channel_unlock(channel);
123 }
124
next_lookup(struct addr_query * aquery)125 static void next_lookup(struct addr_query *aquery)
126 {
127 const char *p;
128 ares_status_t status;
129 struct hostent *host;
130 char *name;
131
132 for (p = aquery->remaining_lookups; *p; p++) {
133 switch (*p) {
134 case 'b':
135 name = ares_dns_addr_to_ptr(&aquery->addr);
136 if (name == NULL) {
137 end_aquery(aquery, ARES_ENOMEM, NULL);
138 return;
139 }
140 aquery->remaining_lookups = p + 1;
141 ares_query(aquery->channel, name, C_IN, T_PTR, addr_callback, aquery);
142 ares_free(name);
143 return;
144 case 'f':
145 status = file_lookup(aquery->channel, &aquery->addr, &host);
146
147 /* this status check below previously checked for !ARES_ENOTFOUND,
148 but we should not assume that this single error code is the one
149 that can occur, as that is in fact no longer the case */
150 if (status == ARES_SUCCESS) {
151 end_aquery(aquery, status, host);
152 return;
153 }
154 break;
155 default:
156 break;
157 }
158 }
159 end_aquery(aquery, ARES_ENOTFOUND, NULL);
160 }
161
addr_callback(void * arg,int status,int timeouts,unsigned char * abuf,int alen)162 static void addr_callback(void *arg, int status, int timeouts,
163 unsigned char *abuf, int alen)
164 {
165 struct addr_query *aquery = (struct addr_query *)arg;
166 struct hostent *host;
167 size_t addrlen;
168
169 aquery->timeouts += (size_t)timeouts;
170 if (status == ARES_SUCCESS) {
171 if (aquery->addr.family == AF_INET) {
172 addrlen = sizeof(aquery->addr.addr.addr4);
173 status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr.addr4,
174 (int)addrlen, AF_INET, &host);
175 } else {
176 addrlen = sizeof(aquery->addr.addr.addr6);
177 status = ares_parse_ptr_reply(abuf, alen, &aquery->addr.addr.addr6,
178 (int)addrlen, AF_INET6, &host);
179 }
180 end_aquery(aquery, (ares_status_t)status, host);
181 } else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
182 end_aquery(aquery, (ares_status_t)status, NULL);
183 } else {
184 next_lookup(aquery);
185 }
186 }
187
end_aquery(struct addr_query * aquery,ares_status_t status,struct hostent * host)188 static void end_aquery(struct addr_query *aquery, ares_status_t status,
189 struct hostent *host)
190 {
191 aquery->callback(aquery->arg, (int)status, (int)aquery->timeouts, host);
192 if (host) {
193 ares_free_hostent(host);
194 }
195 ares_free(aquery->lookups);
196 ares_free(aquery);
197 }
198
file_lookup(ares_channel_t * channel,const struct ares_addr * addr,struct hostent ** host)199 static ares_status_t file_lookup(ares_channel_t *channel,
200 const struct ares_addr *addr,
201 struct hostent **host)
202 {
203 char ipaddr[INET6_ADDRSTRLEN];
204 const void *ptr = NULL;
205 const ares_hosts_entry_t *entry;
206 ares_status_t status;
207
208 if (addr->family == AF_INET) {
209 ptr = &addr->addr.addr4;
210 } else if (addr->family == AF_INET6) {
211 ptr = &addr->addr.addr6;
212 }
213
214 if (ptr == NULL) {
215 return ARES_ENOTFOUND;
216 }
217
218 if (!ares_inet_ntop(addr->family, ptr, ipaddr, sizeof(ipaddr))) {
219 return ARES_ENOTFOUND;
220 }
221
222 status = ares__hosts_search_ipaddr(channel, ARES_FALSE, ipaddr, &entry);
223 if (status != ARES_SUCCESS) {
224 return status;
225 }
226
227 status = ares__hosts_entry_to_hostent(entry, addr->family, host);
228 if (status != ARES_SUCCESS) {
229 return status;
230 }
231
232 return ARES_SUCCESS;
233 }
234