tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

resolve.c (14099B)


      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"
     17 #include "lib/string/parse_int.h"
     18 #include "lib/string/util_string.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 
     45 MOCK_IMPL(int,
     46 tor_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 */
     74 MOCK_IMPL(STATIC int,
     75 tor_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) {
    112      tor_addr_from_in6(addr,
    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 */
    129 MOCK_IMPL(STATIC int,
    130 tor_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 */
    189 MOCK_IMPL(int,
    190 tor_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 
    198  tor_assert(name);
    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. */
    251 int
    252 tor_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 */
    322 static 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 */
    331 typedef 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 
    341 static unsigned
    342 cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item)
    343 {
    344  return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family;
    345 }
    346 
    347 static unsigned
    348 cached_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 
    358 static void
    359 cached_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 
    370 static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
    371     getaddrinfo_cache = HT_INITIALIZER();
    372 
    373 HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
    374             cached_getaddrinfo_item_hash,
    375             cached_getaddrinfo_items_eq);
    376 HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
    377             cached_getaddrinfo_item_hash,
    378             cached_getaddrinfo_items_eq,
    379             0.6, tor_reallocarray_, tor_free_);
    380 
    381 /** If true, don't try to cache getaddrinfo results. */
    382 static 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.*/
    387 void
    388 sandbox_disable_getaddrinfo_cache(void)
    389 {
    390  sandbox_getaddrinfo_cache_disabled = 1;
    391 }
    392 
    393 void
    394 tor_freeaddrinfo(struct addrinfo *ai)
    395 {
    396  if (sandbox_getaddrinfo_cache_disabled)
    397    freeaddrinfo(ai);
    398 }
    399 
    400 int
    401 tor_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 
    463 int
    464 tor_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 
    485 void
    486 tor_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 
    501 void
    502 tor_make_getaddrinfo_cache_active(void)
    503 {
    504  sandbox_getaddrinfo_is_active = 1;
    505 }
    506 #else /* !defined(USE_SANDBOX_GETADDRINFO) */
    507 void
    508 sandbox_disable_getaddrinfo_cache(void)
    509 {
    510 }
    511 void
    512 tor_make_getaddrinfo_cache_active(void)
    513 {
    514 }
    515 #endif /* defined(USE_SANDBOX_GETADDRINFO) */