tor  0.4.2.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-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
11 #include "lib/net/resolve.h"
12 
13 #include "lib/net/address.h"
14 #include "lib/net/inaddr.h"
15 #include "lib/malloc/malloc.h"
16 #include "lib/string/parse_int.h"
17 #include "lib/string/util_string.h"
18 
19 #include "ext/siphash.h"
20 #include "ext/ht.h"
21 
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 #ifdef HAVE_SYS_SOCKET_H
26 #include <sys/socket.h>
27 #endif
28 #ifdef HAVE_NETDB_H
29 #include <netdb.h>
30 #endif
31 
32 #include <string.h>
33 
43 tor_lookup_hostname,(const char *name, uint32_t *addr))
44 {
45  tor_addr_t myaddr;
46  int ret;
47 
48  if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
49  return ret;
50 
51  if (tor_addr_family(&myaddr) == AF_INET) {
52  *addr = tor_addr_to_ipv4h(&myaddr);
53  return ret;
54  }
55 
56  return -1;
57 }
58 
68 tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr))
69 {
70  /* Perhaps eventually this should be replaced by a tor_getaddrinfo or
71  * something.
72  */
73  struct in_addr iaddr;
74  struct in6_addr iaddr6;
75  tor_assert(name);
76  tor_assert(addr);
77  tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
78  if (!*name) {
79  /* Empty address is an error. */
80  return -1;
81  } else if (tor_inet_pton(AF_INET, name, &iaddr)) {
82  /* It's an IPv4 IP. */
83  if (family == AF_INET6)
84  return -1;
85  tor_addr_from_in(addr, &iaddr);
86  return 0;
87  } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) {
88  if (family == AF_INET)
89  return -1;
90  tor_addr_from_in6(addr, &iaddr6);
91  return 0;
92  } else {
93 #ifdef HAVE_GETADDRINFO
94  int err;
95  struct addrinfo *res=NULL, *res_p;
96  struct addrinfo *best=NULL;
97  struct addrinfo hints;
98  int result = -1;
99  memset(&hints, 0, sizeof(hints));
100  hints.ai_family = family;
101  hints.ai_socktype = SOCK_STREAM;
102  err = tor_getaddrinfo(name, NULL, &hints, &res);
103  /* The check for 'res' here shouldn't be necessary, but it makes static
104  * analysis tools happy. */
105  if (!err && res) {
106  best = NULL;
107  for (res_p = res; res_p; res_p = res_p->ai_next) {
108  if (family == AF_UNSPEC) {
109  if (res_p->ai_family == AF_INET) {
110  best = res_p;
111  break;
112  } else if (res_p->ai_family == AF_INET6 && !best) {
113  best = res_p;
114  }
115  } else if (family == res_p->ai_family) {
116  best = res_p;
117  break;
118  }
119  }
120  if (!best)
121  best = res;
122  if (best->ai_family == AF_INET) {
123  tor_addr_from_in(addr,
124  &((struct sockaddr_in*)best->ai_addr)->sin_addr);
125  result = 0;
126  } else if (best->ai_family == AF_INET6) {
127  tor_addr_from_in6(addr,
128  &((struct sockaddr_in6*)best->ai_addr)->sin6_addr);
129  result = 0;
130  }
131  tor_freeaddrinfo(res);
132  return result;
133  }
134  return (err == EAI_AGAIN) ? 1 : -1;
135 #else /* !(defined(HAVE_GETADDRINFO)) */
136  struct hostent *ent;
137  int err;
138 #ifdef HAVE_GETHOSTBYNAME_R_6_ARG
139  char buf[2048];
140  struct hostent hostent;
141  int r;
142  r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err);
143 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
144  char buf[2048];
145  struct hostent hostent;
146  ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);
147 #elif defined(HAVE_GETHOSTBYNAME_R_3_ARG)
148  struct hostent_data data;
149  struct hostent hent;
150  memset(&data, 0, sizeof(data));
151  err = gethostbyname_r(name, &hent, &data);
152  ent = err ? NULL : &hent;
153 #else
154  ent = gethostbyname(name);
155 #ifdef _WIN32
156  err = WSAGetLastError();
157 #else
158  err = h_errno;
159 #endif
160 #endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */
161  if (ent) {
162  if (ent->h_addrtype == AF_INET) {
163  tor_addr_from_in(addr, (struct in_addr*) ent->h_addr);
164  } else if (ent->h_addrtype == AF_INET6) {
165  tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr);
166  } else {
167  tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type
168  }
169  return 0;
170  }
171 #ifdef _WIN32
172  return (err == WSATRY_AGAIN) ? 1 : -1;
173 #else
174  return (err == TRY_AGAIN) ? 1 : -1;
175 #endif
176 #endif /* defined(HAVE_GETADDRINFO) */
177  }
178 }
179 
183 int
184 tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
185 {
186  const char *port;
187  tor_addr_t addr;
188  uint16_t portval;
189  char *tmp = NULL;
190 
191  tor_assert(s);
192  tor_assert(addr_out);
193 
194  s = eat_whitespace(s);
195 
196  if (*s == '[') {
197  port = strstr(s, "]");
198  if (!port)
199  goto err;
200  tmp = tor_strndup(s+1, port-(s+1));
201  port = port+1;
202  if (*port == ':')
203  port++;
204  else
205  port = NULL;
206  } else {
207  port = strchr(s, ':');
208  if (port)
209  tmp = tor_strndup(s, port-s);
210  else
211  tmp = tor_strdup(s);
212  if (port)
213  ++port;
214  }
215 
216  if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
217  goto err;
218  tor_free(tmp);
219 
220  if (port) {
221  portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL);
222  if (!portval)
223  goto err;
224  } else {
225  portval = 0;
226  }
227 
228  if (port_out)
229  *port_out = portval;
230  tor_addr_copy(addr_out, &addr);
231 
232  return 0;
233  err:
234  tor_free(tmp);
235  return -1;
236 }
237 
238 #ifdef USE_SANDBOX_GETADDRINFO
239 
240 static int sandbox_getaddrinfo_is_active = 0;
241 
249 typedef struct cached_getaddrinfo_item_t {
250  HT_ENTRY(cached_getaddrinfo_item_t) node;
251  char *name;
252  int family;
254  struct addrinfo *res;
256  int err;
257 } cached_getaddrinfo_item_t;
258 
259 static unsigned
260 cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
261 {
262  return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
263 }
264 
265 static unsigned
266 cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a,
267  const cached_getaddrinfo_item_t *b)
268 {
269  return (a->family == b->family) && 0 == strcmp(a->name, b->name);
270 }
271 
272 #define cached_getaddrinfo_item_free(item) \
273  FREE_AND_NULL(cached_getaddrinfo_item_t, \
274  cached_getaddrinfo_item_free_, (item))
275 
276 static void
277 cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item)
278 {
279  if (item == NULL)
280  return;
281 
282  tor_free(item->name);
283  if (item->res)
284  freeaddrinfo(item->res);
285  tor_free(item);
286 }
287 
288 static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
289  getaddrinfo_cache = HT_INITIALIZER();
290 
291 HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
292  cached_getaddrinfo_item_hash,
293  cached_getaddrinfo_items_eq)
294 HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
295  cached_getaddrinfo_item_hash,
296  cached_getaddrinfo_items_eq,
298 
299 
300 static int sandbox_getaddrinfo_cache_disabled = 0;
301 
305 void
306 sandbox_disable_getaddrinfo_cache(void)
307 {
308  sandbox_getaddrinfo_cache_disabled = 1;
309 }
310 
311 void
312 tor_freeaddrinfo(struct addrinfo *ai)
313 {
314  if (sandbox_getaddrinfo_cache_disabled)
315  freeaddrinfo(ai);
316 }
317 
318 int
319 tor_getaddrinfo(const char *name, const char *servname,
320  const struct addrinfo *hints,
321  struct addrinfo **res)
322 {
323  int err;
324  struct cached_getaddrinfo_item_t search, *item;
325 
326  if (sandbox_getaddrinfo_cache_disabled) {
327  return getaddrinfo(name, NULL, hints, res);
328  }
329 
330  if (servname != NULL) {
331  log_warn(LD_BUG, "called with non-NULL servname");
332  return EAI_NONAME;
333  }
334  if (name == NULL) {
335  log_warn(LD_BUG, "called with NULL name");
336  return EAI_NONAME;
337  }
338 
339  *res = NULL;
340 
341  memset(&search, 0, sizeof(search));
342  search.name = (char *) name;
343  search.family = hints ? hints->ai_family : AF_UNSPEC;
344  item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search);
345 
346  if (! sandbox_getaddrinfo_is_active) {
347  /* If the sandbox is not turned on yet, then getaddrinfo and store the
348  result. */
349 
350  err = getaddrinfo(name, NULL, hints, res);
351  log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded");
352 
353  if (! item) {
354  item = tor_malloc_zero(sizeof(*item));
355  item->name = tor_strdup(name);
356  item->family = hints ? hints->ai_family : AF_UNSPEC;
357  HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item);
358  }
359 
360  if (item->res) {
361  freeaddrinfo(item->res);
362  item->res = NULL;
363  }
364  item->res = *res;
365  item->err = err;
366  return err;
367  }
368 
369  /* Otherwise, the sandbox is on. If we have an item, yield its cached
370  result. */
371  if (item) {
372  *res = item->res;
373  return item->err;
374  }
375 
376  /* getting here means something went wrong */
377  log_err(LD_BUG,"(Sandbox) failed to get address %s!", name);
378  return EAI_NONAME;
379 }
380 
381 int
382 tor_add_addrinfo(const char *name)
383 {
384  struct addrinfo *res;
385  struct addrinfo hints;
386  int i;
387  static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC };
388 
389  memset(&hints, 0, sizeof(hints));
390  hints.ai_socktype = SOCK_STREAM;
391  for (i = 0; i < 3; ++i) {
392  hints.ai_family = families[i];
393 
394  res = NULL;
395  (void) tor_getaddrinfo(name, NULL, &hints, &res);
396  if (res)
397  tor_freeaddrinfo(res);
398  }
399 
400  return 0;
401 }
402 
403 void
404 tor_free_getaddrinfo_cache(void)
405 {
406  cached_getaddrinfo_item_t **next, **item, *this;
407 
408  for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
409  item;
410  item = next) {
411  this = *item;
412  next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
413  cached_getaddrinfo_item_free(this);
414  }
415 
416  HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
417 }
418 
419 void
420 tor_make_getaddrinfo_cache_active(void)
421 {
422  sandbox_getaddrinfo_is_active = 1;
423 }
424 #else /* !(defined(USE_SANDBOX_GETADDRINFO)) */
425 void
426 sandbox_disable_getaddrinfo_cache(void)
427 {
428 }
429 void
430 tor_make_getaddrinfo_cache_active(void)
431 {
432 }
433 #endif /* defined(USE_SANDBOX_GETADDRINFO) */
int tor_inet_pton(int af, const char *src, void *dst)
Definition: inaddr.c:166
MOCK_IMPL(int, tor_lookup_hostname,(const char *name, uint32_t *addr))
Definition: resolve.c:42
HT_PROTOTYPE(HT_GENERATE2(strmap_impl, HT_GENERATE2(strmap_entry_t, HT_GENERATE2(node, HT_GENERATE2(strmap_entry_hash, HT_GENERATE2(strmap_entries_eq)
Definition: map.c:87
static uint32_t tor_addr_to_ipv4h(const tor_addr_t *a)
Definition: address.h:152
#define tor_free(p)
Definition: malloc.h:52
Header for util_string.c.
Header for inaddr.c.
Headers for util_malloc.c.
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
Definition: resolve.c:184
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
#define tor_addr_from_in(dest, in)
Definition: address.h:291
tor_assert(buffer)
Headers for address.h.
const char * eat_whitespace(const char *s)
Definition: util_string.c:268
void tor_free_(void *mem)
Definition: malloc.c:227
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
Definition: address.c:895
Header for resolve.c.
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:56
#define LD_NET
Definition: log.h:63
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
Definition: address.c:903
Header for parse_int.c.
#define LD_BUG
Definition: log.h:83
static sa_family_t tor_addr_family(const tor_addr_t *a)
Definition: address.h:179