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_private.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 #include "ares_inet_net_pton.h"
42
43 struct addr_query {
44 /* Arguments passed to ares_gethostbyaddr() */
45 ares_channel_t *channel;
46 struct ares_addr addr;
47 ares_host_callback callback;
48 void *arg;
49 char *lookups; /* duplicate memory from channel for ares_reinit() */
50 const char *remaining_lookups;
51 size_t timeouts;
52 };
53
54 static void next_lookup(struct addr_query *aquery);
55 static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
56 const ares_dns_record_t *dnsrec);
57 static void end_aquery(struct addr_query *aquery, ares_status_t status,
58 struct hostent *host);
59 static ares_status_t file_lookup(ares_channel_t *channel,
60 const struct ares_addr *addr,
61 struct hostent **host);
62
ares_gethostbyaddr_nolock(ares_channel_t * channel,const void * addr,int addrlen,int family,ares_host_callback callback,void * arg)63 void ares_gethostbyaddr_nolock(ares_channel_t *channel, const void *addr,
64 int addrlen, int family,
65 ares_host_callback callback, void *arg)
66 {
67 struct addr_query *aquery;
68
69 if (family != AF_INET && family != AF_INET6) {
70 callback(arg, ARES_ENOTIMP, 0, NULL);
71 return;
72 }
73
74 if ((family == AF_INET && addrlen != sizeof(aquery->addr.addr.addr4)) ||
75 (family == AF_INET6 && addrlen != sizeof(aquery->addr.addr.addr6))) {
76 callback(arg, ARES_ENOTIMP, 0, NULL);
77 return;
78 }
79
80 aquery = ares_malloc(sizeof(struct addr_query));
81 if (!aquery) {
82 callback(arg, ARES_ENOMEM, 0, NULL);
83 return;
84 }
85 aquery->lookups = ares_strdup(channel->lookups);
86 if (aquery->lookups == NULL) {
87 /* LCOV_EXCL_START: OutOfMemory */
88 ares_free(aquery);
89 callback(arg, ARES_ENOMEM, 0, NULL);
90 return;
91 /* LCOV_EXCL_STOP */
92 }
93 aquery->channel = channel;
94 if (family == AF_INET) {
95 memcpy(&aquery->addr.addr.addr4, addr, sizeof(aquery->addr.addr.addr4));
96 } else {
97 memcpy(&aquery->addr.addr.addr6, addr, sizeof(aquery->addr.addr.addr6));
98 }
99 aquery->addr.family = family;
100 aquery->callback = callback;
101 aquery->arg = arg;
102 aquery->remaining_lookups = aquery->lookups;
103 aquery->timeouts = 0;
104
105 next_lookup(aquery);
106 }
107
ares_gethostbyaddr(ares_channel_t * channel,const void * addr,int addrlen,int family,ares_host_callback callback,void * arg)108 void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen,
109 int family, ares_host_callback callback, void *arg)
110 {
111 if (channel == NULL) {
112 return;
113 }
114 ares_channel_lock(channel);
115 ares_gethostbyaddr_nolock(channel, addr, addrlen, family, callback, arg);
116 ares_channel_unlock(channel);
117 }
118
next_lookup(struct addr_query * aquery)119 static void next_lookup(struct addr_query *aquery)
120 {
121 const char *p;
122 ares_status_t status;
123 struct hostent *host = NULL;
124 char *name;
125
126 for (p = aquery->remaining_lookups; *p; p++) {
127 switch (*p) {
128 case 'b':
129 name = ares_dns_addr_to_ptr(&aquery->addr);
130 if (name == NULL) {
131 end_aquery(aquery, ARES_ENOMEM,
132 NULL); /* LCOV_EXCL_LINE: OutOfMemory */
133 return; /* LCOV_EXCL_LINE: OutOfMemory */
134 }
135 aquery->remaining_lookups = p + 1;
136 ares_query_nolock(aquery->channel, name, ARES_CLASS_IN,
137 ARES_REC_TYPE_PTR, addr_callback, aquery, NULL);
138 ares_free(name);
139 return;
140 case 'f':
141 status = file_lookup(aquery->channel, &aquery->addr, &host);
142
143 /* this status check below previously checked for !ARES_ENOTFOUND,
144 but we should not assume that this single error code is the one
145 that can occur, as that is in fact no longer the case */
146 if (status == ARES_SUCCESS) {
147 end_aquery(aquery, status, host);
148 return;
149 }
150 break;
151 default:
152 break;
153 }
154 }
155 end_aquery(aquery, ARES_ENOTFOUND, NULL);
156 }
157
addr_callback(void * arg,ares_status_t status,size_t timeouts,const ares_dns_record_t * dnsrec)158 static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
159 const ares_dns_record_t *dnsrec)
160 {
161 struct addr_query *aquery = (struct addr_query *)arg;
162 struct hostent *host;
163 size_t addrlen;
164
165 aquery->timeouts += timeouts;
166 if (status == ARES_SUCCESS) {
167 if (aquery->addr.family == AF_INET) {
168 addrlen = sizeof(aquery->addr.addr.addr4);
169 status = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr4,
170 (int)addrlen, AF_INET, &host);
171 } else {
172 addrlen = sizeof(aquery->addr.addr.addr6);
173 status = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr6,
174 (int)addrlen, AF_INET6, &host);
175 }
176 end_aquery(aquery, status, host);
177 } else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
178 end_aquery(aquery, status, NULL);
179 } else {
180 next_lookup(aquery);
181 }
182 }
183
end_aquery(struct addr_query * aquery,ares_status_t status,struct hostent * host)184 static void end_aquery(struct addr_query *aquery, ares_status_t status,
185 struct hostent *host)
186 {
187 aquery->callback(aquery->arg, (int)status, (int)aquery->timeouts, host);
188 if (host) {
189 ares_free_hostent(host);
190 }
191 ares_free(aquery->lookups);
192 ares_free(aquery);
193 }
194
file_lookup(ares_channel_t * channel,const struct ares_addr * addr,struct hostent ** host)195 static ares_status_t file_lookup(ares_channel_t *channel,
196 const struct ares_addr *addr,
197 struct hostent **host)
198 {
199 char ipaddr[INET6_ADDRSTRLEN];
200 const void *ptr = NULL;
201 const ares_hosts_entry_t *entry;
202 ares_status_t status;
203
204 if (addr->family == AF_INET) {
205 ptr = &addr->addr.addr4;
206 } else if (addr->family == AF_INET6) {
207 ptr = &addr->addr.addr6;
208 }
209
210 if (ptr == NULL) {
211 return ARES_ENOTFOUND;
212 }
213
214 if (!ares_inet_ntop(addr->family, ptr, ipaddr, sizeof(ipaddr))) {
215 return ARES_ENOTFOUND;
216 }
217
218 status = ares_hosts_search_ipaddr(channel, ARES_FALSE, ipaddr, &entry);
219 if (status != ARES_SUCCESS) {
220 return status;
221 }
222
223 status = ares_hosts_entry_to_hostent(entry, addr->family, host);
224 if (status != ARES_SUCCESS) {
225 return status; /* LCOV_EXCL_LINE: OutOfMemory */
226 }
227
228 return ARES_SUCCESS;
229 }
230