⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns.c

📁 关于tor匿名通信的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
      } else {
        log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
                  safe_str(escaped_address),
                  escaped_safe_str(answer_buf));
      }
      tor_free(escaped_address);
    } else if (type == DNS_PTR && count) {
      char *escaped_address;
      is_reverse = 1;
      hostname = ((char**)addresses)[0];
      status = DNS_RESOLVE_SUCCEEDED;
      escaped_address = esc_for_log(string_address);
      log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
                safe_str(escaped_address),
                escaped_safe_str(hostname));
      tor_free(escaped_address);
    } else if (count) {
      log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
               escaped_safe_str(string_address));
    } else {
      log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
               escaped_safe_str(string_address));
    }
  } else {
    if (evdns_err_is_transient(result))
      status = DNS_RESOLVE_FAILED_TRANSIENT;
  }
  if (was_wildcarded) {
    if (is_test_address(string_address)) {
      /* Ick.  We're getting redirected on known-good addresses.  Our DNS
       * server must really hate us.  */
      add_wildcarded_test_address(string_address);
    }
  }
  if (result != DNS_ERR_SHUTDOWN)
    dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl);
  tor_free(string_address);
}

/** For eventdns: start resolving as necessary to find the target for
 * <b>exitconn</b>.  Returns -1 on error, -2 on transient error,
 * 0 on "resolve launched." */
static int
launch_resolve(edge_connection_t *exitconn)
{
  char *addr = tor_strdup(exitconn->_base.address);
  struct in_addr in;
  int r;
  int options = get_options()->ServerDNSSearchDomains ? 0
    : DNS_QUERY_NO_SEARCH;
  /* What? Nameservers not configured?  Sounds like a bug. */
  if (!nameservers_configured) {
    log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve "
             "launched.  Configuring.");
    if (configure_nameservers(1) < 0)
      return -1;
  }

  r = parse_inaddr_arpa_address(exitconn->_base.address, &in);
  if (r == 0) {
    log_info(LD_EXIT, "Launching eventdns request for %s",
             escaped_safe_str(exitconn->_base.address));
    r = evdns_resolve_ipv4(exitconn->_base.address, options,
                           evdns_callback, addr);
  } else if (r == 1) {
    log_info(LD_EXIT, "Launching eventdns reverse request for %s",
             escaped_safe_str(exitconn->_base.address));
    r = evdns_resolve_reverse(&in, DNS_QUERY_NO_SEARCH,
                                 evdns_callback, addr);
  } else if (r == -1) {
    log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
  }

  if (r) {
    log_warn(LD_EXIT, "eventdns rejected address %s: error %d.",
             escaped_safe_str(addr), r);
    r = evdns_err_is_transient(r) ? -2 : -1;
    tor_free(addr); /* There is no evdns request in progress; stop
                     * addr from getting leaked. */
  }
  return r;
}

/** How many requests for bogus addresses have we launched so far? */
static int n_wildcard_requests = 0;

/** Map from dotted-quad IP address in response to an int holding how many
 * times we've seen it for a randomly generated (hopefully bogus) address.  It
 * would be easier to use definitely-invalid addresses (as specified by
 * RFC2606), but see comment in dns_launch_wildcard_checks(). */
static strmap_t *dns_wildcard_response_count = NULL;

/** If present, a list of dotted-quad IP addresses that we are pretty sure our
 * nameserver wants to return in response to requests for nonexistent domains.
 */
static smartlist_t *dns_wildcard_list = NULL;
/** True iff we've logged about a single address getting wildcarded.
 * Subsequent warnings will be less severe.  */
static int dns_wildcard_one_notice_given = 0;
/** True iff we've warned that our DNS server is wildcarding too many failures.
 */
static int dns_wildcard_notice_given = 0;

/** List of supposedly good addresses that are getting wildcarded to the
 * same addresses as nonexistent addresses. */
static smartlist_t *dns_wildcarded_test_address_list = NULL;
/** True iff we've warned about a test address getting wildcarded */
static int dns_wildcarded_test_address_notice_given = 0;
/** True iff all addresses seem to be getting wildcarded. */
static int dns_is_completely_invalid = 0;

/** Called when we see <b>id</b> (a dotted quad) in response to a request for
 * a hopefully bogus address. */
