Commit 84c81e07 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

Annotate circuits w/ whether they aim to contain high uptime nodes and/or

high capacity nodes. When building circuits, choose appropriate nodes.

New config option LongLivedPorts to indicate application streams
that will want high uptime circuits.

When attaching a stream to a circuit, pay attention to its requirements.

This means that every single node in an intro rend circuit, not just
the last one, will have a minimum uptime.

Boost the min uptime from an hour to 24 hours.


svn:r3339
parent 51f47d74
Loading
Loading
Loading
Loading
+46 −20
Original line number Diff line number Diff line
@@ -21,8 +21,9 @@ extern circuit_t *global_circuitlist;

static int
circuit_deliver_create_cell(circuit_t *circ, char *payload);
static cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose,
                                                   const char *exit_digest);
static cpath_build_state_t *
onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest,
                            int need_uptime, int need_capacity);
static int onion_extend_cpath(crypt_path_t **head_ptr,
                       cpath_build_state_t *state, routerinfo_t **router_out);
static int count_acceptable_routers(smartlist_t *routers);
@@ -233,15 +234,17 @@ void circuit_dump_by_conn(connection_t *conn, int severity) {
 * Also launch a connection to the first OR in the chosen path, if
 * it's not open already.
 */
circuit_t *circuit_establish_circuit(uint8_t purpose,
                                     const char *exit_digest) {
circuit_t *
circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
                          int need_uptime, int need_capacity) {
  routerinfo_t *firsthop;
  connection_t *n_conn;
  circuit_t *circ;

  circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
  circ->state = CIRCUIT_STATE_OR_WAIT;
  circ->build_state = onion_new_cpath_build_state(purpose, exit_digest);
  circ->build_state = onion_new_cpath_build_state(purpose, exit_digest,
                                                  need_uptime, need_capacity);
  circ->purpose = purpose;

  if (! circ->build_state) {
@@ -811,13 +814,24 @@ circuit_get_unhandled_ports(time_t now) {

/** Return 1 if we already have circuits present or on the way for
 * all anticipated ports. Return 0 if we should make more.
 *
 * If we're returning 0, set need_uptime and need_capacity to
 * indicate any requirements that the unhandled ports have.
 */
int
circuit_all_predicted_ports_handled(time_t now) {
  int enough;
circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
                                    int *need_capacity) {
  int i, enough;
  uint16_t *port;
  smartlist_t *sl = circuit_get_unhandled_ports(now);
  smartlist_t *LongLivedServices = get_options()->LongLivedPorts;
  enough = (smartlist_len(sl) == 0);
  SMARTLIST_FOREACH(sl, uint16_t *, cp, tor_free(cp));
  for (i = 0; i < smartlist_len(sl); ++i) {
    port = smartlist_get(sl, i);
    if (smartlist_string_num_isin(LongLivedServices, *port))
      *need_uptime = 1;
    tor_free(port);
  }
  smartlist_free(sl);
  return enough;
}
@@ -853,7 +867,9 @@ router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports) {
 *
 * Return NULL if we can't find any suitable routers.
 */
static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
static routerinfo_t *
choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
                                int need_capacity)
{
  int *n_supported;
  int i, j;
@@ -905,9 +921,13 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
//             router->nickname, i);
      continue; /* skip routers that are known to be down */
    }
    if (router_is_unreliable(router, need_uptime, need_capacity)) {
      n_supported[i] = -1;
      continue; /* skip routers that are not suitable */
    }
    if (!router->is_verified &&
        (!(options->_AllowUnverified & ALLOW_UNVERIFIED_EXIT) ||
         router_is_unreliable_router(router, 1, 1))) {
         router_is_unreliable(router, 1, 1))) {
      /* if it's unverified, and either we don't want it or it's unsuitable */
      n_supported[i] = -1;
//      log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- unverified router.",
@@ -1035,16 +1055,19 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
 * For client-side rendezvous circuits, choose a random node, weighted
 * toward the preferences in 'options'.
 */
static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir)
static routerinfo_t *
choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
                        int need_uptime, int need_capacity)
{
  routerinfo_t *r;
  or_options_t *options = get_options();
  switch (purpose) {
    case CIRCUIT_PURPOSE_C_GENERAL:
      return choose_good_exit_server_general(dir);
      return choose_good_exit_server_general(dir, need_uptime, need_capacity);
    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      r = router_choose_random_node(options->RendNodes, options->RendExcludeNodes,
          NULL, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0);
          NULL, need_uptime, need_capacity,
          options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0);
      return r;
  }
  log_fn(LOG_WARN,"Bug: unhandled purpose %d", purpose);
@@ -1056,7 +1079,8 @@ static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir)
 * return it.
 */
