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
ares_ai_has_family(int aftype,const struct ares_addrinfo_node * nodes)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
ares_append_ai_node(int aftype,unsigned short port,unsigned int ttl,const void * adata,struct ares_addrinfo_node ** nodes)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
ares_default_loopback_addrs(int aftype,unsigned short port,struct ares_addrinfo_node ** nodes)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
ares_system_loopback_addrs(int aftype,unsigned short port,struct ares_addrinfo_node ** nodes)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
ares_addrinfo_localhost(const char * name,unsigned short port,const struct ares_addrinfo_hints * hints,struct ares_addrinfo * ai)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 }
246