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
ares_append_ai_node(int aftype, unsigned short port, unsigned int ttl, const void *adata, struct ares_addrinfo_node **nodes)57 ares_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
109 static ares_status_t
ares__default_loopback_addrs(int aftype, unsigned short port, struct ares_addrinfo_node **nodes)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
136 static ares_status_t
ares__system_loopback_addrs(int aftype, unsigned short port, struct ares_addrinfo_node **nodes)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
180 fail:
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
ares__addrinfo_localhost(const char *name, unsigned short port, const struct ares_addrinfo_hints *hints, struct ares_addrinfo *ai)199 ares_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
231 enomem:
232 ares__freeaddrinfo_nodes(nodes);
233 ares_free(ai->name);
234 ai->name = NULL;
235 return ARES_ENOMEM;
236 }
237