static cpath_build_state_t *
onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest)
onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest,
                            int need_uptime, int need_capacity)
{
  routerlist_t *rl;
  int r;
@@ -1071,6 +1095,8 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest)
    return NULL;
  info = tor_malloc_zero(sizeof(cpath_build_state_t));
  info->desired_path_len = r;
  info->need_uptime = need_uptime;
  info->need_capacity = need_capacity;
  if (exit_digest) { /* the circuit-builder pre-requested one */
    memcpy(info->chosen_exit_digest, exit_digest, DIGEST_LEN);
    exit = router_get_by_digest(exit_digest);
@@ -1083,7 +1109,7 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest)
    }
    log_fn(LOG_INFO,"Using requested exit node '%s'", info->chosen_exit_name);
  } else { /* we have to decide one */
    exit = choose_good_exit_server(purpose, rl);
    exit = choose_good_exit_server(purpose, rl, need_uptime, need_capacity);
    if (!exit) {
      log_fn(LOG_WARN,"failed to choose an exit server");
      tor_free(info);
@@ -1169,7 +1195,8 @@ static routerinfo_t *choose_good_middle_server(cpath_build_state_t *state,
    }
  }
  choice = router_choose_random_node(NULL, get_options()->ExcludeNodes, excluded,
           0, 1, get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0);
           state->need_uptime, state->need_capacity,
           get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0);
  smartlist_free(excluded);
  return choice;
}
@@ -1179,7 +1206,6 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state)
  routerinfo_t *r, *choice;
  smartlist_t *excluded = smartlist_create();
  or_options_t *options = get_options();
  char buf[16];

  if ((r = router_get_by_digest(state->chosen_exit_digest))) {
    smartlist_add(excluded, r);
@@ -1200,13 +1226,13 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state)

    for (i=0; i < smartlist_len(rl->routers); i++) {
      r = smartlist_get(rl->routers, i);
      tor_snprintf(buf, sizeof(buf), "%d", r->or_port);
      if (!smartlist_string_isin(options->FirewallPorts, buf))
      if (!smartlist_string_num_isin(options->FirewallPorts, r->or_port))
         smartlist_add(excluded, r);
    }
  }
  choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes,
           excluded, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
           excluded, state->need_uptime, state->need_capacity,
           options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
           options->StrictEntryNodes);
  smartlist_free(excluded);
  return choice;
+27 −9
Original line number Diff line number Diff line
@@ -78,6 +78,11 @@ static int circuit_is_acceptable(circuit_t *circ,
      return 0; /* this circuit is screwed and doesn't know it yet */
    }

    if (!circ->build_state->need_uptime &&
        smartlist_string_num_isin(get_options()->LongLivedPorts,
                                  conn->socks_request->port))
      return 0;

    if (conn->socks_request &&
        conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
      /* 0.0.8 servers have buggy resolve support. */
@@ -311,6 +316,7 @@ int circuit_stream_is_being_handled(connection_t *conn, uint16_t port, int min)
void circuit_build_needed_circs(time_t now) {
  static long time_to_new_circuit = 0;
  circuit_t *circ;
  int need_uptime=0, need_capacity=1;

  /* launch a new circ for any pending streams that need one */
  connection_ap_attach_pending();
@@ -332,7 +338,7 @@ void circuit_build_needed_circs(time_t now) {
        circ &&
        circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) {
      log_fn(LOG_INFO,"Creating a new testing circuit.");
      circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL);
      circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL, 0, 0);
    }
  }

@@ -353,8 +359,9 @@ void circuit_build_needed_circs(time_t now) {
  /* if we know of a port that's been requested recently and no
   * circuit is currently available that can handle it, start one
   * for that too. */
  if (!circuit_all_predicted_ports_handled(now)) {
    circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL);
  if (!circuit_all_predicted_ports_handled(now, &need_uptime, &need_capacity)) {
    circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL,
                               need_uptime, need_capacity);
  }

  /* XXX count idle rendezvous circs and build more */
@@ -637,7 +644,9 @@ static int did_circs_fail_last_period = 0;
 * success. */
#define MAX_CIRCUIT_FAILURES 5

circuit_t *circuit_launch_by_identity(uint8_t purpose, const char *exit_digest)
circuit_t *
circuit_launch_by_identity(uint8_t purpose, const char *exit_digest,
                           int need_uptime, int need_capacity)
{
  if (!has_fetched_directory) {
    log_fn(LOG_DEBUG,"Haven't fetched directory yet; canceling circuit launch.");
@@ -652,11 +661,14 @@ circuit_t *circuit_launch_by_identity(uint8_t purpose, const char *exit_digest)
  }

  /* try a circ. if it fails, circuit_mark_for_close will increment n_circuit_failures */
  return circuit_establish_circuit(purpose, exit_digest);
  return circuit_establish_circuit(purpose, exit_digest,
                                   need_uptime, need_capacity);
}

