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