Back to index

tor  0.2.3.18-rc
Functions
dns.h File Reference

Header file for dns.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int dns_init (void)
 Initialize the DNS subsystem; called by the OR process.
int has_dns_init_failed (void)
 Return true iff the most recent attempt to initialize the DNS subsystem failed.
void dns_free_all (void)
 Free all storage held in the DNS cache and related structures.
uint32_t dns_clip_ttl (uint32_t ttl)
 Helper: Given a TTL from a DNS response, determine what TTL to give the OP that asked us to resolve it.
int dns_reset (void)
 Called when DNS-related options change (or may have changed).
void connection_dns_remove (edge_connection_t *conn)
 Remove conn from the list of connections waiting for conn->address.
void assert_connection_edge_not_dns_pending (edge_connection_t *conn)
 Log an error and abort if conn is waiting for a DNS resolve.
void assert_all_pending_dns_resolves_ok (void)
 Log an error and abort if any connection waiting for a DNS resolve is corrupted.
void dns_cancel_pending_resolve (const char *question)
 Mark all connections waiting for address for close.
int dns_resolve (edge_connection_t *exitconn)
 See if we have a cache entry for exitconn->address.
void dns_launch_correctness_checks (void)
 If appropriate, start testing whether our DNS servers tend to lie to us.
int dns_seems_to_be_broken (void)
 Return true iff our DNS servers lie to us too much to be trusted.
void dns_reset_correctness_checks (void)
 Forget what we've previously learned about our DNS servers' correctness.
void dump_dns_mem_usage (int severity)
 Log memory information about our internal DNS cache at level 'severity'.

Detailed Description

Header file for dns.c.

Definition in file dns.h.


Function Documentation

Log an error and abort if any connection waiting for a DNS resolve is corrupted.

Definition at line 842 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t **resolve;

  HT_FOREACH(resolve, cache_map, &cache_root) {
    for (pend = (*resolve)->pending_connections;
         pend;
         pend = pend->next) {
      assert_connection_ok(TO_CONN(pend->conn), 0);
      tor_assert(!SOCKET_OK(pend->conn->_base.s));
      tor_assert(!connection_in_array(TO_CONN(pend->conn)));
    }
  }
}

Here is the call graph for this function:

Log an error and abort if conn is waiting for a DNS resolve.

Definition at line 815 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t search;

#if 1
  cached_resolve_t *resolve;
  strlcpy(search.address, conn->_base.address, sizeof(search.address));
  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve)
    return;
  for (pend = resolve->pending_connections; pend; pend = pend->next) {
    tor_assert(pend->conn != conn);
  }
#else
  cached_resolve_t **resolve;
  HT_FOREACH(resolve, cache_map, &cache_root) {
    for (pend = (*resolve)->pending_connections; pend; pend = pend->next) {
      tor_assert(pend->conn != conn);
    }
  }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove conn from the list of connections waiting for conn->address.

Definition at line 861 of file dns.c.

