1 /* Copyright (C) 2021
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
14 */
15
16 #include "ares_setup.h"
17
18 #ifdef HAVE_NETINET_IN_H
19 # include <netinet/in.h>
20 #endif
21 #ifdef HAVE_NETDB_H
22 # include <netdb.h>
23 #endif
24 #ifdef HAVE_ARPA_INET_H
25 # include <arpa/inet.h>
26 #endif
27
28 #if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
29 #include <ws2ipdef.h>
30 #include <iphlpapi.h>
31 #endif
32
33 #include "ares.h"
34 #include "ares_inet_net_pton.h"
35 #include "ares_nowarn.h"
36 #include "ares_private.h"
37
ares_append_ai_node(int aftype,unsigned short port,int ttl,const void * adata,struct ares_addrinfo_node ** nodes)38 int ares_append_ai_node(int aftype,
39 unsigned short port,
40 int ttl,
41 const void *adata,
42 struct ares_addrinfo_node **nodes)
43 {
44 struct ares_addrinfo_node *node;
45
46 node = ares__append_addrinfo_node(nodes);
47 if (!node)
48 {
49 return ARES_ENOMEM;
50 }
51
52 memset(node, 0, sizeof(*node));
53
54 if (aftype == AF_INET)
55 {
56 struct sockaddr_in *sin = ares_malloc(sizeof(*sin));
57 if (!sin)
58 {
59 return ARES_ENOMEM;
60 }
61
62 memset(sin, 0, sizeof(*sin));
63 memcpy(&sin->sin_addr.s_addr, adata, sizeof(sin->sin_addr.s_addr));
64 sin->sin_family = AF_INET;
65 sin->sin_port = htons(port);
66
67 node->ai_addr = (struct sockaddr *)sin;
68 node->ai_family = AF_INET;
69 node->ai_addrlen = sizeof(*sin);
70 node->ai_addr = (struct sockaddr *)sin;
71 node->ai_ttl = ttl;
72 }
73
74 if (aftype == AF_INET6)
75 {
76 struct sockaddr_in6 *sin6 = ares_malloc(sizeof(*sin6));
77 if (!sin6)
78 {
79 return ARES_ENOMEM;
80 }
81
82 memset(sin6, 0, sizeof(*sin6));
83 memcpy(&sin6->sin6_addr.s6_addr, adata, sizeof(sin6->sin6_addr.s6_addr));
84 sin6->sin6_family = AF_INET6;
85 sin6->sin6_port = htons(port);
86
87 node->ai_addr = (struct sockaddr *)sin6;
88 node->ai_family = AF_INET6;
89 node->ai_addrlen = sizeof(*sin6);
90 node->ai_addr = (struct sockaddr *)sin6;
91 node->ai_ttl = ttl;
92 }
93
94 return ARES_SUCCESS;
95 }
96
97
ares__default_loopback_addrs(int aftype,unsigned short port,struct ares_addrinfo_node ** nodes)98 static int ares__default_loopback_addrs(int aftype,
99 unsigned short port,
100 struct ares_addrinfo_node **nodes)
101 {
102 int status = ARES_SUCCESS;
103
104 if (aftype == AF_UNSPEC || aftype == AF_INET6)
105 {
106 struct ares_in6_addr addr6;
107 ares_inet_pton(AF_INET6, "::1", &addr6);
108 status = ares_append_ai_node(AF_INET6, port, 0, &addr6, nodes);
109 if (status != ARES_SUCCESS)
110 {
111 return status;
112 }
113 }
114
115 if (aftype == AF_UNSPEC || aftype == AF_INET)
116 {
117 struct in_addr addr4;
118 ares_inet_pton(AF_INET, "127.0.0.1", &addr4);
119 status = ares_append_ai_node(AF_INET, port, 0, &addr4, nodes);
120 if (status != ARES_SUCCESS)
121 {
122 return status;
123 }
124 }
125
126 return status;
127 }
128
129
ares__system_loopback_addrs(int aftype,unsigned short port,struct ares_addrinfo_node ** nodes)130 static int ares__system_loopback_addrs(int aftype,
131 unsigned short port,
132 struct ares_addrinfo_node **nodes)
133 {
134 #if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && !defined(__WATCOMC__)
135 PMIB_UNICASTIPADDRESS_TABLE table;
136 unsigned int i;
137 int status;
138
139 *nodes = NULL;
140
141 if (GetUnicastIpAddressTable(aftype, &table) != NO_ERROR)
142 return ARES_ENOTFOUND;
143
144 for (i=0; i<table->NumEntries; i++)
145 {
146 if (table->Table[i].InterfaceLuid.Info.IfType !=
147 IF_TYPE_SOFTWARE_LOOPBACK)
148 {
149 continue;
150 }
151
152 if (table->Table[i].Address.si_family == AF_INET)
153 {
154 status = ares_append_ai_node(table->Table[i].Address.si_family, port, 0,
155 &table->Table[i].Address.Ipv4.sin_addr,
156 nodes);
157 }
158 else if (table->Table[i].Address.si_family == AF_INET6)
159 {
160 status = ares_append_ai_node(table->Table[i].Address.si_family, port, 0,
161 &table->Table[i].Address.Ipv6.sin6_addr,
162 nodes);
163 }
164 else
165 {
166 /* Ignore any others */
167 continue;
168 }
169
170 if (status != ARES_SUCCESS)
171 {
172 goto fail;
173 }
174 }
175
176 if (*nodes == NULL)
177 status = ARES_ENOTFOUND;
178
179 fail:
180 FreeMibTable(table);
181
182 if (status != ARES_SUCCESS)
183 {
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
199
ares__addrinfo_localhost(const char * name,unsigned short port,const struct ares_addrinfo_hints * hints,struct ares_addrinfo * ai)200 int ares__addrinfo_localhost(const char *name,
201 unsigned short port,
202 const struct ares_addrinfo_hints *hints,
203 struct ares_addrinfo *ai)
204 {
205 struct ares_addrinfo_node *nodes = NULL;
206 int result;
207
208 /* Validate family */
209 switch (hints->ai_family) {
210 case AF_INET:
211 case AF_INET6:
212 case AF_UNSPEC:
213 break;
214 default:
215 return ARES_EBADFAMILY;
216 }
217
218 ai->name = ares_strdup(name);
219 if(!ai->name)
220 {
221 goto enomem;
222 }
223
224 result = ares__system_loopback_addrs(hints->ai_family, port, &nodes);
225
226 if (result == ARES_ENOTFOUND)
227 {
228 result = ares__default_loopback_addrs(hints->ai_family, port, &nodes);
229 }
230
231 ares__addrinfo_cat_nodes(&ai->nodes, nodes);
232
233 return result;
234
235 enomem:
236 ares__freeaddrinfo_nodes(nodes);
237 ares_free(ai->name);
238 ai->name = NULL;
239 return ARES_ENOMEM;
240 }
241