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