{
  pending_connection_t *pend, *victim;
  cached_resolve_t search;
  cached_resolve_t *resolve;

  tor_assert(conn->_base.type == CONN_TYPE_EXIT);
  tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);

  strlcpy(search.address, conn->_base.address, sizeof(search.address));

  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve) {
    log_notice(LD_BUG, "Address %s is not pending. Dropping.",
               escaped_safe_str(conn->_base.address));
    return;
  }

  tor_assert(resolve->pending_connections);
  assert_connection_ok(TO_CONN(conn),0);

  pend = resolve->pending_connections;

  if (pend->conn == conn) {
    resolve->pending_connections = pend->next;
    tor_free(pend);
    log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
              "for resolve of %s",
              conn->_base.s,
              escaped_safe_str(conn->_base.address));
    return;
  } else {
    for ( ; pend->next; pend = pend->next) {
      if (pend->next->conn == conn) {
        victim = pend->next;
        pend->next = victim->next;
        tor_free(victim);
        log_debug(LD_EXIT,
                  "Connection (fd %d) no longer waiting for resolve of %s",
                  conn->_base.s, escaped_safe_str(conn->_base.address));
        return; /* more are pending */
      }
    }
    tor_assert(0); /* not reachable unless onlyconn not in pending list */
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dns_cancel_pending_resolve ( const char *  address)

Mark all connections waiting for address for close.

Then cancel the resolve for address itself, and remove any cached results for address from the cache.

Definition at line 913 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t search;
  cached_resolve_t *resolve, *tmp;
  edge_connection_t *pendconn;
  circuit_t *circ;

  strlcpy(search.address, address, sizeof(search.address));

  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve)
    return;

  if (resolve->state != CACHE_STATE_PENDING) {
    /* We can get into this state if we never actually created the pending
     * resolve, due to finding an earlier cached error or something.  Just
     * ignore it. */
    if (resolve->pending_connections) {
      log_warn(LD_BUG,
               "Address %s is not pending but has pending connections!",
               escaped_safe_str(address));
      tor_fragile_assert();
    }
    return;
  }

  if (!resolve->pending_connections) {
    log_warn(LD_BUG,
             "Address %s is pending but has no pending connections!",
             escaped_safe_str(address));
    tor_fragile_assert();
    return;
  }
  tor_assert(resolve->pending_connections);

  /* mark all pending connections to fail */
  log_debug(LD_EXIT,
             "Failing all connections waiting on DNS resolve of %s",
             escaped_safe_str(address));
  while (resolve->pending_connections) {
    pend = resolve->pending_connections;
    pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
    pendconn = pend->conn;
    assert_connection_ok(TO_CONN(pendconn), 0);
    tor_assert(!SOCKET_OK(pendconn->_base.s));
    if (!pendconn->_base.marked_for_close) {
      connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
    }
    circ = circuit_get_by_edge_conn(pendconn);
    if (circ)
      circuit_detach_stream(circ, pendconn);
    if (!pendconn->_base.marked_for_close)
      connection_free(TO_CONN(pendconn));
    resolve->pending_connections = pend->next;
    tor_free(pend);
  }

  tmp = HT_REMOVE(cache_map, &cache_root, resolve);
  if (tmp != resolve) {
    log_err(LD_BUG, "The cancelled resolve we purged didn't match any in"
            " the cache. Tried to purge %s (%p); instead got %s (%p).",
            resolve->address, (void*)resolve,
            tmp ? tmp->address : "NULL", (void*)tmp);
  }
  tor_assert(tmp == resolve);

  resolve->state = CACHE_STATE_DONE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

uint32_t dns_clip_ttl ( uint32_t  ttl)

Helper: Given a TTL from a DNS response, determine what TTL to give the OP that asked us to resolve it.

Definition at line 313 of file dns.c.

{
  if (ttl < MIN_DNS_TTL)
    return MIN_DNS_TTL;
  else if (ttl > MAX_DNS_TTL)
    return MAX_DNS_TTL;
  else
    return ttl;
}

Here is the caller graph for this function:

void dns_free_all ( void  )

Free all storage held in the DNS cache and related structures.

Definition at line 389 of file dns.c.

{
  cached_resolve_t **ptr, **next, *item;
  assert_cache_ok();
  if (cached_resolve_pqueue) {
    SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
      {
        if (res->state == CACHE_STATE_DONE)
          _free_cached_resolve(res);
      });
  }
  for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) {
    item = *ptr;
    next = HT_NEXT_RMV(cache_map, &cache_root, ptr);
    _free_cached_resolve(item);
  }
  HT_CLEAR(cache_map, &cache_root);
  smartlist_free(cached_resolve_pqueue);
  cached_resolve_pqueue = NULL;
  tor_free(resolv_conf_fname);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_init ( void  )

Initialize the DNS subsystem; called by the OR process.

Definition at line 263 of file dns.c.

