mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Initial, somewhat dodgy implementation of helper nodes. It has too many XXXXs, it logs too verbosely, and it doesnt do persistence.
svn:r4633
This commit is contained in:
parent
5b4e11fa5d
commit
c3a62c1739
@ -17,6 +17,15 @@ const char circuitbuild_c_id[] = "$Id$";
|
||||
/** A global list of all circuits at this hop. */
|
||||
extern circuit_t *global_circuitlist;
|
||||
|
||||
typedef struct {
|
||||
char nickname[MAX_NICKNAME_LEN+1];
|
||||
char identity[DIGEST_LEN];
|
||||
time_t down_since;
|
||||
time_t unlisted_since;
|
||||
} helper_node_t;
|
||||
|
||||
static smartlist_t *helper_nodes;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
static int circuit_deliver_create_cell(circuit_t *circ,
|
||||
@ -27,6 +36,10 @@ static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr,
|
||||
cpath_build_state_t *state);
|
||||
static int count_acceptable_routers(smartlist_t *routers);
|
||||
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
|
||||
static void pick_helper_nodes(void);
|
||||
static routerinfo_t *choose_random_helper(void);
|
||||
static void clear_helper_nodes(void);
|
||||
static void remove_dead_helpers(void);
|
||||
|
||||
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
|
||||
* and with the high bit specified by circ_id_type (see
|
||||
@ -1368,7 +1381,10 @@ choose_good_middle_server(uint8_t purpose,
|
||||
return choice;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
/** DOCDOC
|
||||
*
|
||||
* state == null means 'pick a helper.'
|
||||
*/
|
||||
static routerinfo_t *
|
||||
choose_good_entry_server(cpath_build_state_t *state)
|
||||
{
|
||||
@ -1376,7 +1392,11 @@ choose_good_entry_server(cpath_build_state_t *state)
|
||||
smartlist_t *excluded = smartlist_create();
|
||||
or_options_t *options = get_options();
|
||||
|
||||
if ((r = build_state_get_exit_router(state))) {
|
||||
if (state && options->UseHelperNodes) {
|
||||
return choose_random_helper();
|
||||
}
|
||||
|
||||
if (state && (r = build_state_get_exit_router(state))) {
|
||||
smartlist_add(excluded, r);
|
||||
routerlist_add_family(excluded, r);
|
||||
}
|
||||
@ -1400,7 +1420,8 @@ choose_good_entry_server(cpath_build_state_t *state)
|
||||
}
|
||||
}
|
||||
choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes,
|
||||
excluded, state->need_uptime, state->need_capacity,
|
||||
excluded, state ? state->need_uptime : 1,
|
||||
state ? state->need_capacity : 0,
|
||||
options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY,
|
||||
options->StrictEntryNodes);
|
||||
smartlist_free(excluded);
|
||||
@ -1569,3 +1590,203 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
|
||||
return state->chosen_exit->nickname;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static int
|
||||
n_live_helpers(void)
|
||||
{
|
||||
int n = 0;
|
||||
SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
|
||||
if (! helper->down_since && ! helper->unlisted_since)
|
||||
++n;);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static void
|
||||
pick_helper_nodes(void)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
|
||||
if (! options->UseHelperNodes)
|
||||
return;
|
||||
|
||||
if (helper_nodes == NULL)
|
||||
helper_nodes = smartlist_create();
|
||||
|
||||
while (smartlist_len(helper_nodes) < options->NumHelperNodes) {
|
||||
routerinfo_t *entry = choose_good_entry_server(NULL);
|
||||
/* XXXX deal with duplicate entries. */
|
||||
helper_node_t *helper = tor_malloc_zero(sizeof(helper_node_t));
|
||||
/* XXXX Downgrade this to info before release. */
|
||||
log_fn(LOG_NOTICE, "Chose '%s' as helper node.", entry->nickname);
|
||||
strlcpy(helper->nickname, entry->nickname, sizeof(helper->nickname));
|
||||
memcpy(helper->identity, entry->identity_digest, DIGEST_LEN);
|
||||
smartlist_add(helper_nodes, helper);
|
||||
}
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static void
|
||||
clear_helper_nodes(void)
|
||||
{
|
||||
SMARTLIST_FOREACH(helper_nodes, helper_node_t *, h, tor_free(h));
|
||||
smartlist_clear(helper_nodes);
|
||||
}
|
||||
|
||||
#define HELPER_ALLOW_DOWNTIME 48*60*60
|
||||
#define HELPER_ALLOW_UNLISTED 48*60*60
|
||||
|
||||
/** DOCDOC */
|
||||
static void
|
||||
remove_dead_helpers(void)
|
||||
{
|
||||
char dbuf[HEX_DIGEST_LEN+1];
|
||||
char tbuf[ISO_TIME_LEN+1];
|
||||
time_t now = time(NULL);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < smartlist_len(helper_nodes); ) {
|
||||
helper_node_t *helper = smartlist_get(helper_nodes, i);
|
||||
char *why = NULL;
|
||||
time_t since = 0;
|
||||
if (helper->unlisted_since + HELPER_ALLOW_UNLISTED > now) {
|
||||
why = "unlisted";
|
||||
since = helper->unlisted_since;
|
||||
} else if (helper->down_since + HELPER_ALLOW_DOWNTIME > now) {
|
||||
why = "down";
|
||||
since = helper->unlisted_since;
|
||||
}
|
||||
if (why) {
|
||||
base16_encode(dbuf, sizeof(dbuf), helper->identity, DIGEST_LEN);
|
||||
format_local_iso_time(tbuf, since);
|
||||
log_fn(LOG_WARN, "Helper node '%s' (%s) has been %s since %s; removing.",
|
||||
helper->nickname, dbuf, why, tbuf);
|
||||
tor_free(helper);
|
||||
smartlist_del(helper_nodes, i);
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
helper_nodes_set_status_from_directory(void)
|
||||
{
|
||||
/* Don't call this on startup; only on a fresh download. Otherwise we'll
|
||||
* think that things are unlisted. */
|
||||
routerlist_t *routers;
|
||||
time_t now;
|
||||
int changed = 0;
|
||||
if (! helper_nodes)
|
||||
return;
|
||||
|
||||
router_get_routerlist(&routers);
|
||||
if (! routers)
|
||||
return;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
/*XXXX Most of these warns should be non-warns. */
|
||||
|
||||
SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
|
||||
{
|
||||
routerinfo_t *r = router_get_by_digest(helper->identity);
|
||||
if (! r) {
|
||||
if (! helper->unlisted_since) {
|
||||
/* Watch out for skew here. XXXX */
|
||||
helper->unlisted_since = routers->published_on;
|
||||
++changed;
|
||||
log_fn(LOG_WARN,"Helper node '%s' is not published in latest directory",
|
||||
helper->nickname);
|
||||
}
|
||||
} else {
|
||||
if (helper->unlisted_since) {
|
||||
log_fn(LOG_WARN,"Helper node '%s' is listed again in latest directory",
|
||||
helper->nickname);
|
||||
++changed;
|
||||
}
|
||||
helper->unlisted_since = 0;
|
||||
if (! r->is_running) {
|
||||
if (! helper->down_since) {
|
||||
helper->down_since = now;
|
||||
log_fn(LOG_WARN, "Helper node '%s' is now down.", helper->nickname);
|
||||
++changed;
|
||||
}
|
||||
} else {
|
||||
if (helper->down_since) {
|
||||
log_fn(LOG_WARN,"Helper node '%s' is up in latest directory",
|
||||
helper->nickname);
|
||||
++changed;
|
||||
}
|
||||
helper->down_since = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (changed)
|
||||
log_fn(LOG_WARN, " (%d/%d helpers are usable)",
|
||||
n_live_helpers(), smartlist_len(helper_nodes));
|
||||
|
||||
remove_dead_helpers();
|
||||
pick_helper_nodes();
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
helper_node_set_status(const char *digest, int succeeded)
|
||||
{
|
||||
if (! helper_nodes)
|
||||
return;
|
||||
|
||||
SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
|
||||
{
|
||||
if (!memcmp(helper->identity, digest, DIGEST_LEN)) {
|
||||
if (succeeded) {
|
||||
if (helper->down_since) {
|
||||
/*XXXX shouldn't warn. */
|
||||
log_fn(LOG_WARN,
|
||||
"Connection to formerly down helper node '%s' succeeeded. "
|
||||
"%d/%d helpers usable.", helper->nickname,
|
||||
n_live_helpers(), smartlist_len(helper_nodes));
|
||||
}
|
||||
helper->down_since = 0;
|
||||
} else if (!helper->down_since) {
|
||||
helper->down_since = time(NULL);
|
||||
log_fn(LOG_WARN,
|
||||
"Connection to helper node '%s' failed. %d/%d helpers usable.",
|
||||
helper->nickname, n_live_helpers(), smartlist_len(helper_nodes));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static routerinfo_t *
|
||||
choose_random_helper(void)
|
||||
{
|
||||
smartlist_t *live_helpers = smartlist_create();
|
||||
routerinfo_t *r;
|
||||
|
||||
if (! helper_nodes)
|
||||
pick_helper_nodes();
|
||||
|
||||
retry:
|
||||
SMARTLIST_FOREACH(helper_nodes, helper_node_t *, helper,
|
||||
if (! helper->down_since && ! helper->unlisted_since) {
|
||||
if ((r = router_get_by_digest(helper->identity)))
|
||||
smartlist_add(live_helpers, r);
|
||||
});
|
||||
|
||||
if (! smartlist_len(live_helpers)) {
|
||||
/* XXXX Is this right? What if network is down? */
|
||||
log_fn(LOG_WARN, "No functional helper nodes found; picking a new set.");
|
||||
clear_helper_nodes();
|
||||
pick_helper_nodes();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
r = smartlist_choose(live_helpers);
|
||||
smartlist_free(live_helpers);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -307,6 +307,9 @@ options_act(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options->EntryNodes && strlen(options->EntryNodes))
|
||||
options->UseHelperNodes = 0;
|
||||
|
||||
/* Setuid/setgid as appropriate */
|
||||
if (options->User || options->Group) {
|
||||
if (switch_id(options->User, options->Group) != 0) {
|
||||
|
@ -309,6 +309,7 @@ connection_about_to_close_connection(connection_t *conn)
|
||||
if (conn->state != OR_CONN_STATE_OPEN) {
|
||||
if (connection_or_nonopen_was_started_here(conn)) {
|
||||
rep_hist_note_connect_failed(conn->identity_digest, time(NULL));
|
||||
helper_node_set_status(conn->identity_digest, 0);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
|
||||
}
|
||||
} else if (conn->hold_open_until_flushed) {
|
||||
|
@ -358,6 +358,7 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
|
||||
case -1:
|
||||
if (!options->HttpsProxy)
|
||||
router_mark_as_down(conn->identity_digest);
|
||||
helper_node_set_status(conn->identity_digest, 0);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
|
||||
connection_free(conn);
|
||||
return NULL;
|
||||
@ -527,6 +528,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
|
||||
log_fn(severity,
|
||||
"Identity key not as expected for router at %s:%d: wanted %s but got %s",
|
||||
conn->address, conn->port, conn->nickname+1, d);
|
||||
helper_node_set_status(conn->identity_digest, 0);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
|
||||
as_advertised = 0;
|
||||
}
|
||||
@ -535,6 +537,7 @@ connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd)
|
||||
log_fn(severity,
|
||||
"Other side (%s:%d) is '%s', but we tried to connect to '%s'",
|
||||
conn->address, conn->port, nickname, conn->nickname);
|
||||
helper_node_set_status(conn->identity_digest, 0);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED);
|
||||
as_advertised = 0;
|
||||
}
|
||||
@ -592,6 +595,7 @@ connection_tls_finish_handshake(connection_t *conn)
|
||||
connection_watch_events(conn, EV_READ);
|
||||
circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
|
||||
rep_hist_note_connect_succeeded(conn->identity_digest, time(NULL));
|
||||
helper_node_set_status(conn->identity_digest, 1);
|
||||
control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED);
|
||||
return 0;
|
||||
}
|
||||
|
@ -758,6 +758,7 @@ connection_dir_client_reached_eof(connection_t *conn)
|
||||
log_fn(LOG_INFO,"updated routers.");
|
||||
}
|
||||
/* do things we've been waiting to do */
|
||||
helper_nodes_set_status_from_directory();
|
||||
directory_has_arrived(time(NULL), conn->identity_digest);
|
||||
}
|
||||
|
||||
@ -780,6 +781,7 @@ connection_dir_client_reached_eof(connection_t *conn)
|
||||
router_get_routerlist(&rl);
|
||||
if (rl) {
|
||||
routerlist_set_runningrouters(rl,rrs);
|
||||
helper_nodes_set_status_from_directory();
|
||||
} else {
|
||||
running_routers_free(rrs);
|
||||
}
|
||||
|
@ -1252,6 +1252,9 @@ void extend_info_free(extend_info_t *info);
|
||||
routerinfo_t *build_state_get_exit_router(cpath_build_state_t *state);
|
||||
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
||||
|
||||
void helper_node_set_status(const char *digest, int succeeded);
|
||||
void helper_nodes_set_status_from_directory(void);
|
||||
|
||||
/********************************* circuitlist.c ***********************/
|
||||
|
||||
circuit_t * _circuit_get_global_list(void);
|
||||
|
Loading…
Reference in New Issue
Block a user