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