{
  init_cache_map();
  evdns_set_random_bytes_fn(_dns_randfn);
  if (server_mode(get_options())) {
    int r = configure_nameservers(1);
    return r;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

If appropriate, start testing whether our DNS servers tend to lie to us.

Definition at line 1671 of file dns.c.

{
  static struct event *launch_event = NULL;
  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. */
  if (! launch_event)
    launch_event = tor_evtimer_new(tor_libevent_get_base(),
                                   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");
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_reset ( void  )

Called when DNS-related options change (or may have changed).

Returns -1 on failure, 0 on success.

Definition at line 277 of file dns.c.

{
  const or_options_t *options = get_options();
  if (! server_mode(options)) {

    if (!the_evdns_base) {
      if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) {
        log_err(LD_BUG, "Couldn't create an evdns_base");
        return -1;
      }
    }

    evdns_base_clear_nameservers_and_suspend(the_evdns_base);
    evdns_base_search_clear(the_evdns_base);
    nameservers_configured = 0;
    tor_free(resolv_conf_fname);
    resolv_conf_mtime = 0;
  } else {
    if (configure_nameservers(0) < 0) {
      return -1;
    }
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Forget what we've previously learned about our DNS servers' correctness.

Definition at line 1700 of file dns.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_resolve ( edge_connection_t exitconn)

See if we have a cache entry for exitconn->address.

if so, if resolve valid, put it into exitconn->addr and return 1. If resolve failed, free exitconn and return -1.

(For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no need to send back an END cell, since connection_exit_begin_conn will do that for us.)

If we have a cached answer, send the answer back along exitconn's circuit.

Else, if seen before and pending, add conn to the pending list, and return 0.

Else, if not seen before, add conn to pending list, hand to dns farm, and return 0.

Exitconn's on_circuit field must be set, but exitconn should not yet be linked onto the n_streams/resolving_streams list of that circuit. On success, link the connection to n_streams if it's an exit connection. On "pending", link the connection to resolving streams. Otherwise, clear its on_circuit field.

Definition at line 595 of file dns.c.

{
  or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit);
  int is_resolve, r;
  char *hostname = NULL;
  is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;

  r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname);

  switch (r) {
    case 1:
      /* We got an answer without a lookup -- either the answer was
       * cached, or it was obvious (like an IP address). */
      if (is_resolve) {
        /* Send the answer back right now, and detach. */
        if (hostname)
          send_resolved_hostname_cell(exitconn, hostname);
        else
          send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
        exitconn->on_circuit = NULL;
      } else {
        /* Add to the n_streams list; the calling function will send back a
         * connected cell. */
        exitconn->next_stream = oncirc->n_streams;
        oncirc->n_streams = exitconn;
      }
      break;
    case 0:
      /* The request is pending: add the connection into the linked list of
       * resolving_streams on this circuit. */
      exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
      exitconn->next_stream = oncirc->resolving_streams;
      oncirc->resolving_streams = exitconn;
      break;
    case -2:
    case -1:
      /* The request failed before it could start: cancel this connection,
       * and stop everybody waiting for the same connection. */
      if (is_resolve) {
        send_resolved_cell(exitconn,
             (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
      }

      exitconn->on_circuit = NULL;

      dns_cancel_pending_resolve(exitconn->_base.address);

      if (!exitconn->_base.marked_for_close) {
        connection_free(TO_CONN(exitconn));
        // XXX ... and we just leak exitconn otherwise? -RD
        // If it's marked for close, it's on closeable_connection_lst in
        // main.c.  If it's on the closeable list, it will get freed from
        // main.c. -NM
        // "<armadev> If that's true, there are other bugs around, where we
        //  don't check if it's marked, and will end up double-freeing."
        // On the other hand, I don't know of any actual bugs here, so this
        // shouldn't be holding up the rc. -RD
      }
      break;
    default:
      tor_assert(0);
  }

  tor_free(hostname);
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_seems_to_be_broken ( void  )

Return true iff our DNS servers lie to us too much to be trusted.

Definition at line 1693 of file dns.c.

Here is the caller graph for this function:

void dump_dns_mem_usage ( int  severity)

Log memory information about our internal DNS cache at level 'severity'.

Definition at line 1758 of file dns.c.

{
  /* This should never be larger than INT_MAX. */
  int hash_count = dns_cache_entry_count();
  size_t hash_mem = sizeof(struct cached_resolve_t) * hash_count;
  hash_mem += HT_MEM_USAGE(&cache_root);

  /* Print out the count and estimated size of our &cache_root.  It undercounts
     hostnames in cached reverse resolves.
   */
  log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count);
  log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.",
      (unsigned)hash_mem);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int has_dns_init_failed ( void  )

Return true iff the most recent attempt to initialize the DNS subsystem failed.

Definition at line 305 of file dns.c.

Here is the caller graph for this function: