• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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