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
This commit is contained in:
Roger Dingledine 2005-01-12 04:58:23 +00:00
parent 51f47d746e
commit 84c81e0783
7 changed files with 151 additions and 79 deletions

View File

@ -21,8 +21,9 @@ extern circuit_t *global_circuitlist;
static int static int
circuit_deliver_create_cell(circuit_t *circ, char *payload); circuit_deliver_create_cell(circuit_t *circ, char *payload);
static cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, static cpath_build_state_t *
const char *exit_digest); 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, static int onion_extend_cpath(crypt_path_t **head_ptr,
cpath_build_state_t *state, routerinfo_t **router_out); cpath_build_state_t *state, routerinfo_t **router_out);
static int count_acceptable_routers(smartlist_t *routers); 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 * Also launch a connection to the first OR in the chosen path, if
* it's not open already. * it's not open already.
*/ */
circuit_t *circuit_establish_circuit(uint8_t purpose, circuit_t *
const char *exit_digest) { circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
int need_uptime, int need_capacity) {
routerinfo_t *firsthop; routerinfo_t *firsthop;
connection_t *n_conn; connection_t *n_conn;
circuit_t *circ; circuit_t *circ;
circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */ circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
circ->state = CIRCUIT_STATE_OR_WAIT; 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; circ->purpose = purpose;
if (! circ->build_state) { 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 /** Return 1 if we already have circuits present or on the way for
* all anticipated ports. Return 0 if we should make more. * 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 int
circuit_all_predicted_ports_handled(time_t now) { circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int enough; int *need_capacity) {
int i, enough;
uint16_t *port;
smartlist_t *sl = circuit_get_unhandled_ports(now); smartlist_t *sl = circuit_get_unhandled_ports(now);
smartlist_t *LongLivedServices = get_options()->LongLivedPorts;
enough = (smartlist_len(sl) == 0); 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); smartlist_free(sl);
return enough; 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. * 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 *n_supported;
int i, j; int i, j;
@ -905,9 +921,13 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir)
// router->nickname, i); // router->nickname, i);
continue; /* skip routers that are known to be down */ 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 && if (!router->is_verified &&
(!(options->_AllowUnverified & ALLOW_UNVERIFIED_EXIT) || (!(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 */ /* if it's unverified, and either we don't want it or it's unsuitable */
n_supported[i] = -1; n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- unverified router.", // 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 * For client-side rendezvous circuits, choose a random node, weighted
* toward the preferences in 'options'. * 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; routerinfo_t *r;
or_options_t *options = get_options(); or_options_t *options = get_options();
switch (purpose) { switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL: 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: case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
r = router_choose_random_node(options->RendNodes, options->RendExcludeNodes, 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; return r;
} }
log_fn(LOG_WARN,"Bug: unhandled purpose %d", purpose); 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. * return it.
*/ */
static cpath_build_state_t * 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; routerlist_t *rl;
int r; int r;
@ -1071,6 +1095,8 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest)
return NULL; return NULL;
info = tor_malloc_zero(sizeof(cpath_build_state_t)); info = tor_malloc_zero(sizeof(cpath_build_state_t));
info->desired_path_len = r; info->desired_path_len = r;
info->need_uptime = need_uptime;
info->need_capacity = need_capacity;
if (exit_digest) { /* the circuit-builder pre-requested one */ if (exit_digest) { /* the circuit-builder pre-requested one */
memcpy(info->chosen_exit_digest, exit_digest, DIGEST_LEN); memcpy(info->chosen_exit_digest, exit_digest, DIGEST_LEN);
exit = router_get_by_digest(exit_digest); 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); log_fn(LOG_INFO,"Using requested exit node '%s'", info->chosen_exit_name);
} else { /* we have to decide one */ } 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) { if (!exit) {
log_fn(LOG_WARN,"failed to choose an exit server"); log_fn(LOG_WARN,"failed to choose an exit server");
tor_free(info); 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, 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); smartlist_free(excluded);
return choice; return choice;
} }
@ -1179,7 +1206,6 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state)
routerinfo_t *r, *choice; routerinfo_t *r, *choice;
smartlist_t *excluded = smartlist_create(); smartlist_t *excluded = smartlist_create();
or_options_t *options = get_options(); or_options_t *options = get_options();
char buf[16];
if ((r = router_get_by_digest(state->chosen_exit_digest))) { if ((r = router_get_by_digest(state->chosen_exit_digest))) {
smartlist_add(excluded, r); 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++) { for (i=0; i < smartlist_len(rl->routers); i++) {
r = smartlist_get(rl->routers, i); r = smartlist_get(rl->routers, i);
tor_snprintf(buf, sizeof(buf), "%d", r->or_port); if (!smartlist_string_num_isin(options->FirewallPorts, r->or_port))
if (!smartlist_string_isin(options->FirewallPorts, buf))
smartlist_add(excluded, r); smartlist_add(excluded, r);
} }
} }
choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes, 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); options->StrictEntryNodes);
smartlist_free(excluded); smartlist_free(excluded);
return choice; return choice;

View File

@ -78,6 +78,11 @@ static int circuit_is_acceptable(circuit_t *circ,
return 0; /* this circuit is screwed and doesn't know it yet */ 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 && if (conn->socks_request &&
conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
/* 0.0.8 servers have buggy resolve support. */ /* 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) { void circuit_build_needed_circs(time_t now) {
static long time_to_new_circuit = 0; static long time_to_new_circuit = 0;
circuit_t *circ; circuit_t *circ;
int need_uptime=0, need_capacity=1;
/* launch a new circ for any pending streams that need one */ /* launch a new circ for any pending streams that need one */
connection_ap_attach_pending(); connection_ap_attach_pending();
@ -332,7 +338,7 @@ void circuit_build_needed_circs(time_t now) {
circ && circ &&
circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) { circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) {
log_fn(LOG_INFO,"Creating a new testing circuit."); 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 /* if we know of a port that's been requested recently and no
* circuit is currently available that can handle it, start one * circuit is currently available that can handle it, start one
* for that too. */ * for that too. */
if (!circuit_all_predicted_ports_handled(now)) { if (!circuit_all_predicted_ports_handled(now, &need_uptime, &need_capacity)) {
circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL); circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL,
need_uptime, need_capacity);
} }
/* XXX count idle rendezvous circs and build more */ /* XXX count idle rendezvous circs and build more */
@ -637,7 +644,9 @@ static int did_circs_fail_last_period = 0;
* success. */ * success. */
#define MAX_CIRCUIT_FAILURES 5 #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) { if (!has_fetched_directory) {
log_fn(LOG_DEBUG,"Haven't fetched directory yet; canceling circuit launch."); 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 */ /* 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. */ /** 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; 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; 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 /** 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; circuit_t *circ;
uint32_t addr; uint32_t addr;
int is_resolve; int is_resolve;
int need_uptime;
tor_assert(conn); tor_assert(conn);
tor_assert(circp); tor_assert(circp);
@ -729,10 +743,14 @@ circuit_get_open_circ_or_launch(connection_t *conn,
return 0; return 0;
} }
need_uptime = smartlist_string_num_isin(get_options()->LongLivedPorts,
conn->socks_request->port);
/* Do we need to check exit policy? */ /* Do we need to check exit policy? */
if (!is_resolve && !connection_edge_is_rendezvous_stream(conn)) { if (!is_resolve && !connection_edge_is_rendezvous_stream(conn)) {
addr = client_dns_lookup_entry(conn->socks_request->address); 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.", log_fn(LOG_NOTICE,"No Tor server exists that allows exit to %s:%d. Rejecting.",
conn->socks_request->address, conn->socks_request->port); conn->socks_request->address, conn->socks_request->port);
return -1; return -1;
@ -783,7 +801,7 @@ circuit_get_open_circ_or_launch(connection_t *conn,
else else
new_circ_purpose = desired_circuit_purpose; 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); tor_free(exitname);
if (circ && if (circ &&

View File

@ -53,6 +53,7 @@ static config_abbrev_t config_abbrevs[] = {
PLURAL(EntryNode), PLURAL(EntryNode),
PLURAL(ExcludeNode), PLURAL(ExcludeNode),
PLURAL(FirewallPort), PLURAL(FirewallPort),
PLURAL(LongLivedPort),
PLURAL(HiddenServiceNode), PLURAL(HiddenServiceNode),
PLURAL(HiddenServiceExcludeNode), PLURAL(HiddenServiceExcludeNode),
PLURAL(RendNode), PLURAL(RendNode),
@ -149,6 +150,7 @@ static config_var_t config_vars[] = {
VAR("ORBindAddress", LINELIST, ORBindAddress, NULL), VAR("ORBindAddress", LINELIST, ORBindAddress, NULL),
VAR("OutboundBindAddress", STRING, OutboundBindAddress, NULL), VAR("OutboundBindAddress", STRING, OutboundBindAddress, NULL),
VAR("PidFile", STRING, PidFile, NULL), VAR("PidFile", STRING, PidFile, NULL),
VAR("LongLivedPorts", CSV, LongLivedPorts, "22,6667"),
VAR("PathlenCoinWeight", DOUBLE, PathlenCoinWeight, "0.3"), VAR("PathlenCoinWeight", DOUBLE, PathlenCoinWeight, "0.3"),
VAR("RedirectExit", LINELIST, RedirectExit, NULL), VAR("RedirectExit", LINELIST, RedirectExit, NULL),
OBSOLETE("RouterFile"), OBSOLETE("RouterFile"),
@ -1137,13 +1139,32 @@ config_dump_options(or_options_t *options, int minimal)
return result; 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 /** Return 0 if every setting in <b>options</b> is reasonable. Else
* warn and return -1. Should have no side effects, except for * warn and return -1. Should have no side effects, except for
* normalizing the contents of <b>options</b>. */ * normalizing the contents of <b>options</b>. */
static int static int
options_validate(or_options_t *options) options_validate(or_options_t *options)
{ {
int i;
int result = 0; int result = 0;
struct config_line_t *cl; struct config_line_t *cl;
addr_policy_t *addr_policy=NULL; addr_policy_t *addr_policy=NULL;
@ -1261,16 +1282,14 @@ options_validate(or_options_t *options)
options->_AccountingMaxKB = 0; options->_AccountingMaxKB = 0;
} }
if (options->FirewallPorts) { if (validate_ports_csv(options->FirewallPorts,
SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp, "FirewallPorts") < 0)
{ result = -1;
i = atoi(cp);
if (i < 1 || i > 65535) { if (validate_ports_csv(options->LongLivedPorts,
log(LOG_WARN, "Port '%s' out of range in FirewallPorts", cp); "LongLivedPorts") < 0)
result=-1; result = -1;
}
});
}
options->_AllowUnverified = 0; options->_AllowUnverified = 0;
if (options->AllowUnverifiedNodes) { if (options->AllowUnverifiedNodes) {
SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, { SMARTLIST_FOREACH(options->AllowUnverifiedNodes, const char *, cp, {
@ -1287,7 +1306,7 @@ options_validate(or_options_t *options)
else { else {
log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes", log(LOG_WARN, "Unrecognized value '%s' in AllowUnverifiedNodes",
cp); cp);
result=-1; result = -1;
} }
}); });
} }

View File

@ -116,7 +116,6 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
size_t payload_len) size_t payload_len)
{ {
smartlist_t *dirservers; smartlist_t *dirservers;
char buf[16];
router_get_trusted_dir_servers(&dirservers); router_get_trusted_dir_servers(&dirservers);
tor_assert(dirservers); tor_assert(dirservers);
@ -130,8 +129,7 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
* descriptor -- those use Tor. */ * descriptor -- those use Tor. */
if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR && if (get_options()->FascistFirewall && purpose == DIR_PURPOSE_UPLOAD_DIR &&
!get_options()->HttpProxy) { !get_options()->HttpProxy) {
tor_snprintf(buf,sizeof(buf),"%d",ds->dir_port); if (!smartlist_string_num_isin(get_options()->FirewallPorts, ds->dir_port))
if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
continue; continue;
} }
directory_initiate_command_trusted_dir(ds, purpose, NULL, 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 * 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>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 * <b>platform</b>, and whose identity key digest is <b>digest</b>. The

View File

@ -722,6 +722,10 @@ typedef struct {
char *chosen_exit_name; char *chosen_exit_name;
/** Identity of planned exit node. */ /** Identity of planned exit node. */
char chosen_exit_digest[DIGEST_LEN]; 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. */ /** The crypt_path_t to append after rendezvous: used for rendezvous. */
struct crypt_path_t *pending_final_cpath; struct crypt_path_t *pending_final_cpath;
/** How many times has building a circuit for this task failed? */ /** How many times has building a circuit for this task failed? */
@ -930,7 +934,9 @@ typedef struct {
* directory recommends. */ * directory recommends. */
int RunAsDaemon; /**< If true, run in the background. (Unix only) */ int RunAsDaemon; /**< If true, run in the background. (Unix only) */
int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */ 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 DirFetchPeriod; /**< How often do we fetch new directories? */
int DirPostPeriod; /**< How often do we post our server descriptor to the int DirPostPeriod; /**< How often do we post our server descriptor to the
* authoritative directory servers? */ * 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_log_path(int severity, circuit_t *circ);
void circuit_rep_hist_note_result(circuit_t *circ); void circuit_rep_hist_note_result(circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity); void circuit_dump_by_conn(connection_t *conn, int severity);
circuit_t *circuit_establish_circuit(uint8_t purpose, circuit_t *circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
const char *exit_digest); int need_uptime, int need_capacity);
void circuit_n_conn_done(connection_t *or_conn, int status); void circuit_n_conn_done(connection_t *or_conn, int status);
int circuit_send_next_onion_skin(circuit_t *circ); int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_extend(cell_t *cell, 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_finish_handshake(circuit_t *circ, char *reply);
int circuit_truncated(circuit_t *circ, crypt_path_t *layer); int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys); 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); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
/********************************* circuitlist.c ***********************/ /********************************* 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_about_to_close_connection(connection_t *conn);
void circuit_has_opened(circuit_t *circ); void circuit_has_opened(circuit_t *circ);
void circuit_build_failed(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_nickname(uint8_t purpose, const char *exit_nickname,
circuit_t *circuit_launch_by_identity(uint8_t purpose, const char *exit_digest); 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); void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_circuit(connection_t *conn); 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 /** How many seconds a router must be up before we'll use it for
* reliability-critical node positions. * 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 #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 *routerlist_sl_choose_by_bandwidth(smartlist_t *sl);
routerinfo_t *router_choose_random_node(const char *preferred, routerinfo_t *router_choose_random_node(const char *preferred,
const char *excluded, const char *excluded,
struct smartlist_t *excludedsmartlist, struct smartlist_t *excludedsmartlist,
int preferuptime, int preferbandwidth, int need_uptime, int need_bandwidth,
int allow_unverified, int strict); int allow_unverified, int strict);
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
routerinfo_t *router_get_by_nickname(const char *nickname); 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_ACCEPTED 0
#define ADDR_POLICY_REJECTED -1 #define ADDR_POLICY_REJECTED -1
#define ADDR_POLICY_UNKNOWN 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); int router_exit_policy_rejects_all(routerinfo_t *router);
void running_routers_free(running_routers_t *rr); void running_routers_free(running_routers_t *rr);
void routerlist_update_from_runningrouters(routerlist_t *list, void routerlist_update_from_runningrouters(routerlist_t *list,

View File

@ -459,7 +459,7 @@ rend_service_introduce(circuit_t *circuit, const char *request, size_t request_l
/* Launch a circuit to alice's chosen rendezvous point. /* Launch a circuit to alice's chosen rendezvous point.
*/ */
for (i=0;i<MAX_REND_FAILURES;i++) { for (i=0;i<MAX_REND_FAILURES;i++) {
launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND, rp_nickname); launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND, rp_nickname, 0, 1);
if (launched) if (launched)
break; break;
} }
@ -524,7 +524,7 @@ rend_service_relaunch_rendezvous(circuit_t *oldcirc)
oldstate->chosen_exit_name); oldstate->chosen_exit_name);
newcirc = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND, newcirc = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_CONNECT_REND,
oldstate->chosen_exit_name); oldstate->chosen_exit_name, 0, 1);
if (!newcirc) { if (!newcirc) {
log_fn(LOG_WARN,"Couldn't relaunch rendezvous circuit to %s", log_fn(LOG_WARN,"Couldn't relaunch rendezvous circuit to %s",
oldstate->chosen_exit_name); oldstate->chosen_exit_name);
@ -553,7 +553,7 @@ rend_service_launch_establish_intro(rend_service_t *service, const char *nicknam
nickname, service->service_id); nickname, service->service_id);
++service->n_intro_circuits_launched; ++service->n_intro_circuits_launched;
launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, nickname); launched = circuit_launch_by_nickname(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, nickname, 1, 0);
if (!launched) { if (!launched) {
log_fn(LOG_WARN, "Can't launch circuit to establish introduction at '%s'", log_fn(LOG_WARN, "Can't launch circuit to establish introduction at '%s'",
nickname); nickname);

View File

@ -166,7 +166,6 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall,
int i; int i;
routerinfo_t *router; routerinfo_t *router;
smartlist_t *sl; smartlist_t *sl;
char buf[16];
if (!routerlist) if (!routerlist)
return NULL; return NULL;
@ -183,8 +182,7 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall,
if (requireothers && router_is_me(router)) if (requireothers && router_is_me(router))
continue; continue;
if (fascistfirewall) { if (fascistfirewall) {
tor_snprintf(buf,sizeof(buf),"%d",router->dir_port); if (!smartlist_string_num_isin(get_options()->FirewallPorts, router->dir_port))
if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
continue; continue;
} }
/* before 0.0.9rc5-cvs, only trusted dirservers served status info. */ /* before 0.0.9rc5-cvs, only trusted dirservers served status info. */
@ -205,7 +203,6 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
{ {
smartlist_t *sl; smartlist_t *sl;
routerinfo_t *me; routerinfo_t *me;
char buf[16];
trusted_dir_server_t *ds; trusted_dir_server_t *ds;
sl = smartlist_create(); sl = smartlist_create();
me = router_get_my_routerinfo(); me = router_get_my_routerinfo();
@ -223,8 +220,7 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
!memcmp(me->identity_digest, d->digest, DIGEST_LEN)) !memcmp(me->identity_digest, d->digest, DIGEST_LEN))
continue; continue;
if (fascistfirewall) { if (fascistfirewall) {
tor_snprintf(buf,sizeof(buf),"%d",d->dir_port); if (!smartlist_string_num_isin(get_options()->FirewallPorts, d->dir_port))
if (!smartlist_string_isin(get_options()->FirewallPorts, buf))
continue; continue;
} }
smartlist_add(sl, d); smartlist_add(sl, d);
@ -360,7 +356,7 @@ router_nickname_is_in_list(routerinfo_t *router, const char *list)
*/ */
static void static void
router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified, router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
int preferuptime, int preferbandwidth) int need_uptime, int need_capacity)
{ {
routerinfo_t *router; routerinfo_t *router;
int i; int i;
@ -373,7 +369,7 @@ router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
if (router->is_running && if (router->is_running &&
(router->is_verified || (router->is_verified ||
(allow_unverified && (allow_unverified &&
!router_is_unreliable_router(router, preferuptime, preferbandwidth)))) { !router_is_unreliable(router, need_uptime, need_capacity)))) {
/* If it's running, and either it's verified or we're ok picking /* If it's running, and either it's verified or we're ok picking
* unverified routers and this one is suitable. * unverified routers and this one is suitable.
*/ */
@ -399,11 +395,11 @@ routerlist_find_my_routerinfo(void) {
} }
int int
router_is_unreliable_router(routerinfo_t *router, int need_uptime, int need_bw) router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity)
{ {
if (need_uptime && router->uptime < ROUTER_REQUIRED_MIN_UPTIME) if (need_uptime && router->uptime < ROUTER_REQUIRED_MIN_UPTIME)
return 1; return 1;
if (need_bw && router->bandwidthcapacity < ROUTER_REQUIRED_MIN_BANDWIDTH) if (need_capacity && router->bandwidthcapacity < ROUTER_REQUIRED_MIN_BANDWIDTH)
return 1; return 1;
return 0; return 0;
} }
@ -416,7 +412,7 @@ routerlist_sl_remove_unreliable_routers(smartlist_t *sl)
for (i = 0; i < smartlist_len(sl); ++i) { for (i = 0; i < smartlist_len(sl); ++i) {
router = smartlist_get(sl, i); router = smartlist_get(sl, i);
if (router_is_unreliable_router(router, 1, 0)) { if (router_is_unreliable(router, 1, 0)) {
log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.", log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.",
router->nickname); router->nickname);
smartlist_del(sl, i--); smartlist_del(sl, i--);
@ -480,7 +476,7 @@ routerlist_sl_choose_by_bandwidth(smartlist_t *sl)
routerinfo_t *router_choose_random_node(const char *preferred, routerinfo_t *router_choose_random_node(const char *preferred,
const char *excluded, const char *excluded,
smartlist_t *excludedsmartlist, smartlist_t *excludedsmartlist,
int preferuptime, int preferbandwidth, int need_uptime, int need_capacity,
int allow_unverified, int strict) int allow_unverified, int strict)
{ {
smartlist_t *sl, *excludednodes; smartlist_t *sl, *excludednodes;
@ -495,9 +491,9 @@ routerinfo_t *router_choose_random_node(const char *preferred,
smartlist_subtract(sl,excludednodes); smartlist_subtract(sl,excludednodes);
if (excludedsmartlist) if (excludedsmartlist)
smartlist_subtract(sl,excludedsmartlist); smartlist_subtract(sl,excludedsmartlist);
if (preferuptime) if (need_uptime)
routerlist_sl_remove_unreliable_routers(sl); routerlist_sl_remove_unreliable_routers(sl);
if (preferbandwidth) if (need_capacity)
choice = routerlist_sl_choose_by_bandwidth(sl); choice = routerlist_sl_choose_by_bandwidth(sl);
else else
choice = smartlist_choose(sl); choice = smartlist_choose(sl);
@ -505,13 +501,13 @@ routerinfo_t *router_choose_random_node(const char *preferred,
if (!choice && !strict) { if (!choice && !strict) {
sl = smartlist_create(); sl = smartlist_create();
router_add_running_routers_to_smartlist(sl, allow_unverified, router_add_running_routers_to_smartlist(sl, allow_unverified,
preferuptime, preferbandwidth); need_uptime, need_capacity);
smartlist_subtract(sl,excludednodes); smartlist_subtract(sl,excludednodes);
if (excludedsmartlist) if (excludedsmartlist)
smartlist_subtract(sl,excludedsmartlist); smartlist_subtract(sl,excludedsmartlist);
if (preferuptime) if (need_uptime)
routerlist_sl_remove_unreliable_routers(sl); routerlist_sl_remove_unreliable_routers(sl);
if (preferbandwidth) if (need_capacity)
choice = routerlist_sl_choose_by_bandwidth(sl); choice = routerlist_sl_choose_by_bandwidth(sl);
else else
choice = smartlist_choose(sl); choice = smartlist_choose(sl);
@ -1007,16 +1003,19 @@ int router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port,
return maybe_reject ? ADDR_POLICY_UNKNOWN : ADDR_POLICY_ACCEPTED; return maybe_reject ? ADDR_POLICY_UNKNOWN : ADDR_POLICY_ACCEPTED;
} }
/** Return 1 if all running routers will reject addr:port, return 0 if /** Return 1 if all running sufficiently-stable routers will reject
* any might accept it. */ * addr:port, return 0 if any might accept it. */
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 i; int i;
routerinfo_t *router; routerinfo_t *router;
if (!routerlist) return 1; if (!routerlist) return 1;
for (i=0;i<smartlist_len(routerlist->routers);i++) { for (i=0;i<smartlist_len(routerlist->routers);i++) {
router = smartlist_get(routerlist->routers, i); router = smartlist_get(routerlist->routers, i);
if (router->is_running && router_compare_addr_to_addr_policy( if (router->is_running &&
!router_is_unreliable(router, need_uptime, 0) &&
router_compare_addr_to_addr_policy(
addr, port, router->exit_policy) != ADDR_POLICY_REJECTED) addr, port, router->exit_policy) != ADDR_POLICY_REJECTED)
return 0; /* this one could be ok. good enough. */ return 0; /* this one could be ok. good enough. */
} }