/** Launch a new circuit and return a pointer to it. Return NULL if you failed. */
circuit_t *circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname)
circuit_t *
circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
                           int need_uptime, int need_capacity)
{
  const char *digest = NULL;

@@ -668,7 +680,8 @@ circuit_t *circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname
    }
    digest = r->identity_digest;
  }
  return circuit_launch_by_identity(purpose, digest);
  return circuit_launch_by_identity(purpose, digest,
                                    need_uptime, need_capacity);
}

/** Record another failure at opening a general circuit. When we have
@@ -704,6 +717,7 @@ circuit_get_open_circ_or_launch(connection_t *conn,
  circuit_t *circ;
  uint32_t addr;
  int is_resolve;
  int need_uptime;

  tor_assert(conn);
  tor_assert(circp);
@@ -729,10 +743,14 @@ circuit_get_open_circ_or_launch(connection_t *conn,
    return 0;
  }

  need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts,
                                          conn->socks_request->port);

  /* 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);
    if (router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) {
    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.",
             conn->socks_request->address, conn->socks_request->port);
      return -1;
@@ -783,7 +801,7 @@ circuit_get_open_circ_or_launch(connection_t *conn,
    else
      new_circ_purpose = desired_circuit_purpose;

    circ = circuit_launch_by_nickname(new_circ_purpose, exitname);
    circ = circuit_launch_by_nickname(new_circ_purpose, exitname, need_uptime, 1);
    tor_free(exitname);

    if (circ &&
+31 −12
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ static config_abbrev_t config_abbrevs[] = {
  PLURAL(EntryNode),
  PLURAL(ExcludeNode),
  PLURAL(FirewallPort),
  PLURAL(LongLivedPort),
  PLURAL(HiddenServiceNode),
  PLURAL(HiddenServiceExcludeNode),
  PLURAL(RendNode),
@@ -149,6 +150,7 @@ static config_var_t config_vars[] = {
  VAR("ORBindAddress",       LINELIST, ORBindAddress,        NULL),
  VAR("OutboundBindAddress", STRING,   OutboundBindAddress,  NULL),
  VAR("PidFile",             STRING,   PidFile,              NULL),
  VAR("LongLivedPorts",      CSV,      LongLivedPorts,       "22,6667"),
  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight,    "0.3"),
  VAR("RedirectExit",        LINELIST, RedirectExit,         NULL),
  OBSOLETE("RouterFile"),
@@ -1137,13 +1139,32 @@ config_dump_options(or_options_t *options, int minimal)
  return result;
}

static int
validate_ports_csv(smartlist_t *sl, char *name) {
  int i;
  int result = 0;
  tor_assert(name);

  if(!sl)
    return 0;

  SMARTLIST_FOREACH(sl, const char *, cp,
  {
    i = atoi(cp);
    if (i < 1 || i > 65535) {
      log(LOG_WARN, "Port '%s' out of range in %s", cp, name);
      result=-1;
    }
  });
  return result;
}

/** Return 0 if every setting in <b>options</b> is reasonable.  Else
 * warn and return -1.  Should have no side effects, except for
 * normalizing the contents of <b>options</b>. */
static int
options_validate(or_options_t *options)
{
  int i;
  int result = 0;
  struct config_line_t *cl;
  addr_policy_t *addr_policy=NULL;
@@ -1261,16 +1282,14 @@ options_validate(or_options_t *options)
    options->_AccountingMaxKB = 0;
  }

  if (options->FirewallPorts) {
    SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp,
    {
      i = atoi(cp);
      if (i < 1 || i > 65535) {
        log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp);
  if (validate_ports_csv(options->FirewallPorts,
                         "FirewallPorts") < 0)
    result = -1;
      }
    });
  }

  if (validate_ports_csv(options->LongLivedPorts,
                         "LongLivedPorts") < 0)
    result = -1;

  options->_AllowUnverified = 0;
  if (options->AllowUnverifiedNodes) {
    SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
+2 −4
Original line number Diff line number Diff line
@@ -116,7 +116,6 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
                             size_t payload_len)
{
  smartlist_t *dirservers;
  char buf[16];

  router_get_trusted_dir_servers(&dirservers);
  tor_assert(dirservers);
@@ -130,8 +129,7 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
       * descriptor -- those use Tor. */
      if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
          !get_options()->HttpProxy) {
        tor_snprintf(buf,sizeof(buf),"%d",ds->dir_port);
        if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
        if (!smartlist_string_num_isin(get_options()->FirewallPorts, ds->dir_port))
          continue;
      }
      directory_initiate_command_trusted_dir(ds, purpose, NULL,
@@ -244,7 +242,7 @@ connection_dir_connect_failed(connection_t *conn)
  }
}