static void
wildcard_increment_answer(const char *id)
{
  int *ip;
  if (!dns_wildcard_response_count)
    dns_wildcard_response_count = strmap_new();

  ip = strmap_get(dns_wildcard_response_count, id); // may be null (0)
  if (!ip) {
    ip = tor_malloc_zero(sizeof(int));
    strmap_set(dns_wildcard_response_count, id, ip);
  }
  ++*ip;

  if (*ip > 5 && n_wildcard_requests > 10) {
    if (!dns_wildcard_list) dns_wildcard_list = smartlist_create();
    if (!smartlist_string_isin(dns_wildcard_list, id)) {
    log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
        "Your DNS provider has given \"%s\" as an answer for %d different "
        "invalid addresses. Apparently they are hijacking DNS failures. "
        "I'll try to correct for this by treating future occurrences of "
        "\"%s\" as 'not found'.", id, *ip, id);
      smartlist_add(dns_wildcard_list, tor_strdup(id));
    }
    if (!dns_wildcard_notice_given)
      control_event_server_status(LOG_NOTICE, "DNS_HIJACKED");
    dns_wildcard_notice_given = 1;
  }
}

/** Note that a single test address (one believed to be good) seems to be
 * getting redirected to the same IP as failures are. */
static void
add_wildcarded_test_address(const char *address)
{
  int n, n_test_addrs;
  if (!dns_wildcarded_test_address_list)
    dns_wildcarded_test_address_list = smartlist_create();

  if (smartlist_string_isin_case(dns_wildcarded_test_address_list, address))
    return;

  n_test_addrs = get_options()->ServerDNSTestAddresses ?
    smartlist_len(get_options()->ServerDNSTestAddresses) : 0;

  smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address));
  n = smartlist_len(dns_wildcarded_test_address_list);
  if (n > n_test_addrs/2) {
    log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE,
        LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk "
        "address.  It has done this with %d test addresses so far.  I'm "
        "going to stop being an exit node for now, since our DNS seems so "
        "broken.", address, n);
    if (!dns_is_completely_invalid) {
      dns_is_completely_invalid = 1;
      mark_my_descriptor_dirty();
    }
    if (!dns_wildcarded_test_address_notice_given)
      control_event_server_status(LOG_WARN, "DNS_USELESS");
    dns_wildcarded_test_address_notice_given = 1;
  }
}

/** Callback function when we get an answer (possibly failing) for a request
 * for a (hopefully) nonexistent domain. */
static void
evdns_wildcard_check_callback(int result, char type, int count, int ttl,
                              void *addresses, void *arg)
{
  (void)ttl;
  ++n_wildcard_requests;
  if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
    uint32_t *addrs = addresses;
    int i;
    char *string_address = arg;
    for (i = 0; i < count; ++i) {
      char answer_buf[INET_NTOA_BUF_LEN+1];
      struct in_addr in;
      in.s_addr = addrs[i];
      tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
      wildcard_increment_answer(answer_buf);
    }
    log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
        "Your DNS provider gave an answer for \"%s\", which "
        "is not supposed to exist.  Apparently they are hijacking "
        "DNS failures. Trying to correct for this.  We've noticed %d possibly "
        "bad addresses so far.",
        string_address, strmap_size(dns_wildcard_response_count));
    dns_wildcard_one_notice_given = 1;
  }
  tor_free(arg);
}

/** Launch a single request for a nonexistent hostname consisting of between
 * <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by
 * <b>suffix</b> */
static void
launch_wildcard_check(int min_len, int max_len, const char *suffix)
{
  char *addr;
  int r;

  addr = crypto_random_hostname(min_len, max_len, "", suffix);
  log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent "
           "domains with request for bogus hostname \"%s\"", addr);

  r = evdns_resolve_ipv4(/* This "addr" tells us which address to resolve */
                         addr,
                         DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback,
                         /* This "addr" is an argument to the callback*/ addr);
  if (r) {
    /* There is no evdns request in progress; stop addr from getting leaked */
    tor_free(addr);
  }
}

/** Launch attempts to resolve a bunch of known-good addresses (configured in
 * ServerDNSTestAddresses).  [Callback for a libevent timer] */
static void
launch_test_addresses(int fd, short event, void *args)
{
  or_options_t *options = get_options();
  (void)fd;
  (void)event;
  (void)args;

  log_info(LD_EXIT, "Launching checks to see whether our nameservers like to "
           "hijack *everything*.");
  /* This situation is worse than the failure-hijacking situation.  When this
   * happens, we're no good for DNS requests at all, and we shouldn't really
   * be an exit server.*/
  if (!options->ServerDNSTestAddresses)
    return;
  SMARTLIST_FOREACH(options->ServerDNSTestAddresses, const char *, address,
    {
      int r = evdns_resolve_ipv4(address, DNS_QUERY_NO_SEARCH, evdns_callback,
                                 tor_strdup(address));
      if (r)
        log_info(LD_EXIT, "eventdns rejected test address %s: error %d",
                 escaped_safe_str(address), r);
    });
}

#define N_WILDCARD_CHECKS 2

