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