/** Helper for directory_initiate_command(router|trusted_dir): send the
/** Helper for directory_initiate_command_(router|trusted_dir): send the
 * command to a server whose address is <b>address</b>, whose IP is
 * <b>addr</b>, whose directory port is <b>dir_port</b>, whose tor version is
 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The
+22 −10
Original line number Diff line number Diff line
@@ -722,6 +722,10 @@ typedef struct {
  char *chosen_exit_name;
  /** Identity of planned exit node. */
  char chosen_exit_digest[DIGEST_LEN];
  /** Whether every node in the circ must have adequate uptime. */
  int need_uptime;
  /** Whether every node in the circ must have adequate capacity. */
  int need_capacity;
  /** The crypt_path_t to append after rendezvous: used for rendezvous. */
  struct crypt_path_t *pending_final_cpath;
  /** How many times has building a circuit for this task failed? */
@@ -930,7 +934,9 @@ typedef struct {
                      * directory recommends. */
  int RunAsDaemon; /**< If true, run in the background. (Unix only) */
  int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
  smartlist_t *FirewallPorts; /** Which ports our firewall allows. */
  smartlist_t *FirewallPorts; /**< Which ports our firewall allows (strings). */
  /** Application ports that require all nodes in circ to have sufficient uptime. */
  smartlist_t *LongLivedPorts;
  int DirFetchPeriod; /**< How often do we fetch new directories? */
  int DirPostPeriod; /**< How often do we post our server descriptor to the
                      * authoritative directory servers? */
@@ -1040,8 +1046,8 @@ char *circuit_list_path(circuit_t *circ, int verbose);
void circuit_log_path(int severity, circuit_t *circ);
void circuit_rep_hist_note_result(circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity);
circuit_t *circuit_establish_circuit(uint8_t purpose,
                                     const char *exit_digest);
circuit_t *circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
                                     int need_uptime, int need_capacity);
void circuit_n_conn_done(connection_t *or_conn, int status);
int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_extend(cell_t *cell, circuit_t *circ);
@@ -1049,7 +1055,9 @@ int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse);
int circuit_finish_handshake(circuit_t *circ, char *reply);
int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys);
int circuit_all_predicted_ports_handled(time_t now);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
                                        int *need_capacity);

void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);

/********************************* circuitlist.c ***********************/
@@ -1092,8 +1100,10 @@ void circuit_detach_stream(circuit_t *circ, connection_t *conn);
void circuit_about_to_close_connection(connection_t *conn);
void circuit_has_opened(circuit_t *circ);
void circuit_build_failed(circuit_t *circ);
circuit_t *circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname);
circuit_t *circuit_launch_by_identity(uint8_t purpose, const char *exit_digest);
circuit_t *circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
                                      int need_uptime, int need_capacity);
circuit_t *circuit_launch_by_identity(uint8_t purpose, const char *exit_digest,
                                      int need_uptime, int need_capacity);
void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_circuit(connection_t *conn);

@@ -1592,15 +1602,15 @@ int router_nickname_matches(routerinfo_t *router, const char *nickname);
/** How many seconds a router must be up before we'll use it for
 * reliability-critical node positions.
 */
#define ROUTER_REQUIRED_MIN_UPTIME 3600 /* an hour */
#define ROUTER_REQUIRED_MIN_UPTIME (24*3600) /* a day */
#define ROUTER_REQUIRED_MIN_BANDWIDTH 10000

int router_is_unreliable_router(routerinfo_t *router, int need_uptime, int need_bw);
int router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity);
routerinfo_t *routerlist_sl_choose_by_bandwidth(smartlist_t *sl);
routerinfo_t *router_choose_random_node(const char *preferred,
                                        const char *excluded,
                                        struct smartlist_t *excludedsmartlist,
                                        int preferuptime, int preferbandwidth,
                                        int need_uptime, int need_bandwidth,
                                        int allow_unverified, int strict);
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
routerinfo_t *router_get_by_nickname(const char *nickname);
@@ -1621,7 +1631,9 @@ int router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port,
#define ADDR_POLICY_ACCEPTED 0
#define ADDR_POLICY_REJECTED -1
#define ADDR_POLICY_UNKNOWN 1
int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port);
int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port,
                                          int need_uptime);

int router_exit_policy_rejects_all(routerinfo_t *router);
void running_routers_free(running_routers_t *rr);
void routerlist_update_from_runningrouters(routerlist_t *list,
Loading