Tor 0.4.9.0-alpha-dev
resolve.c
Go to the documentation of this file.
1/* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4/* See LICENSE for licensing information */
5
6/**
7 * \file resolve.c
8 * \brief Use the libc DNS resolver to convert hostnames into addresses.
9 **/
10
11#define RESOLVE_PRIVATE
12#include "lib/net/resolve.h"
13
14#include "lib/net/address.h"
15#include "lib/net/inaddr.h"
16#include "lib/malloc/malloc.h"
19
20#include "ext/siphash.h"
21#include "ext/ht.h"
22
23#ifdef HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26#ifdef HAVE_SYS_SOCKET_H
27#include <sys/socket.h>
28#endif
29#ifdef HAVE_NETDB_H
30#include <netdb.h>
31#endif
32
33#include <string.h>
34
35/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
36 * *<b>addr</b> to the proper IP address, in host byte order. Returns 0
37 * on success, -1 on failure; 1 on transient failure.
38 *
39 * This function only accepts IPv4 addresses.
40 *
41 * (This function exists because standard windows gethostbyname
42 * doesn't treat raw IP addresses properly.)
43 */
44
45MOCK_IMPL(int,
46tor_lookup_hostname,(const char *name, uint32_t *addr))
47{
48 tor_addr_t myaddr;
49 int ret;
50
51 if (BUG(!addr))
52 return -1;
53
54 *addr = 0;
55
56 if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
57 return ret;
58
59 if (tor_addr_family(&myaddr) == AF_INET) {
60 *addr = tor_addr_to_ipv4h(&myaddr);
61 return ret;
62 }
63
64 return -1;
65}
66
67#ifdef HAVE_GETADDRINFO
68
69/* Host lookup helper for tor_addr_lookup(), when getaddrinfo() is
70 * available on this system.
71 *
72 * See tor_addr_lookup() for details.
73 */
75tor_addr_lookup_host_impl,(const char *name,
76 uint16_t family,
77 tor_addr_t *addr))
78{
79 int err;
80 struct addrinfo *res=NULL, *res_p;
81 struct addrinfo *best=NULL;
82 struct addrinfo hints;
83 int result = -1;
84 memset(&hints, 0, sizeof(hints));
85 hints.ai_family = family;
86 hints.ai_socktype = SOCK_STREAM;
87 err = tor_getaddrinfo(name, NULL, &hints, &res);
88 /* The check for 'res' here shouldn't be necessary, but it makes static
89 * analysis tools happy. */
90 if (!err && res) {
91 best = NULL;
92 for (res_p = res; res_p; res_p = res_p->ai_next) {
93 if (family == AF_UNSPEC) {
94 if (res_p->ai_family == AF_INET) {
95 best = res_p;
96 break;
97 } else if (res_p->ai_family == AF_INET6 && !best) {
98 best = res_p;
99 }
100 } else if (family == res_p->ai_family) {
101 best = res_p;
102 break;
103 }
104 }
105 if (!best)
106 best = res;
107 if (best->ai_family == AF_INET) {
108 tor_addr_from_in(addr,
109 &((struct sockaddr_in*)best->ai_addr)->sin_addr);
110 result = 0;
111 } else if (best->ai_family == AF_INET6) {
113 &((struct sockaddr_in6*)best->ai_addr)->sin6_addr);
114 result = 0;
115 }
116 tor_freeaddrinfo(res);
117 return result;
118 }
119 return (err == EAI_AGAIN) ? 1 : -1;
120}
121
122#else /* !defined(HAVE_GETADDRINFO) */
123
124/* Host lookup helper for tor_addr_lookup(), which calls gethostbyname().
125 * Used when getaddrinfo() is not available on this system.
126 *
127 * See tor_addr_lookup() for details.
128 */
129MOCK_IMPL(STATIC int,
130tor_addr_lookup_host_impl,(const char *name,
131 uint16_t family,
132 tor_addr_t *addr))
133{
134 (void) family;
135 struct hostent *ent;
136 int err;
137#ifdef HAVE_GETHOSTBYNAME_R_6_ARG
138 char buf[2048];
139 struct hostent hostent;
140 int r;
141 r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err);
142#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
143 char buf[2048];
144 struct hostent hostent;
145 ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);
146#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG)
147 struct hostent_data data;
148 struct hostent hent;
149 memset(&data, 0, sizeof(data));
150 err = gethostbyname_r(name, &hent, &data);
151 ent = err ? NULL : &hent;
152#else
153 ent = gethostbyname(name);
154#ifdef _WIN32
155 err = WSAGetLastError();
156#else
157 err = h_errno;
158#endif /* defined(_WIN32) */
159#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */
160 if (ent) {
161 if (ent->h_addrtype == AF_INET) {
162 tor_addr_from_in(addr, (struct in_addr*) ent->h_addr);
163 } else if (ent->h_addrtype == AF_INET6) {
164 tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr);
165 } else {
166 tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type
167 }
168 return 0;
169 }
170#ifdef _WIN32
171 return (err == WSATRY_AGAIN) ? 1 : -1;
172#else
173 return (err == TRY_AGAIN) ? 1 : -1;
174#endif
175}
176#endif /* defined(HAVE_GETADDRINFO) */
177
178/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
179 * *<b>addr</b> to the proper IP address and family. The <b>family</b>
180 * argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
181 * <i>preferred</i> family, though another one may be returned if only one
182 * family is implemented for this address.
183 *
184 * Like tor_addr_parse(), this function accepts IPv6 addresses with or without
185 * square brackets.
186 *
187 * Return 0 on success, -1 on failure; 1 on transient failure.
188 */
189MOCK_IMPL(int,
190tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr))
191{
192 /* Perhaps eventually this should be replaced by a tor_getaddrinfo or
193 * something.
194 */
195 int parsed_family = 0;
196 int result = -1;
197
199 tor_assert(addr);
200 tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
201
202 if (!*name) {
203 /* Empty address is an error. */
204 goto permfail;
205 }
206
207 /* Is it an IP address? */
208 parsed_family = tor_addr_parse(addr, name);
209
210 if (parsed_family >= 0) {
211 /* If the IP address family matches, or was unspecified */
212 if (parsed_family == family || family == AF_UNSPEC) {
213 goto success;
214 } else {
215 goto permfail;
216 }
217 } else {
218 /* Clear the address after a failed tor_addr_parse(). */
219 memset(addr, 0, sizeof(tor_addr_t));
220 result = tor_addr_lookup_host_impl(name, family, addr);
221 goto done;
222 }
223
224 /* If we weren't successful, and haven't already set the result,
225 * assume it's a permanent failure */
226 permfail:
227 result = -1;
228 goto done;
229 success:
230 result = 0;
231
232 /* We have set the result, now it's time to clean up */
233 done:
234 if (result) {
235 /* Clear the address on error */
236 memset(addr, 0, sizeof(tor_addr_t));
237 }
238 return result;
239}
240
241/** Parse an address or address-port combination from <b>s</b>, resolve the
242 * address as needed, and put the result in <b>addr_out</b> and (optionally)
243 * <b>port_out</b>.
244 *
245 * Like tor_addr_port_parse(), this function accepts:
246 * - IPv6 address and port, when the IPv6 address is in square brackets,
247 * - IPv6 address with square brackets,
248 * - IPv6 address without square brackets.
249 *
250 * Return 0 on success, negative on failure. */
251int
252tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
253{
254 tor_addr_t addr;
255 uint16_t portval = 0;
256 char *tmp = NULL;
257 int rv = 0;
258 int result;
259
260 tor_assert(s);
261 tor_assert(addr_out);
262
263 s = eat_whitespace(s);
264
265 /* Try parsing s as an address:port first, so we don't have to duplicate
266 * the logic that rejects IPv6:Port with no square brackets. */
267 rv = tor_addr_port_parse(LOG_WARN, s, &addr, &portval, 0);
268 /* That was easy, no DNS required. */
269 if (rv == 0)
270 goto success;
271
272 /* Now let's check for malformed IPv6 addresses and ports:
273 * tor_addr_port_parse() requires squared brackes if there is a port,
274 * and we want tor_addr_port_lookup() to have the same requirement.
275 * But we strip the port using tor_addr_port_split(), so tor_addr_lookup()
276 * only sees the address, and will accept it without square brackets. */
277 int family = tor_addr_parse(&addr, s);
278 /* If tor_addr_parse() succeeds where tor_addr_port_parse() failed, we need
279 * to reject this address as malformed. */
280 if (family >= 0) {
281 /* Double-check it's an IPv6 address. If not, we have a parsing bug.
282 */
283 tor_assertf_nonfatal(family == AF_INET6,
284 "Wrong family: %d (should be IPv6: %d) which "
285 "failed IP:port parsing, but passed IP parsing. "
286 "input string: '%s'; parsed address: '%s'.",
287 family, AF_INET6, s, fmt_addr(&addr));
288 goto err;
289 }
290
291 /* Now we have a hostname. Let's split off the port, if any. */
292 rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval);
293 if (rv < 0)
294 goto err;
295
296 /* And feed the hostname to the lookup function. */
297 if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
298 goto err;
299
300 success:
301 if (port_out)
302 *port_out = portval;
303 tor_addr_copy(addr_out, &addr);
304 result = 0;
305 goto done;
306
307 err:
308 /* Clear the address and port on error */
309 memset(addr_out, 0, sizeof(tor_addr_t));
310 if (port_out)
311 *port_out = 0;
312 result = -1;
313
314 /* We have set the result, now it's time to clean up */
315 done:
316 tor_free(tmp);
317 return result;
318}
319
320#ifdef USE_SANDBOX_GETADDRINFO
321/** True if we should only return cached values */
322static int sandbox_getaddrinfo_is_active = 0;
323
324/** Cache entry for getaddrinfo results; used when sandboxing is implemented
325 * so that we can consult the cache when the sandbox prevents us from doing
326 * getaddrinfo.
327 *
328 * We support only a limited range of getaddrinfo calls, where servname is null
329 * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC.
330 */
331typedef struct cached_getaddrinfo_item_t {
332 HT_ENTRY(cached_getaddrinfo_item_t) node;
333 char *name;
334 int family;
335 /** set if no error; otherwise NULL */
336 struct addrinfo *res;
337 /** 0 for no error; otherwise an EAI_* value */
338 int err;
339} cached_getaddrinfo_item_t;
340
341static unsigned
342cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
343{
344 return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
345}
346
347static unsigned
348cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
349 const cached_getaddrinfo_item_t *b)
350{
351 return (a->family == b->family) && 0 == strcmp(a->name, b->name);
352}
353
354#define cached_getaddrinfo_item_free(item) \
355 FREE_AND_NULL(cached_getaddrinfo_item_t, \
356 cached_getaddrinfo_item_free_, (item))
357
358static void
359cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
360{
361 if (item == NULL)
362 return;
363
364 tor_free(item->name);
365 if (item->res)
366 freeaddrinfo(item->res);
367 tor_free(item);
368}
369
370static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
371 getaddrinfo_cache = HT_INITIALIZER();
372
373HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
374 cached_getaddrinfo_item_hash,
375 cached_getaddrinfo_items_eq);
376HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
377 cached_getaddrinfo_item_hash,
378 cached_getaddrinfo_items_eq,
380
381/** If true, don't try to cache getaddrinfo results. */
382static int sandbox_getaddrinfo_cache_disabled = 0;
383
384/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in
385 * tor-resolve, when we have no intention of initializing crypto or of
386 * installing the sandbox.*/
387void
388sandbox_disable_getaddrinfo_cache(void)
389{
390 sandbox_getaddrinfo_cache_disabled = 1;
391}
392
393void
394tor_freeaddrinfo(struct addrinfo *ai)
395{
396 if (sandbox_getaddrinfo_cache_disabled)
397 freeaddrinfo(ai);
398}
399
400int
401tor_getaddrinfo(const char *name, const char *servname,
402 const struct addrinfo *hints,
403 struct addrinfo **res)
404{
405 int err;
406 struct cached_getaddrinfo_item_t search, *item;
407
408 if (sandbox_getaddrinfo_cache_disabled) {
409 return getaddrinfo(name, NULL, hints, res);
410 }
411
412 if (servname != NULL) {
413 log_warn(LD_BUG, "called with non-NULL servname");
414 return EAI_NONAME;
415 }
416 if (name == NULL) {
417 log_warn(LD_BUG, "called with NULL name");
418 return EAI_NONAME;
419 }
420
421 *res = NULL;
422
423 memset(&search, 0, sizeof(search));
424 search.name = (char *) name;
425 search.family = hints ? hints->ai_family : AF_UNSPEC;
426 item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
427
428 if (! sandbox_getaddrinfo_is_active) {
429 /* If the sandbox is not turned on yet, then getaddrinfo and store the
430 result. */
431
432 err = getaddrinfo(name, NULL, hints, res);
433 log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
434
435 if (! item) {
436 item = tor_malloc_zero(sizeof(*item));
437 item->name = tor_strdup(name);
438 item->family = hints ? hints->ai_family : AF_UNSPEC;
439 HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
440 }
441
442 if (item->res) {
443 freeaddrinfo(item->res);
444 item->res = NULL;
445 }
446 item->res = *res;
447 item->err = err;
448 return err;
449 }
450
451 /* Otherwise, the sandbox is on. If we have an item, yield its cached
452 result. */
453 if (item) {
454 *res = item->res;
455 return item->err;
456 }
457
458 /* getting here means something went wrong */
459 log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
460 return EAI_NONAME;
461}
462
463int
464tor_add_addrinfo(const char *name)
465{
466 struct addrinfo *res;
467 struct addrinfo hints;
468 int i;
469 static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
470
471 memset(&hints, 0, sizeof(hints));
472 hints.ai_socktype = SOCK_STREAM;
473 for (i = 0; i < 3; ++i) {
474 hints.ai_family = families[i];
475
476 res = NULL;
477 (void) tor_getaddrinfo(name, NULL, &hints, &res);
478 if (res)
479 tor_freeaddrinfo(res);
480 }
481
482 return 0;
483}
484
485void
486tor_free_getaddrinfo_cache(void)
487{
488 cached_getaddrinfo_item_t **next, **item, *this;
489
490 for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
491 item;
492 item = next) {
493 this = *item;
494 next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
495 cached_getaddrinfo_item_free(this);
496 }
497
498 HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
499}
500
501void
502tor_make_getaddrinfo_cache_active(void)
503{
504 sandbox_getaddrinfo_is_active = 1;
505}
506#else /* !defined(USE_SANDBOX_GETADDRINFO) */
507void
508sandbox_disable_getaddrinfo_cache(void)
509{
510}
511void
512tor_make_getaddrinfo_cache_active(void)
513{
514}
515#endif /* defined(USE_SANDBOX_GETADDRINFO) */
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
Definition: address.c:933
int tor_addr_parse(tor_addr_t *addr, const char *src)
Definition: address.c:1349
int tor_addr_port_parse(int severity, const char *addrport, tor_addr_t *address_out, uint16_t *port_out, int default_port)
Definition: address.c:1857
int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out)
Definition: address.c:1916
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
Definition: address.c:911
Headers for address.h.
static sa_family_t tor_addr_family(const tor_addr_t *a)
Definition: address.h:187
static uint32_t tor_addr_to_ipv4h(const tor_addr_t *a)
Definition: address.h:160
#define tor_addr_from_in(dest, in)
Definition: address.h:331
#define fmt_addr(a)
Definition: address.h:239
const char * name
Definition: config.c:2462
HT_PROTOTYPE(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, hs_circuit_hash_token, hs_circuits_have_same_token)
typedef HT_HEAD(hs_service_ht, hs_service_t) hs_service_ht
Header for inaddr.c.
#define LD_BUG
Definition: log.h:86
#define LD_NET
Definition: log.h:66
#define LOG_WARN
Definition: log.h:53
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
void tor_free_(void *mem)
Definition: malloc.c:227
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
Header for parse_int.c.
int tor_lookup_hostname(const char *name, uint32_t *addr)
Definition: resolve.c:46
int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
Definition: resolve.c:190
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
Definition: resolve.c:252
Header for resolve.c.
#define STATIC
Definition: testsupport.h:32
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define tor_assert(expr)
Definition: util_bug.h:103
const char * eat_whitespace(const char *s)
Definition: util_string.c:279
Header for util_string.c.