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 51struct 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 62static void next_lookup(struct addr_query *aquery); 63static void addr_callback(void *arg, int status, int timeouts, 64 unsigned char *abuf, int alen); 65static void end_aquery(struct addr_query *aquery, ares_status_t status, 66 struct hostent *host); 67static ares_status_t file_lookup(ares_channel_t *channel, 68 const struct ares_addr *addr, 69 struct hostent **host); 70 71static 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 114void 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 125static 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 162static 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 188static 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 199static 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