/** Launch DNS requests for a few nonexistent hostnames and a few well-known
 * hostnames, and see if we can catch our nameserver trying to hijack them and
 * map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to
 * buy these lovely encyclopedias" page. */
static void
dns_launch_wildcard_checks(void)
{
  int i;
  log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
           "to hijack DNS failures.");
  for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
    /* RFC2606 reserves these.  Sadly, some DNS hijackers, in a silly attempt
     * to 'comply' with rfc2606, refrain from giving A records for these.
     * This is the standards-compliance equivalent of making sure that your
     * crackhouse's elevator inspection certificate is up to date.
     */
    launch_wildcard_check(2, 16, ".invalid");
    launch_wildcard_check(2, 16, ".test");

    /* These will break specs if there are ever any number of
     * 8+-character top-level domains. */
    launch_wildcard_check(8, 16, "");

    /* Try some random .com/org/net domains. This will work fine so long as
     * not too many resolve to the same place. */
    launch_wildcard_check(8, 16, ".com");
    launch_wildcard_check(8, 16, ".org");
    launch_wildcard_check(8, 16, ".net");
  }
}

/** If appropriate, start testing whether our DNS servers tend to lie to
 * us. */
void
dns_launch_correctness_checks(void)
{
  static struct event launch_event;
  struct timeval timeout;
  if (!get_options()->ServerDNSDetectHijacking)
    return;
  dns_launch_wildcard_checks();

  /* Wait a while before launching requests for test addresses, so we can
   * get the results from checking for wildcarding. */
  evtimer_set(&launch_event, launch_test_addresses, NULL);
  timeout.tv_sec = 30;
  timeout.tv_usec = 0;
  if (evtimer_add(&launch_event, &timeout)<0) {
    log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking");
  }
}

/** Return true iff our DNS servers lie to us too much to be trustd. */
int
dns_seems_to_be_broken(void)
{
  return dns_is_completely_invalid;
}

/** Forget what we've previously learned about our DNS servers' correctness. */
void
dns_reset_correctness_checks(void)
{
  if (dns_wildcard_response_count) {
    strmap_free(dns_wildcard_response_count, _tor_free);
    dns_wildcard_response_count = NULL;
  }
  n_wildcard_requests = 0;

  if (dns_wildcard_list) {
    SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp));
    smartlist_clear(dns_wildcard_list);
  }
  if (dns_wildcarded_test_address_list) {
    SMARTLIST_FOREACH(dns_wildcarded_test_address_list, char *, cp,
                      tor_free(cp));
    smartlist_clear(dns_wildcarded_test_address_list);
  }
  dns_wildcard_one_notice_given = dns_wildcard_notice_given =
    dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = 0;
}

/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
 * returned in response to requests for nonexistent hostnames. */
static int
answer_is_wildcarded(const char *ip)
{
  return dns_wildcard_list && smartlist_string_isin(dns_wildcard_list, ip);
}

/** Exit with an assertion if <b>resolve</b> is corrupt. */
static void
assert_resolve_ok(cached_resolve_t *resolve)
{
  tor_assert(resolve);
  tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC);
  tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN);
  tor_assert(tor_strisnonupper(resolve->address));
  if (resolve->state != CACHE_STATE_PENDING) {
    tor_assert(!resolve->pending_connections);
  }
  if (resolve->state == CACHE_STATE_PENDING ||
      resolve->state == CACHE_STATE_DONE) {
    tor_assert(!resolve->ttl);
    if (resolve->is_reverse)
      tor_assert(!resolve->result.hostname);
    else
      tor_assert(!resolve->result.addr);
  }
}

#ifdef DEBUG_DNS_CACHE
/** Exit with an assertion if the DNS cache is corrupt. */
static void
_assert_cache_ok(void)
{
  cached_resolve_t **resolve;
  int bad_rep = _cache_map_HT_REP_IS_BAD(&cache_root);
  if (bad_rep) {
    log_err(LD_BUG, "Bad rep type %d on dns cache hash table", bad_rep);
    tor_assert(!bad_rep);
  }

  HT_FOREACH(resolve, cache_map, &cache_root) {
    assert_resolve_ok(*resolve);
    tor_assert((*resolve)->state != CACHE_STATE_DONE);
  }
  if (!cached_resolve_pqueue)
    return;

  smartlist_pqueue_assert_ok(cached_resolve_pqueue,
                             _compare_cached_resolves_by_expiry);

  SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
    {
      if (res->state == CACHE_STATE_DONE) {
        cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res);
        tor_assert(!found || found != res);
      } else {
        cached_resolve_t *found = HT_FIND(cache_map, &cache_root, res);
        tor_assert(found);
      }
    });
}
#endif


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -