Commit 8727acf2 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

Add a new AddressMap directive to rewrite incoming socks addresses.

Add a new TrackHostExits directive to trigger addressmaps for
certain incoming socks addresses, for sites that break when your exit
keeps changing.
Redo the client-side dns cache so it's just an addressmap too.


svn:r3641
parent b5bddd8c
Loading
Loading
Loading
Loading
+53 −4
Original line number Diff line number Diff line
@@ -385,7 +385,7 @@ void circuit_build_needed_circs(time_t now) {
    circuit_reset_failure_count(1);
    time_to_new_circuit = now + get_options()->NewCircuitPeriod;
    if (proxy_mode(get_options()))
      client_dns_clean();
      addressmap_clean(now);
    circuit_expire_old_circuits();

#if 0 /* disable for now, until predict-and-launch-new can cull leftovers */
@@ -768,7 +768,6 @@ circuit_get_open_circ_or_launch(connection_t *conn,
                                uint8_t desired_circuit_purpose,
                                circuit_t **circp) {
  circuit_t *circ;
  uint32_t addr;
  int is_resolve;
  int need_uptime;

@@ -801,7 +800,10 @@ circuit_get_open_circ_or_launch(connection_t *conn,

  /* Do we need to check exit policy? */
  if (!is_resolve && !connection_edge_is_rendezvous_stream(conn)) {
    addr = client_dns_lookup_entry(conn->socks_request->address);
    struct in_addr in;
    uint32_t addr = 0;
    if (tor_inet_aton(conn->socks_request->address, &in))
      addr = ntohl(in.s_addr);
    if (router_exit_policy_all_routers_reject(addr, conn->socks_request->port,
                                              need_uptime)) {
      log_fn(LOG_NOTICE,"No Tor server exists that allows exit to %s:%d. Rejecting.",
@@ -899,6 +901,53 @@ static void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) {
  apconn->cpath_layer = circ->cpath->prev;
}

/** If an exit wasn't specifically chosen, save the history for future
 * use */
static void
consider_recording_trackhost(connection_t *conn, circuit_t *circ) {
  int found_needle = 0;
  char *str;
  or_options_t *options = get_options();
  size_t len;
  char *new_address;

  /* Search the addressmap for this conn's destination. */
  /* If he's not in the address map.. */
  if (!options->TrackHostExits ||
      addressmap_already_mapped(conn->socks_request->address))
    return; /* nothing to track, or already mapped */

  SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, {
    if (cp[0] == '.') { /* match end */
      /* XXX strstr is probably really bad here */
      if ((str = strstr(conn->socks_request->address, &cp[1]))) {
        if (str == conn->socks_request->address
          || strcmp(str, &cp[1]) == 0) {
          found_needle = 1;
        }
      }
    } else if (strcmp(cp, conn->socks_request->address) == 0) {
      found_needle = 1;
    }
  });

  if (!found_needle)
    return;

  /* Add this exit/hostname pair to the addressmap. */
  len = strlen(conn->socks_request->address) + 1 /* '.' */ +
        strlen(circ->build_state->chosen_exit_name) + 1 /* '.' */ +
        strlen("exit") + 1 /* '\0' */;
  new_address = tor_malloc(len);

  tor_snprintf(new_address, len, "%s.%s.exit",
               conn->socks_request->address,
               circ->build_state->chosen_exit_name);

  addressmap_register(conn->socks_request->address, new_address,
                      time(NULL) + options->TrackHostExitsExpire);
}

/** Try to find a safe live circuit for CONN_TYPE_AP connection conn. If
 * we don't find one: if conn cannot be handled by any known nodes,
 * warn and return -1 (conn needs to die);
@@ -957,7 +1006,7 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
    link_apconn_to_circ(conn, circ);
    tor_assert(conn->socks_request);
    if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
//      consider_recording_trackhost(conn, circ);
      consider_recording_trackhost(conn, circ);
      connection_ap_handshake_send_begin(conn, circ);
    } else {
      connection_ap_handshake_send_resolve(conn, circ);
+30 −0
Original line number Diff line number Diff line
@@ -120,6 +120,9 @@ static config_var_t config_vars[] = {
  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
  VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
  VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
  VAR("TrackHostExitsExpire",INTERVAL, TrackHostExitsExpire, "30 minutes"),
  VAR("AddressMap",          LINELIST, AddressMap,           NULL),
  VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
  VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
  VAR("MyFamily",            STRING,   MyFamily,             NULL),
@@ -186,6 +189,7 @@ static or_options_t *options_dup(or_options_t *old);
static int options_validate(or_options_t *options);
static int options_transition_allowed(or_options_t *old, or_options_t *new);
static int check_nickname_list(const char *lst, const char *name);
static void config_register_addressmaps(or_options_t *options);

static int parse_dir_server_line(const char *line, int validate_only);
static int parse_redirect_line(smartlist_t *result,
@@ -333,6 +337,9 @@ options_act(void) {
  if (options->PidFile)
    write_pidfile(options->PidFile);

  /* Register addressmap directives */
  config_register_addressmaps(options);

  /* Update address policies. */
  parse_socks_policy();
  parse_dir_policy();
@@ -1797,6 +1804,29 @@ init_from_config(int argc, char **argv)
  return -1;
}

static void
config_register_addressmaps(or_options_t *options) {
  smartlist_t *elts;
  struct config_line_t *opt;
  char *from, *to;

  elts = smartlist_create();
  for (opt = options->AddressMap; opt; opt = opt->next) {
    smartlist_split_string(elts, opt->value, NULL,
                           SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
    if (smartlist_len(elts) >= 2) {
      from = smartlist_get(elts,0);
      to = smartlist_get(elts,1);
      addressmap_register(from, tor_strdup(to), 0);
    } else {
      log_fn(LOG_WARN,"AddressMap '%s' has too few arguments. Ignoring.", opt->value);
    }
    SMARTLIST_FOREACH(elts, char*, cp, tor_free(cp));
    smartlist_clear(elts);
  }
  smartlist_free(elts);
}

/** If <b>range</b> is of the form MIN-MAX, for MIN and MAX both
 * recognized log severity levels, set *<b>min_out</b> to MIN and
 * *<b>max_out</b> to MAX and return 0.  Else, if <b>range<b> is of
+182 −185
Original line number Diff line number Diff line
@@ -329,6 +329,169 @@ void connection_ap_attach_pending(void)
  }
}

/** A client-side struct to remember requests to rewrite addresses
 * to new addresses. These structs make up a tree, with addressmap
 * below as its root.
 *
 * There are 5 ways to set an address mapping:
 * - A MapAddress command from the controller [permanent]
 * - An AddressMap directive in the torrc [permanent]
 * - When a TrackHostExits torrc directive is triggered [temporary]
 * - When a dns resolve succeeds [temporary]
 * - When a dns resolve fails [temporary]
 *
 * When an addressmap request is made but one is already registered,
 * the new one is replaced only if the currently registered one has
 * no "new_address" (that is, it's in the process of dns resolve),
 * or if the new one is permanent (expires==0).
 */
typedef struct {
  char *new_address;
  time_t expires;
  int num_resolve_failures;
} addressmap_entry_t;

/** The tree of client-side address rewrite instructions. */
static strmap_t *addressmap;

/** Initialize addressmap. */
void addressmap_init(void) {
  addressmap = strmap_new();
}

/** Free the memory associated with the addressmap entry <b>_ent</b>. */
static void
addressmap_ent_free(void *_ent) {
  addressmap_entry_t *ent = _ent;
  tor_free(ent->new_address);
  tor_free(ent);
}

/** A helper function for addressmap_clean() below. If ent is too old,
 * then remove it from the tree and return NULL, else return ent.
 */
static void *
_addressmap_remove_if_expired(const char *addr,
                              addressmap_entry_t *ent,
                              time_t *nowp) {
  if (ent->expires && ent->expires < *nowp) {
    log(LOG_NOTICE, "Addressmap: expiring remap (%s to %s)",
           addr, ent->new_address);
    addressmap_ent_free(ent);
    return NULL;
  } else {
    return ent;
  }
}

/** Clean out entries from the addressmap cache that were
 * added long enough ago that they are no longer valid.
 */
void addressmap_clean(time_t now) {
  strmap_foreach(addressmap,
                 (strmap_foreach_fn)_addressmap_remove_if_expired, &now);
}

/** Free all the elements in the addressmap, and free the addressmap
 * itself. */
void addressmap_free_all(void) {
  strmap_free(addressmap, addressmap_ent_free);
  addressmap = NULL;
}

/** Look at address, and rewrite it until it doesn't want any
 * more rewrites; but don't get into an infinite loop.
 * Don't write more than maxlen chars into address.
 */
void addressmap_rewrite(char *address, size_t maxlen) {
  addressmap_entry_t *ent;
  int rewrites;

  for (rewrites = 0; rewrites < 16; rewrites++) {
    ent = strmap_get(addressmap, address);

    if (!ent || !ent->new_address)
      return; /* done, no rewrite needed */

    log_fn(LOG_NOTICE, "Addressmap: rewriting '%s' to '%s'",
           address, ent->new_address);
    strlcpy(address, ent->new_address, maxlen);
  }
  log_fn(LOG_WARN,"Loop detected: we've rewritten '%s' 16 times! Using it as-is.",
         address);
  /* it's fine to rewrite a rewrite, but don't loop forever */
}

/** Return 1 if <b>address</b> is already registered, else return 0 */
int addressmap_already_mapped(const char *address) {
  return strmap_get(addressmap, address) ? 1 : 0;
}

/** Register a request to map <b>address</b> to <b>new_address</b>,
 * which will expire on <b>expires</b> (or 0 if never expires).
 *
 * new_address should be a newly dup'ed string, which we'll use or
 * free as appropriate. We will leave address alone.
 */
void addressmap_register(const char *address, char *new_address, time_t expires) {
  addressmap_entry_t *ent;

  ent = strmap_get(addressmap, address);
  if (ent && ent->new_address && expires) {
    log_fn(LOG_NOTICE,"Addressmap ('%s' to '%s') not performed, since it's already mapped to '%s'", address, new_address, ent->new_address);
    tor_free(new_address);
    return;
  }
  if (ent) { /* we'll replace it */
    tor_free(ent->new_address);
  } else { /* make a new one and register it */
    ent = tor_malloc_zero(sizeof(addressmap_entry_t));
    strmap_set(addressmap, address, ent);
  }
  ent->new_address = new_address;
  ent->expires = expires;
  ent->num_resolve_failures = 0;

  log_fn(LOG_NOTICE, "Addressmap: (re)mapped '%s' to '%s'",
         address, ent->new_address);
}

/** An attempt to resolve <b>address</b> failed at some OR.
 * Increment the number of resolve failures we have on record
 * for it, and then return that number.
 */
int client_dns_incr_failures(const char *address)
{
  addressmap_entry_t *ent;
  ent = strmap_get(addressmap,address);
  if (!ent) {
    ent = tor_malloc_zero(sizeof(addressmap_entry_t));
    ent->expires = time(NULL)+MAX_DNS_ENTRY_AGE;
    strmap_set(addressmap,address,ent);
  }
  ++ent->num_resolve_failures;
  log_fn(LOG_NOTICE,"Address %s now has %d resolve failures.",
         address, ent->num_resolve_failures);
  return ent->num_resolve_failures;
}

/** Record the fact that <b>address</b> resolved to <b>val</b>.
 * We can now use this in subsequent streams via addressmap_rewrite()
 * so we can more correctly choose an exit that will allow <b>address</b>.
 */
void client_dns_set_addressmap(const char *address, uint32_t val)
{
  struct in_addr in;

  tor_assert(address); tor_assert(val);

  if (tor_inet_aton(address, &in))
    return; /* don't set an addressmap back to ourselves! */
  in.s_addr = htonl(val);
  addressmap_register(address, strdup(inet_ntoa(in)),
                      time(NULL) + MAX_DNS_ENTRY_AGE);
}

/** Return 1 if <b>address</b> has funny characters in it like
 * colons. Return 0 if it's fine.
 */
@@ -383,6 +546,11 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
    return sockshere;
  } /* else socks handshake is done, continue processing */

  tor_strlower(socks->address); /* normalize it */

  /* For address map controls, remap the address */
  addressmap_rewrite(socks->address, sizeof(socks->address));

  /* Parse the address provided by SOCKS.  Modify it in-place if it
   * specifies a hidden-service (.onion) or particular exit node (.exit).
   */
@@ -408,7 +576,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
    }

    if (socks->command == SOCKS_COMMAND_RESOLVE) {
      uint32_t answer = 0;
      uint32_t answer;
      struct in_addr in;
      /* Reply to resolves immediately if we can. */
      if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
@@ -416,11 +584,8 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
        connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL);
        return -1;
      }
      if (tor_inet_aton(socks->address, &in)) /* see if it's an IP already */
      if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
        answer = in.s_addr;
      if (!answer && !conn->chosen_exit_name) /* if it's not .exit, check cache */
        answer = htonl(client_dns_lookup_entry(socks->address));
      if (answer) {
        connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
                                               (char*)&answer);
        conn->has_sent_end = 1;
@@ -514,8 +679,6 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
{
  char payload[CELL_PAYLOAD_SIZE];
  int payload_len;
  struct in_addr in;
  const char *string_addr;

  tor_assert(ap_conn->type == CONN_TYPE_AP);
  tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
@@ -530,18 +693,10 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
    return -1;
  }

  if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
    in.s_addr = htonl(client_dns_lookup_entry(ap_conn->socks_request->address));
    string_addr = in.s_addr ? inet_ntoa(in) : NULL;

    tor_snprintf(payload,RELAY_PAYLOAD_SIZE,
             "%s:%d",
             string_addr ? string_addr : ap_conn->socks_request->address,
  tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
               (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
                 ap_conn->socks_request->address : "",
               ap_conn->socks_request->port);
  } else {
    tor_snprintf(payload,RELAY_PAYLOAD_SIZE,
             ":%d", ap_conn->socks_request->port);
  }
  payload_len = strlen(payload)+1;

  log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",ap_conn->stream_id);
@@ -670,7 +825,7 @@ void connection_ap_handshake_socks_resolved(connection_t *conn,
  if (answer_type == RESOLVED_TYPE_IPV4) {
    uint32_t a = get_uint32(answer);
    if (a)
      client_dns_set_entry(conn->socks_request->address, ntohl(a));
      client_dns_set_addressmap(conn->socks_request->address, ntohl(a));
  }

  if (conn->socks_request->socks_version == 4) {
@@ -844,6 +999,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
    tor_free(address);
    return 0;
  }
  tor_strlower(address);
  n_stream->address = address;
  n_stream->state = EXIT_CONN_STATE_RESOLVEFAILED;
  /* default to failed, change in dns_resolve if it turns out not to fail */
@@ -1018,8 +1174,6 @@ int connection_edge_is_rendezvous_stream(connection_t *conn) {
 */
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
{
  uint32_t addr;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_AP);
  tor_assert(conn->socks_request);
@@ -1042,7 +1196,10 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
  }

  if (conn->socks_request->command != SOCKS_COMMAND_RESOLVE) {
    addr = client_dns_lookup_entry(conn->socks_request->address);
    struct in_addr in;
    uint32_t addr = 0;
    if (tor_inet_aton(conn->socks_request->address, &in))
      addr = ntohl(in.s_addr);
    if (router_compare_addr_to_addr_policy(addr, conn->socks_request->port,
          exit->exit_policy) == ADDR_POLICY_REJECTED)
      return 0;
@@ -1098,164 +1255,6 @@ int socks_policy_permits_address(uint32_t addr)
  return 0;
}

/* ***** Client DNS code ***** */

/* XXX Perhaps this should get merged with the dns.c code somehow. */
/* XXX But we can't just merge them, because then nodes that act as
 *     both OR and OP could be attacked: people could rig the dns cache
 *     by answering funny things to stream begin requests, and later
 *     other clients would reuse those funny addr's. Hm.
 */

/** A client-side struct to remember the resolved IP (addr) for
 * a given address. These structs make up a tree, with client_dns_map
 * below as its root.
 */
struct client_dns_entry {
  uint32_t addr; /**< The resolved IP of this entry. */
  time_t expires; /**< At what second does addr expire? */
  int n_failures; /**< How many times has this entry failed to resolve so far? */
};

/** How many elements are in the client dns cache currently? */
static int client_dns_size = 0;
/** The tree of client-side cached DNS resolves. */
static strmap_t *client_dns_map = NULL;

/** Initialize client_dns_map and client_dns_size. */
void client_dns_init(void) {
  client_dns_map = strmap_new();
  client_dns_size = 0;
}

/** Return the client_dns_entry that corresponds to <b>address</b>.
 * If it's not there, allocate and return a new entry for <b>address</b>.
 */
static struct client_dns_entry *
_get_or_create_ent(const char *address)
{
  struct client_dns_entry *ent;
  ent = strmap_get_lc(client_dns_map,address);
  if (!ent) {
    ent = tor_malloc_zero(sizeof(struct client_dns_entry));
    ent->expires = time(NULL)+MAX_DNS_ENTRY_AGE;
    strmap_set_lc(client_dns_map,address,ent);
    ++client_dns_size;
  }
  return ent;
}

/** Return the IP associated with <b>address</b>, if we know it
 * and it's still fresh enough. Otherwise return 0.
 */
uint32_t client_dns_lookup_entry(const char *address)
{
  struct client_dns_entry *ent;
  struct in_addr in;
  time_t now;

  tor_assert(address);

  if (tor_inet_aton(address, &in)) {
    log_fn(LOG_DEBUG, "Using static address %s (%08lX)", address,
           (unsigned long)ntohl(in.s_addr));
    return ntohl(in.s_addr);
  }
  ent = strmap_get_lc(client_dns_map,address);
  if (!ent || !ent->addr) {
    log_fn(LOG_DEBUG, "No entry found for address %s", address);
    return 0;
  } else {
    now = time(NULL);
    if (ent->expires < now) {
      log_fn(LOG_DEBUG, "Expired entry found for address %s", address);
      strmap_remove_lc(client_dns_map,address);
      tor_free(ent);
      --client_dns_size;
      return 0;
    }
    in.s_addr = htonl(ent->addr);
    log_fn(LOG_DEBUG, "Found cached entry for address %s: %s", address,
           inet_ntoa(in));
    return ent->addr;
  }
}

/** An attempt to resolve <b>address</b> failed at some OR.
 * Increment the number of resolve failures we have on record
 * for it, and then return that number.
 */
int client_dns_incr_failures(const char *address)
{
  struct client_dns_entry *ent;
  ent = _get_or_create_ent(address);
  ++ent->n_failures;
  log_fn(LOG_DEBUG,"Address %s now has %d resolve failures.",
         address, ent->n_failures);
  return ent->n_failures;
}

/** Record the fact that <b>address</b> resolved to <b>val</b>.
 * We can now use this in subsequent streams in client_dns_lookup_entry(),
 * so we can more correctly choose a router that will allow <b>address</b>
 * to exit from him.
 */
void client_dns_set_entry(const char *address, uint32_t val)
{
  struct client_dns_entry *ent;
  struct in_addr in;
  time_t now;

  tor_assert(address);
  tor_assert(val);

  if (tor_inet_aton(address, &in))
    return;
  now = time(NULL);
  ent = _get_or_create_ent(address);
  in.s_addr = htonl(val);
  log_fn(LOG_DEBUG, "Updating entry for address %s: %s", address,
         inet_ntoa(in));
  ent->addr = val;
  ent->expires = now+MAX_DNS_ENTRY_AGE;
  ent->n_failures = 0;
}

/** A helper function for client_dns_clean() below. If ent is too old,
 * then remove it from the tree and return NULL, else return ent.
 */
static void* _remove_if_expired(const char *addr,
                                struct client_dns_entry *ent,
                                time_t *nowp)
{
  if (ent->expires < *nowp) {
    --client_dns_size;
    tor_free(ent);
    return NULL;
  } else {
    return ent;
  }
}

/** Clean out entries from the client-side DNS cache that were
 * resolved long enough ago that they are no longer valid.
 */
void client_dns_clean(void)
{
  time_t now;

  if (!client_dns_size)
    return;
  now = time(NULL);
  strmap_foreach(client_dns_map, (strmap_foreach_fn)_remove_if_expired, &now);
}

void client_dns_free_all(void)
{
  strmap_free(client_dns_map, free);
  client_dns_map = NULL;
}

/** Make connection redirection follow the provided list of
 * exit_redirect_t */
void
@@ -1284,20 +1283,18 @@ parse_extended_hostname(char *address) {

    s = strrchr(address,'.');
    if (!s) return 0; /* no dot, thus normal */
    if (!strcasecmp(s+1,"exit")) {
    if (!strcmp(s+1,"exit")) {
      *s = 0; /* null-terminate it */
      return EXIT_HOSTNAME; /* .exit */
    }
    if (strcasecmp(s+1,"onion"))
    if (strcmp(s+1,"onion"))
      return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */

    /* so it is .onion */
    *s = 0; /* null-terminate it */
    if (strlcpy(query, address, REND_SERVICE_ID_LEN+1) >= REND_SERVICE_ID_LEN+1)
      goto failed;
    tor_strlower(query);
    if (rend_valid_service_id(query)) {
      tor_strlower(address);
      return ONION_HOSTNAME; /* success */
    }
failed:
+2 −2
Original line number Diff line number Diff line
@@ -1263,7 +1263,7 @@ static int tor_init(int argc, char *argv[]) {
  rep_hist_init();
  /* Initialize the service cache. */
  rend_cache_init();
  client_dns_init(); /* Init the client dns cache. Do it always, since it's cheap. */
  addressmap_init(); /* Init the client dns cache. Do it always, since it's cheap. */

  /* give it somewhere to log to initially */
  add_temp_log();
@@ -1308,7 +1308,7 @@ void tor_free_all(void)
{
  routerlist_free_current();
  free_trusted_dir_servers();
  client_dns_free_all();
  addressmap_free_all();
  free_socks_policy();
  free_dir_policy();
  dirserv_free_all();
+14 −6
Original line number Diff line number Diff line
@@ -950,6 +950,10 @@ typedef struct {
  smartlist_t *FirewallPorts; /**< Which ports our firewall allows (strings). */
  /** Application ports that require all nodes in circ to have sufficient uptime. */
  smartlist_t *LongLivedPorts;
  /** Should we try to reuse the same exit node for a given host */
  smartlist_t *TrackHostExits;
  int TrackHostExitsExpire; /**< Number of seconds until we expire an addressmap */
  struct config_line_t *AddressMap; /**< List of address map directives. */
  int DirFetchPeriod; /**< How often do we fetch new directories? */
  int DirPostPeriod; /**< How often do we post our server descriptor to the
                      * authoritative directory servers? */
@@ -1212,6 +1216,7 @@ connection_t *connection_get_by_identity_digest(const char *digest, int type);

connection_t *connection_get_by_type(int type);
connection_t *connection_get_by_type_state(int type, int state);
connection_t *connection_get_by_type_purpose(int type, int purpose);
connection_t *connection_get_by_type_state_lastwritten(int type, int state);
connection_t *connection_get_by_type_state_rendquery(int type, int state, const char *rendquery);
connection_t *connection_get_by_type_purpose(int type, int purpose);
@@ -1258,16 +1263,19 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);

void addressmap_init(void);
void addressmap_clean(time_t now);
void addressmap_free_all(void);
void addressmap_rewrite(char *address, size_t maxlen);
int addressmap_already_mapped(const char *address);
void addressmap_register(const char *address, char *new_address, time_t expires);
int client_dns_incr_failures(const char *address);
void client_dns_set_addressmap(const char *address, uint32_t val);

void parse_socks_policy(void);
void free_socks_policy(void);
int socks_policy_permits_address(uint32_t addr);

void client_dns_init(void);
uint32_t client_dns_lookup_entry(const char *address);
int client_dns_incr_failures(const char *address);
void client_dns_set_entry(const char *address, uint32_t val);
void client_dns_clean(void);
void client_dns_free_all(void);
void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t {
  NORMAL_HOSTNAME, ONION_HOSTNAME, EXIT_HOSTNAME
Loading