ares_addrinfo_localhost.c (7100B)
1 /* MIT License 2 * 3 * Copyright (c) Massachusetts Institute of Technology 4 * Copyright (c) Daniel Stenberg 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 #if defined(USE_WINSOCK) 41 # if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 42 # include <ws2ipdef.h> 43 # endif 44 # if defined(HAVE_IPHLPAPI_H) 45 # include <iphlpapi.h> 46 # endif 47 # if defined(HAVE_NETIOAPI_H) 48 # include <netioapi.h> 49 # endif 50 #endif 51 52 static ares_bool_t ares_ai_has_family(int aftype, 53 const struct ares_addrinfo_node *nodes) 54 { 55 const struct ares_addrinfo_node *node; 56 57 for (node = nodes; node != NULL; node = node->ai_next) { 58 if (node->ai_family == aftype) 59 return ARES_TRUE; 60 } 61 62 return ARES_FALSE; 63 } 64 65 ares_status_t ares_append_ai_node(int aftype, unsigned short port, 66 unsigned int ttl, const void *adata, 67 struct ares_addrinfo_node **nodes) 68 { 69 struct ares_addrinfo_node *node; 70 71 node = ares_append_addrinfo_node(nodes); 72 if (!node) { 73 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 74 } 75 76 memset(node, 0, sizeof(*node)); 77 78 if (aftype == AF_INET) { 79 struct sockaddr_in *sin = ares_malloc(sizeof(*sin)); 80 if (!sin) { 81 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 82 } 83 84 memset(sin, 0, sizeof(*sin)); 85 memcpy(&sin->sin_addr.s_addr, adata, sizeof(sin->sin_addr.s_addr)); 86 sin->sin_family = AF_INET; 87 sin->sin_port = htons(port); 88 89 node->ai_addr = (struct sockaddr *)sin; 90 node->ai_family = AF_INET; 91 node->ai_addrlen = sizeof(*sin); 92 node->ai_addr = (struct sockaddr *)sin; 93 node->ai_ttl = (int)ttl; 94 } 95 96 if (aftype == AF_INET6) { 97 struct sockaddr_in6 *sin6 = ares_malloc(sizeof(*sin6)); 98 if (!sin6) { 99 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 100 } 101 102 memset(sin6, 0, sizeof(*sin6)); 103 memcpy(&sin6->sin6_addr.s6_addr, adata, sizeof(sin6->sin6_addr.s6_addr)); 104 sin6->sin6_family = AF_INET6; 105 sin6->sin6_port = htons(port); 106 107 node->ai_addr = (struct sockaddr *)sin6; 108 node->ai_family = AF_INET6; 109 node->ai_addrlen = sizeof(*sin6); 110 node->ai_addr = (struct sockaddr *)sin6; 111 node->ai_ttl = (int)ttl; 112 } 113 114 return ARES_SUCCESS; 115 } 116 117 static ares_status_t 118 ares_default_loopback_addrs(int aftype, unsigned short port, 119 struct ares_addrinfo_node **nodes) 120 { 121 ares_status_t status = ARES_SUCCESS; 122 123 if ((aftype == AF_UNSPEC || aftype == AF_INET6) && 124 !ares_ai_has_family(AF_INET6, *nodes)) { 125 struct ares_in6_addr addr6; 126 ares_inet_pton(AF_INET6, "::1", &addr6); 127 status = ares_append_ai_node(AF_INET6, port, 0, &addr6, nodes); 128 if (status != ARES_SUCCESS) { 129 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 130 } 131 } 132 133 if ((aftype == AF_UNSPEC || aftype == AF_INET) && 134 !ares_ai_has_family(AF_INET, *nodes)) { 135 struct in_addr addr4; 136 ares_inet_pton(AF_INET, "127.0.0.1", &addr4); 137 status = ares_append_ai_node(AF_INET, port, 0, &addr4, nodes); 138 if (status != ARES_SUCCESS) { 139 return status; /* LCOV_EXCL_LINE: OutOfMemory */ 140 } 141 } 142 143 return status; 144 } 145 146 static ares_status_t 147 ares_system_loopback_addrs(int aftype, unsigned short port, 148 struct ares_addrinfo_node **nodes) 149 { 150 #if defined(USE_WINSOCK) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && \ 151 !defined(__WATCOMC__) 152 PMIB_UNICASTIPADDRESS_TABLE table; 153 unsigned int i; 154 ares_status_t status = ARES_ENOTFOUND; 155 156 *nodes = NULL; 157 158 if (GetUnicastIpAddressTable((ADDRESS_FAMILY)aftype, &table) != NO_ERROR) { 159 return ARES_ENOTFOUND; 160 } 161 162 for (i = 0; i < table->NumEntries; i++) { 163 if (table->Table[i].InterfaceLuid.Info.IfType != 164 IF_TYPE_SOFTWARE_LOOPBACK) { 165 continue; 166 } 167 168 if (table->Table[i].Address.si_family == AF_INET && 169 !ares_ai_has_family(AF_INET, *nodes)) { 170 status = 171 ares_append_ai_node(table->Table[i].Address.si_family, port, 0, 172 &table->Table[i].Address.Ipv4.sin_addr, nodes); 173 } else if (table->Table[i].Address.si_family == AF_INET6 && 174 !ares_ai_has_family(AF_INET6, *nodes)) { 175 status = 176 ares_append_ai_node(table->Table[i].Address.si_family, port, 0, 177 &table->Table[i].Address.Ipv6.sin6_addr, nodes); 178 } else { 179 /* Ignore any others */ 180 continue; 181 } 182 183 if (status != ARES_SUCCESS) { 184 goto fail; 185 } 186 } 187 188 if (*nodes == NULL) { 189 status = ARES_ENOTFOUND; 190 } 191 192 fail: 193 FreeMibTable(table); 194 195 if (status != ARES_SUCCESS) { 196 ares_freeaddrinfo_nodes(*nodes); 197 *nodes = NULL; 198 } 199 200 return status; 201 202 #else 203 (void)aftype; 204 (void)port; 205 (void)nodes; 206 /* Not supported on any other OS at this time */ 207 return ARES_ENOTFOUND; 208 #endif 209 } 210 211 ares_status_t ares_addrinfo_localhost(const char *name, unsigned short port, 212 const struct ares_addrinfo_hints *hints, 213 struct ares_addrinfo *ai) 214 { 215 ares_status_t status; 216 217 /* Validate family */ 218 switch (hints->ai_family) { 219 case AF_INET: 220 case AF_INET6: 221 case AF_UNSPEC: 222 break; 223 default: /* LCOV_EXCL_LINE: DefensiveCoding */ 224 return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */ 225 } 226 227 if (ai->name != NULL) { 228 ares_free(ai->name); 229 } 230 ai->name = ares_strdup(name); 231 if (ai->name == NULL) { 232 status = ARES_ENOMEM; 233 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 234 } 235 236 status = ares_system_loopback_addrs(hints->ai_family, port, &ai->nodes); 237 if (status != ARES_SUCCESS && status != ARES_ENOTFOUND) { 238 goto done; 239 } 240 241 status = ares_default_loopback_addrs(hints->ai_family, port, &ai->nodes); 242 243 done: 244 return status; 245 }