From 8da24c99bdb90b04a05d5bccf5bcff1218174b75 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 15 Nov 2016 07:49:06 -0500 Subject: Split bridge functions into a new module. This patch is just: * Code movement * Adding headers here and there as needed * Adding a bridges_free_all() with a call to it. It breaks compilation, since the bridge code needed to make exactly 2 calls into entrynodes.c internals. I'll fix those in the next commit. --- src/or/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/or/main.c') diff --git a/src/or/main.c b/src/or/main.c index c10f62724a..a508003f97 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -50,6 +50,7 @@ #include "or.h" #include "addressmap.h" #include "backtrace.h" +#include "bridges.h" #include "buffers.h" #include "channel.h" #include "channeltls.h" @@ -3114,6 +3115,7 @@ tor_free_all(int postfork) control_free_all(); sandbox_free_getaddrinfo_cache(); protover_free_all(); + bridges_free_all(); if (!postfork) { config_free_all(); or_state_free_all(); -- cgit v1.2.3-54-g00ecf From dbbaa515183e250e20c40fa7b4c00df9487058fa Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 21 Nov 2016 17:23:25 -0500 Subject: Use the new guard notification/selection APIs throughout Tor This patch doesn't cover every case; omitted cases are marked with "XXXX prop271", as usual. It leaves both the old interface and the new interface for guard status notification, since they don't actually work in the same way: the new API wants to be told when a circuit has failed or succeeded, whereas the old API wants to know when a channel has failed or succeeded. I ran into some trouble with directory guard stuff, since when we pick the directory guard, we don't actually have a circuit to associate it with. I solved that by allowing guard states to be associated with directory connections, not just circuits. --- src/or/bridges.c | 2 ++ src/or/channel.c | 1 + src/or/circuitbuild.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++---- src/or/circuitbuild.h | 6 +++- src/or/circuitlist.c | 42 +++++++++++++++++++++++++++- src/or/circuitlist.h | 2 ++ src/or/circuituse.c | 2 ++ src/or/connection.c | 1 + src/or/connection_or.c | 6 ++++ src/or/directory.c | 74 +++++++++++++++++++++++++++++++++++++++---------- src/or/directory.h | 6 ++-- src/or/entrynodes.c | 60 ++++++++++++++++++++++++++++++++++++---- src/or/entrynodes.h | 2 +- src/or/main.c | 5 +++- src/or/or.h | 4 +++ src/or/rendclient.c | 2 +- src/or/rendservice.c | 2 +- src/or/routerlist.c | 4 +-- src/test/test_dir.c | 8 ++++-- 19 files changed, 268 insertions(+), 36 deletions(-) (limited to 'src/or/main.c') diff --git a/src/or/bridges.c b/src/or/bridges.c index 508c77fc9e..2170cc668a 100644 --- a/src/or/bridges.c +++ b/src/or/bridges.c @@ -724,6 +724,7 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) from_cache ? "cached" : "fresh", router_describe(ri)); /* set entry->made_contact so if it goes down we don't drop it from * our entry node list */ + // XXXX prop271 use new interface here when we hit bridges? entry_guard_register_connect_status(ri->cache_info.identity_digest, 1, 0, now); if (first) { @@ -743,6 +744,7 @@ int any_bridge_descriptors_known(void) { tor_assert(get_options()->UseBridges); + // XXXX prop271 this needs to get fixed. -- bridges return choose_random_entry(NULL) != NULL; } diff --git a/src/or/channel.c b/src/or/channel.c index af5810788c..1e3e99c51d 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -2538,6 +2538,7 @@ channel_do_open_actions(channel_t *chan) if (started_here) { circuit_build_times_network_is_live(get_circuit_build_times_mutable()); rep_hist_note_connect_succeeded(chan->identity_digest, now); + // XXXX prop271 this call is no longer useful with the new algorithm. if (entry_guard_register_connect_status( chan->identity_digest, 1, 0, now) < 0) { /* Close any circuits pending on this channel. We leave it in state diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index a33c2ca654..2f4ce7a727 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -964,7 +964,35 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) memset(&ec, 0, sizeof(ec)); if (!hop) { /* done building the circuit. whew. */ - circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); + int r; + if (! circ->guard_state) { + if (circuit_get_cpath_len(circ) != 1) { + log_warn(LD_BUG, "%d-hop circuit %p with purpose %d has no " + "guard state", + circuit_get_cpath_len(circ), circ, circ->base_.purpose); + } + r = 1; + } else { + r = entry_guard_succeeded(get_guard_selection_info(), + &circ->guard_state); + } + const int is_usable_for_streams = (r == 1); + if (r == 1) { + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); + } else if (r == 0) { + // XXXX prop271 we might want to probe for whether this + // XXXX one is ready even before the next second rolls over. + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_GUARD_WAIT); + } else { + return - END_CIRC_REASON_INTERNAL; + } + + /* XXXX prop271 -- the rest of this branch needs careful thought! + * Some of the things here need to happen when a circuit becomes + * mechanically open; some need to happen when it is actually usable. + * I think I got them right, but more checking would be wise. -NM + */ + if (circuit_timeout_want_to_count_circ(circ)) { struct timeval end; long timediff; @@ -1006,7 +1034,8 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) pathbias_count_build_success(circ); circuit_rep_hist_note_result(circ); - circuit_has_opened(circ); /* do other actions as necessary */ + if (is_usable_for_streams) + circuit_has_opened(circ); /* do other actions as necessary */ if (!have_completed_a_circuit() && !circ->build_state->onehop_tunnel) { const or_options_t *options = get_options(); @@ -2206,9 +2235,20 @@ choose_good_middle_server(uint8_t purpose, * * If state is NULL, we're choosing a router to serve as an entry * guard, not for any particular circuit. + * + * Set *guard_state_out to information about the guard that + * we're selecting, which we'll use later to remember whether the + * guard worked or not. + * + * XXXX prop271 this function is used in four ways: picking out guards for + * the old (pre-prop271) guard algorithm; picking out guards for circuits; + * picking out guards for testing circuits on non-bridgees; + * picking out entries when entry guards are disabled. These options + * should be disentangled. */ const node_t * -choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) +choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state, + circuit_guard_state_t **guard_state_out) { const node_t *choice; smartlist_t *excluded; @@ -2223,7 +2263,8 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) (purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) { /* This request is for an entry server to use for a regular circuit, * and we use entry guard nodes. Just return one of the guard nodes. */ - return choose_random_entry(state); + tor_assert(guard_state_out); + return guards_choose_guard(state, guard_state_out); } excluded = smartlist_new(); @@ -2306,7 +2347,8 @@ onion_extend_cpath(origin_circuit_t *circ) if (cur_len == state->desired_path_len - 1) { /* Picking last node */ info = extend_info_dup(state->chosen_exit); } else if (cur_len == 0) { /* picking first node */ - const node_t *r = choose_good_entry_server(purpose, state); + const node_t *r = choose_good_entry_server(purpose, state, + &circ->guard_state); if (r) { /* If we're a client, use the preferred address rather than the primary address, for potentially connecting to an IPv6 OR @@ -2574,3 +2616,26 @@ extend_info_has_preferred_onion_key(const extend_info_t* ei) return extend_info_supports_ntor(ei); } +/** Find the circuits that are waiting to find out whether their guards are + * usable, and if any are ready to become usable, mark them open and try + * attaching streams as appropriate. */ +void +circuit_upgrade_circuits_from_guard_wait(void) +{ + smartlist_t *to_upgrade = + circuit_find_circuits_to_upgrade_from_guard_wait(); + + if (to_upgrade == NULL) + return; + + log_info(LD_GUARD, "Upgrading %d circuits from 'waiting for better guard' " + "to 'open'.", smartlist_len(to_upgrade)); + + SMARTLIST_FOREACH_BEGIN(to_upgrade, origin_circuit_t *, circ) { + circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); + circuit_has_opened(circ); + } SMARTLIST_FOREACH_END(circ); + + smartlist_free(to_upgrade); +} + diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 56f66a19d6..2c83a16550 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -64,8 +64,12 @@ int extend_info_has_preferred_onion_key(const extend_info_t* ei); const node_t *build_state_get_exit_node(cpath_build_state_t *state); const char *build_state_get_exit_nickname(cpath_build_state_t *state); +struct circuit_guard_state_t; + const node_t *choose_good_entry_server(uint8_t purpose, - cpath_build_state_t *state); + cpath_build_state_t *state, + struct circuit_guard_state_t **guard_state_out); +void circuit_upgrade_circuits_from_guard_wait(void); #ifdef CIRCUITBUILD_PRIVATE STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index c274534759..2a03f8a0d9 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -92,6 +92,10 @@ static smartlist_t *global_origin_circuit_list = NULL; /** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */ static smartlist_t *circuits_pending_chans = NULL; +/** List of all the (origin) circuits whose state is + * CIRCUIT_STATE_GUARD_WAIT. */ +static smartlist_t *circuits_pending_other_guards = NULL; + /** A list of all the circuits that have been marked with * circuit_mark_for_close and which are waiting for circuit_about_to_free. */ static smartlist_t *circuits_pending_close = NULL; @@ -433,8 +437,10 @@ circuit_set_state(circuit_t *circ, uint8_t state) tor_assert(circ); if (state == circ->state) return; - if (!circuits_pending_chans) + if (PREDICT_UNLIKELY(!circuits_pending_chans)) circuits_pending_chans = smartlist_new(); + if (PREDICT_UNLIKELY(!circuits_pending_other_guards)) + circuits_pending_other_guards = smartlist_new(); if (circ->state == CIRCUIT_STATE_CHAN_WAIT) { /* remove from waiting-circuit list. */ smartlist_remove(circuits_pending_chans, circ); @@ -1022,6 +1028,9 @@ circuit_free_all(void) smartlist_free(circuits_pending_close); circuits_pending_close = NULL; + smartlist_free(circuits_pending_other_guards); + circuits_pending_other_guards = NULL; + { chan_circid_circuit_map_t **elt, **next, *c; for (elt = HT_START(chan_circid_map, &chan_circid_map); @@ -1721,6 +1730,37 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, return best; } +/** + * Check whether any of the origin circuits that are waiting to see if + * their guard is good enough to use can be upgraded to "ready". If so, + * return a new smartlist containing them. Otherwise return NULL. + */ +smartlist_t * +circuit_find_circuits_to_upgrade_from_guard_wait(void) +{ + /* Only if some circuit is actually waiting on an upgrade should we + * run the algorithm. */ + if (! circuits_pending_other_guards || + smartlist_len(circuits_pending_other_guards)==0) + return NULL; + /* Only if we have some origin circuiuts should we run the algorithm. + */ + if (!global_origin_circuit_list) + return NULL; + + /* Okay; we can pass our circuit list to entrynodes.c.*/ + smartlist_t *result = smartlist_new(); + int r = entry_guards_upgrade_waiting_circuits(get_guard_selection_info(), + global_origin_circuit_list, + result); + if (r && smartlist_len(result)) { + return result; + } else { + smartlist_free(result); + return NULL; + } +} + /** Return the number of hops in circuit's path. If circ has no entries, * or is NULL, returns 0. */ int diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 989c02afd5..73039cc06e 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -77,6 +77,8 @@ void channel_note_destroy_pending(channel_t *chan, circid_t id); MOCK_DECL(void, channel_note_destroy_not_pending, (channel_t *chan, circid_t id)); +smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void); + #ifdef CIRCUITLIST_PRIVATE STATIC void circuit_free(circuit_t *circ); STATIC size_t n_cells_in_circ_queues(const circuit_t *c); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 2f972d1a28..d2a7f20aa2 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1633,6 +1633,8 @@ circuit_build_failed(origin_circuit_t *circ) "Our circuit died before the first hop with no connection"); } if (n_chan_id && !already_marked) { + entry_guard_failed(get_guard_selection_info(), &circ->guard_state); + /* XXXX prop271 -- old API */ entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL)); /* if there are any one-hop streams waiting on this circuit, fail * them now so they can retry elsewhere. */ diff --git a/src/or/connection.c b/src/or/connection.c index 2964c30f73..c2a7a87d41 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -634,6 +634,7 @@ connection_free_(connection_t *conn) cached_dir_decref(dir_conn->cached_dir); rend_data_free(dir_conn->rend_data); + circuit_guard_state_free(dir_conn->guard_state); } if (SOCKET_OK(conn->s)) { diff --git a/src/or/connection_or.c b/src/or/connection_or.c index ecc5a4511a..fefcc86932 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -735,6 +735,9 @@ connection_or_about_to_close(or_connection_t *or_conn) const or_options_t *options = get_options(); connection_or_note_state_when_broken(or_conn); rep_hist_note_connect_failed(or_conn->identity_digest, now); + entry_guard_chan_failed(get_guard_selection_info(), + TLS_CHAN_TO_BASE(or_conn->chan)); + /* XXXX prop271 -- old API */ entry_guard_register_connect_status(or_conn->identity_digest,0, !options->HTTPSProxy, now); if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) { @@ -1673,6 +1676,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn, "Tried connecting to router at %s:%d, but identity key was not " "as expected: wanted %s but got %s.%s", conn->base_.address, conn->base_.port, expected, seen, extra_log); + entry_guard_chan_failed(get_guard_selection_info(), + TLS_CHAN_TO_BASE(conn->chan)); + /* XXXX prop271 old API */ entry_guard_register_connect_status(conn->identity_digest, 0, 1, time(NULL)); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, diff --git a/src/or/directory.c b/src/or/directory.c index efa5a3126a..4164672f10 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -128,7 +128,8 @@ static void directory_initiate_command_rend( const char *payload, size_t payload_len, time_t if_modified_since, - const rend_data_t *rend_query); + const rend_data_t *rend_query, + circuit_guard_state_t *guard_state); static void connection_dir_close_consensus_fetches( dir_connection_t *except_this_one, const char *resource); @@ -422,7 +423,8 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, indirection, - NULL, payload, upload_len, 0); + NULL, payload, upload_len, 0, + NULL); } SMARTLIST_FOREACH_END(ds); if (!found) { char *s = authdir_type_to_string(type); @@ -458,7 +460,8 @@ should_use_directory_guards(const or_options_t *options) * information of type type, and return its routerstatus. */ static const routerstatus_t * directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, - uint8_t dir_purpose) + uint8_t dir_purpose, + circuit_guard_state_t **guard_state_out) { const routerstatus_t *rs = NULL; const or_options_t *options = get_options(); @@ -467,7 +470,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, log_warn(LD_BUG, "Called when we have UseBridges set."); if (should_use_directory_guards(options)) { - const node_t *node = choose_random_dirguard(type); + const node_t *node = guards_choose_dirguard(type, guard_state_out); if (node) rs = node->rs; } else { @@ -548,6 +551,7 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( if (!options->FetchServerDescriptors) return; + circuit_guard_state_t *guard_state = NULL; if (!get_via_tor) { if (options->UseBridges && !(type & BRIDGE_DIRINFO)) { /* We want to ask a running bridge for which we have a descriptor. @@ -556,6 +560,7 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( * sort of dir fetch we'll be doing, so it won't return a bridge * that can't answer our question. */ + // XXXX prop271 update this for bridge support. const node_t *node = choose_random_dirguard(type); if (node && node->ri) { /* every bridge has a routerinfo. */ @@ -605,9 +610,9 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( } } if (!rs && !(type & BRIDGE_DIRINFO)) { - /* */ rs = directory_pick_generic_dirserver(type, pds_flags, - dir_purpose); + dir_purpose, + &guard_state); if (!rs) get_via_tor = 1; /* last resort: try routing it via Tor */ } @@ -630,7 +635,8 @@ MOCK_IMPL(void, directory_get_from_dirserver, ( router_purpose, indirection, resource, NULL, 0, - if_modified_since); + if_modified_since, + guard_state); } else { log_notice(LD_DIR, "While fetching directory info, " @@ -664,7 +670,7 @@ directory_get_from_all_authorities(uint8_t dir_purpose, rs = &ds->fake_status; directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose, DIRIND_ONEHOP, resource, NULL, - 0, 0); + 0, 0, NULL); } SMARTLIST_FOREACH_END(ds); } @@ -775,7 +781,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, const char *payload, size_t payload_len, time_t if_modified_since, - const rend_data_t *rend_query) + const rend_data_t *rend_query, + circuit_guard_state_t *guard_state) { const or_options_t *options = get_options(); const node_t *node; @@ -830,7 +837,8 @@ directory_initiate_command_routerstatus_rend(const routerstatus_t *status, dir_purpose, router_purpose, indirection, resource, payload, payload_len, if_modified_since, - rend_query); + rend_query, + guard_state); } /** Launch a new connection to the directory server status to @@ -855,13 +863,15 @@ MOCK_IMPL(void, directory_initiate_command_routerstatus, const char *resource, const char *payload, size_t payload_len, - time_t if_modified_since)) + time_t if_modified_since, + circuit_guard_state_t *guard_state)) { directory_initiate_command_routerstatus_rend(status, dir_purpose, router_purpose, indirection, resource, payload, payload_len, - if_modified_since, NULL); + if_modified_since, NULL, + guard_state); } /** Return true iff conn is the client side of a directory connection @@ -889,6 +899,11 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn) static void connection_dir_request_failed(dir_connection_t *conn) { + if (conn->guard_state) { + /* We haven't seen a success on this guard state, so consider it to have + * failed. */ + entry_guard_failed(get_guard_selection_info(), &conn->guard_state); + } if (directory_conn_is_self_reachability_test(conn)) { return; /* this was a test fetch. don't retry. */ } @@ -1136,7 +1151,7 @@ directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port, digest, dir_purpose, router_purpose, indirection, resource, payload, payload_len, - if_modified_since, NULL); + if_modified_since, NULL, NULL); } /** Same as directory_initiate_command(), but accepts rendezvous data to @@ -1151,7 +1166,8 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port, const char *resource, const char *payload, size_t payload_len, time_t if_modified_since, - const rend_data_t *rend_query) + const rend_data_t *rend_query, + circuit_guard_state_t *guard_state) { tor_assert(or_addr_port); tor_assert(dir_addr_port); @@ -1246,12 +1262,18 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port, if (!anonymized_connection && !use_begindir) { /* then we want to connect to dirport directly */ + // XXXX prop271 I think that we never use guards in this case. if (options->HTTPProxy) { tor_addr_copy(&addr, &options->HTTPProxyAddr); port = options->HTTPProxyPort; } + // In this case we should not have picked a directory guard. + if (BUG(guard_state)) { + entry_guard_cancel(get_guard_selection_info(), &guard_state); + } + switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr, port, &socket_error)) { case -1: @@ -1288,6 +1310,14 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port, else if (anonymized_connection && !use_begindir) rep_hist_note_used_port(time(NULL), conn->base_.port); + // In this case we should not have a directory guard; we'll + // get a regular guard later when we build the circuit. + if (BUG(anonymized_connection && guard_state)) { + entry_guard_cancel(get_guard_selection_info(), &guard_state); + } + + conn->guard_state = guard_state; + /* make an AP connection * populate it and add it at the right state * hook up both sides @@ -2540,6 +2570,22 @@ connection_dir_process_inbuf(dir_connection_t *conn) tor_assert(conn); tor_assert(conn->base_.type == CONN_TYPE_DIR); + if (conn->guard_state) { + /* we count the connection as successful once we can read from it. We do + * not, however, delay use of the circuit here, since it's just for a + * one-hop directory request. */ + /* XXXXprop271 note that this will not do the right thing for other + * waiting circuits that would be triggered by this circuit becoming + * complete/usable. But that's ok, I think. + */ + /* XXXXprop271 should we count this as only a partial success somehow? + */ + entry_guard_succeeded(get_guard_selection_info(), + &conn->guard_state); + circuit_guard_state_free(conn->guard_state); + conn->guard_state = NULL; + } + /* Directory clients write, then read data until they receive EOF; * directory servers read data until they get an HTTP command, then * write their response (when it's finished flushing, they mark for diff --git a/src/or/directory.h b/src/or/directory.h index 589df7b70d..ee0a198c52 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -49,7 +49,8 @@ MOCK_DECL(void, directory_initiate_command_routerstatus, const char *resource, const char *payload, size_t payload_len, - time_t if_modified_since)); + time_t if_modified_since, + struct circuit_guard_state_t *guard_state)); void directory_initiate_command_routerstatus_rend(const routerstatus_t *status, uint8_t dir_purpose, @@ -59,7 +60,8 @@ void directory_initiate_command_routerstatus_rend(const routerstatus_t *status, const char *payload, size_t payload_len, time_t if_modified_since, - const rend_data_t *rend_query); + const rend_data_t *rend_query, + struct circuit_guard_state_t *guard_state); int parse_http_response(const char *headers, int *code, time_t *date, compress_method_t *compression, char **response); diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 24a3448969..eca88a947c 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -89,7 +89,7 @@ * [x] Whenever a guard becomes reachable or maybe-reachable, if its filtered * flag is set, set its usable_filtered flag. * - * [ ] Whenever we get a new consensus, call update_from_consensus(). (LATER.) + * [x] Whenever we get a new consensus, call update_from_consensus(). (LATER.) * * [ ] Whenever the configuration changes in a relevant way, update the * filtered/usable flags. (LATER.) @@ -1203,8 +1203,6 @@ entry_guards_note_guard_success(guard_selection_t *gs, if (last_time_on_internet + INTERNET_LIKELY_DOWN_INTERVAL < approx_time()) { mark_primary_guards_maybe_reachable(gs); - } else { - // update_waiting_circuits(gs); // XXXX prop271 write this function. } } @@ -1475,7 +1473,7 @@ circ_state_has_higher_priority(origin_circuit_t *a, */ int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, - smartlist_t *all_circuits, + const smartlist_t *all_circuits, smartlist_t *newly_complete_out) { tor_assert(gs); @@ -2274,7 +2272,7 @@ add_an_entry_guard(guard_selection_t *gs, return NULL; } } else if (!for_directory) { - node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL); + node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL, NULL); if (!node) return NULL; } else { @@ -3779,6 +3777,58 @@ entries_retry_all(const or_options_t *options) entries_retry_helper(options, 1); } +/** Helper: Update the status of all entry guards, in whatever algorithm + is used. */ +void +guards_update_all(void) +{ + if (get_options()->UseDeprecatedGuardAlgorithm) { + entry_guards_compute_status(get_options(), approx_time()); + } else { + entry_guards_update_all(get_guard_selection_info()); + } +} + +/** Helper: pick a guard for a circuit, with whatever algorithm is + used. */ +const node_t * +guards_choose_guard(cpath_build_state_t *state, + circuit_guard_state_t **guard_state_out) +{ + if (get_options()->UseDeprecatedGuardAlgorithm) { + return choose_random_entry(state); + } else { + // XXXX prop271 we need to look at the chosen exit node if any, and + // not duplicate it. + const node_t *r = NULL; + if (entry_guard_pick_for_circuit(get_guard_selection_info(), + &r, + guard_state_out) < 0) { + tor_assert(r == NULL); + } + return r; + } +} + +/** Helper: pick a directory guard, with whatever algorithm is used. */ +const node_t * +guards_choose_dirguard(dirinfo_type_t info, + circuit_guard_state_t **guard_state_out) +{ + if (get_options()->UseDeprecatedGuardAlgorithm) { + return choose_random_dirguard(info); + } else { + // XXXX prop271 look at info? + const node_t *r = NULL; + if (entry_guard_pick_for_circuit(get_guard_selection_info(), + &r, + guard_state_out) < 0) { + tor_assert(r == NULL); + } + return r; + } +} + /** Free one guard selection context */ STATIC void guard_selection_free(guard_selection_t *gs) diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 60191ab8b9..7dcedd6066 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -328,7 +328,7 @@ void entry_guard_chan_failed(guard_selection_t *gs, channel_t *chan); void entry_guards_update_all(guard_selection_t *gs); int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, - smartlist_t *all_circuits, + const smartlist_t *all_circuits, smartlist_t *newly_complete_out); void entry_guards_note_internet_connectivity(guard_selection_t *gs); diff --git a/src/or/main.c b/src/or/main.c index a508003f97..65d1c1fd79 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -979,7 +979,7 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs) /* if we have enough dir info, then update our guard status with * whatever we just learned. */ - entry_guards_compute_status(options, now); + guards_update_all(); /* Don't even bother trying to get extrainfo until the rest of our * directory info is up-to-date */ if (options->DownloadExtraInfo) @@ -1376,6 +1376,9 @@ run_scheduled_events(time_t now) /* 0c. If we've deferred log messages for the controller, handle them now */ flush_pending_log_callbacks(); + /* Maybe enough time elapsed for us to reconsider a circuit. */ + circuit_upgrade_circuits_from_guard_wait(); + if (options->UseBridges && !options->DisableNetwork) { fetch_bridge_descriptors(options, now); } diff --git a/src/or/or.h b/src/or/or.h index c8f39f90d9..8b9ede3607 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1786,6 +1786,10 @@ typedef struct dir_connection_t { /** What rendezvous service are we querying for? */ rend_data_t *rend_data; + /** If this is a one-hop connection, tracks the state of the directory guard + * for this connection (if any). */ + struct circuit_guard_state_t *guard_state; + char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for * the directory server's signing key. */ diff --git a/src/or/rendclient.c b/src/or/rendclient.c index b0dcf52507..06744ad795 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -762,7 +762,7 @@ directory_get_from_hs_dir(const char *desc_id, how_to_fetch, desc_id_base32, NULL, 0, 0, - rend_query); + rend_query, NULL); log_info(LD_REND, "Sending fetch request for v2 descriptor for " "service '%s' with descriptor ID '%s', auth type %d, " "and descriptor cookie '%s' to hidden service " diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 8ffd0bc319..cf57c7d061 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -3452,7 +3452,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, DIRIND_ANONYMOUS, NULL, desc->desc_str, strlen(desc->desc_str), - 0, rend_data); + 0, rend_data, NULL); rend_data_free(rend_data); base32_encode(desc_id_base32, sizeof(desc_id_base32), desc->desc_id, DIGEST_LEN); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index f51b50e8e5..d2f360a63f 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -971,7 +971,7 @@ authority_certs_fetch_resource_impl(const char *resource, directory_initiate_command_routerstatus(rs, DIR_PURPOSE_FETCH_CERTIFICATE, 0, indirection, resource, NULL, - 0, 0); + 0, 0, NULL); return; } @@ -4946,7 +4946,7 @@ MOCK_IMPL(STATIC void, initiate_descriptor_downloads, directory_initiate_command_routerstatus(source, purpose, ROUTER_PURPOSE_GENERAL, DIRIND_ONEHOP, - resource, NULL, 0, 0); + resource, NULL, 0, 0, NULL); } else { directory_get_from_dirserver(purpose, ROUTER_PURPOSE_GENERAL, resource, pds_flags, DL_WANT_ANY_DIRSERVER); diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 6f83ceff00..4501d6b547 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -23,6 +23,7 @@ #include "directory.h" #include "dirserv.h" #include "dirvote.h" +#include "entrynodes.h" #include "hibernate.h" #include "memarea.h" #include "networkstatus.h" @@ -4397,7 +4398,8 @@ directory_initiate_command_routerstatus, (const routerstatus_t *status, const char *resource, const char *payload, size_t payload_len, - time_t if_modified_since)); + time_t if_modified_since, + circuit_guard_state_t *guardstate)); static void test_dir_should_not_init_request_to_ourselves(void *data) @@ -4504,7 +4506,8 @@ NS(directory_initiate_command_routerstatus)(const routerstatus_t *status, const char *resource, const char *payload, size_t payload_len, - time_t if_modified_since) + time_t if_modified_since, + circuit_guard_state_t *guardstate) { (void)status; (void)dir_purpose; @@ -4514,6 +4517,7 @@ NS(directory_initiate_command_routerstatus)(const routerstatus_t *status, (void)payload; (void)payload_len; (void)if_modified_since; + (void)guardstate; CALLED(directory_initiate_command_routerstatus)++; } -- cgit v1.2.3-54-g00ecf From 897626953b15ac216d27b3814804524caa9fdd1c Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 23 Nov 2016 09:09:30 -0500 Subject: Rebuild the guard lists as appropriate on torrc change. (Also, prepare to tie guard changes into the mark-all-old-circuits logic.) --- src/or/config.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/or/entrynodes.c | 17 ++++++++++++----- src/or/entrynodes.h | 4 ++-- src/or/main.c | 5 ++++- 4 files changed, 61 insertions(+), 8 deletions(-) (limited to 'src/or/main.c') diff --git a/src/or/config.c b/src/or/config.c index f77f4d1879..b7b5cff35a 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1561,6 +1561,36 @@ options_transition_requires_fresh_tls_context(const or_options_t *old_options, return 0; } +/** + * Return true if changing the configuration from old to new + * affects the guard susbsystem. + */ +static int +options_transition_affects_guards(const or_options_t *old, + const or_options_t *new) +{ + /* NOTE: Make sure this function stays in sync with + * entry_guards_set_filtered_flags */ + + tor_assert(old); + tor_assert(new); + + return + (old->UseEntryGuards != new->UseEntryGuards || + old->UseDeprecatedGuardAlgorithm != new->UseDeprecatedGuardAlgorithm || + old->UseBridges != new->UseBridges || + old->UseEntryGuards != new->UseEntryGuards || + old->ClientUseIPv4 != new->ClientUseIPv4 || + old->ClientUseIPv6 != new->ClientUseIPv6 || + old->FascistFirewall != new->FascistFirewall || + !routerset_equal(old->ExcludeNodes, new->ExcludeNodes) || + !routerset_equal(old->EntryNodes, new->EntryNodes) || + !smartlist_strings_eq(old->FirewallPorts, new->FirewallPorts) || + !config_lines_eq(old->Bridges, new->Bridges) || + !config_lines_eq(old->ReachableORAddresses, new->ReachableORAddresses) || + !config_lines_eq(old->ReachableDirAddresses, new->ReachableDirAddresses)); +} + /** Fetch the active option list, and take actions based on it. All of the * things we do should survive being done repeatedly. If present, * old_options contains the previous value of the options. @@ -1580,6 +1610,8 @@ options_act(const or_options_t *old_options) const int transition_affects_workers = old_options && options_transition_affects_workers(old_options, options); int old_ewma_enabled; + const int transition_affects_guards = + old_options && options_transition_affects_guards(old_options, options); /* disable ptrace and later, other basic debugging techniques */ { @@ -1875,6 +1907,7 @@ options_act(const or_options_t *old_options) if (old_options) { int revise_trackexithosts = 0; int revise_automap_entries = 0; + int abandon_circuits = 0; if ((options->UseEntryGuards && !old_options->UseEntryGuards) || options->UseBridges != old_options->UseBridges || (options->UseBridges && @@ -1891,6 +1924,16 @@ options_act(const or_options_t *old_options) "Changed to using entry guards or bridges, or changed " "preferred or excluded node lists. " "Abandoning previous circuits."); + abandon_circuits = 1; + } + + if (transition_affects_guards) { + if (guards_update_all()) { + abandon_circuits = 1; + } + } + + if (abandon_circuits) { circuit_mark_all_unused_circs(); circuit_mark_all_dirty_circs_as_unusable(); revise_trackexithosts = 1; diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 81751f565c..9a753e6d25 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -91,7 +91,7 @@ * * [x] Whenever we get a new consensus, call update_from_consensus(). (LATER.) * - * [ ] Whenever the configuration changes in a relevant way, update the + * [x] Whenever the configuration changes in a relevant way, update the * filtered/usable flags. (LATER.) * * [x] Whenever we add a guard to the sample, make sure its filtered/usable @@ -696,6 +696,9 @@ static int node_passes_guard_filter(const or_options_t *options, guard_selection_t *gs, const node_t *node) { + /* NOTE: Make sure that this function stays in sync with + * options_transition_affects_entry_guards */ + (void)gs; if (routerset_contains_node(options->ExcludeNodes, node)) return 0; @@ -1636,14 +1639,16 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, /** * Update all derived pieces of the guard selection state in gs. + * Return true iff we should stop using all previously generated circuits. */ -void +int entry_guards_update_all(guard_selection_t *gs) { sampled_guards_update_from_consensus(gs); entry_guards_update_filtered_sets(gs); entry_guards_update_confirmed(gs); entry_guards_update_primary(gs); + return 0; } /** @@ -4020,14 +4025,16 @@ entries_retry_all(const or_options_t *options) } /** Helper: Update the status of all entry guards, in whatever algorithm - is used. */ -void + * is used. Return true if we should stop using all previously generated + * circuits. */ +int guards_update_all(void) { if (get_options()->UseDeprecatedGuardAlgorithm) { entry_guards_compute_status(get_options(), approx_time()); + return 0; } else { - entry_guards_update_all(get_guard_selection_info()); + return entry_guards_update_all(get_guard_selection_info()); } } diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index d8468eb287..4cbfbf55bf 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -294,7 +294,7 @@ struct circuit_guard_state_t { #endif /* Common entry points for old and new guard code */ -void guards_update_all(void); +int guards_update_all(void); const node_t *guards_choose_guard(cpath_build_state_t *state, circuit_guard_state_t **guard_state_out); const node_t *guards_choose_dirguard(dirinfo_type_t info, @@ -336,7 +336,7 @@ void entry_guard_cancel(guard_selection_t *gs, circuit_guard_state_t **guard_state_p); void entry_guard_chan_failed(guard_selection_t *gs, channel_t *chan); -void entry_guards_update_all(guard_selection_t *gs); +int entry_guards_update_all(guard_selection_t *gs); int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, const smartlist_t *all_circuits, smartlist_t *newly_complete_out); diff --git a/src/or/main.c b/src/or/main.c index 65d1c1fd79..16106612a9 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -979,7 +979,10 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs) /* if we have enough dir info, then update our guard status with * whatever we just learned. */ - guards_update_all(); + int invalidate_circs = guards_update_all(); + // This shouldn't be able to occur at this point. + tor_assert_nonfatal(! invalidate_circs); + /* Don't even bother trying to get extrainfo until the rest of our * directory info is up-to-date */ if (options->DownloadExtraInfo) -- cgit v1.2.3-54-g00ecf From 2ea5aa71823f385e36f20e643a20996dcb164464 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 25 Nov 2016 12:53:00 -0500 Subject: Expire circuits that have been WAITING_FOR_BETTER_GUARD too long (This is required by 3.9 in prop271, but is better done as a separate function IMO) --- src/or/circuitlist.c | 12 +++++++++++- src/or/circuitlist.h | 1 + src/or/circuituse.c | 19 +++++++++++++++++++ src/or/circuituse.h | 1 + src/or/entrynodes.c | 18 +++++++++++++++--- src/or/entrynodes.h | 1 + src/or/main.c | 1 + 7 files changed, 49 insertions(+), 4 deletions(-) (limited to 'src/or/main.c') diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 9d7a5d7f0e..0afe2f8059 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -553,7 +553,7 @@ circuit_close_all_marked(void) smartlist_clear(circuits_pending_close); } -/** Return the head of the global linked list of circuits. */ +/** Return a pointer to the global list of circuits. */ MOCK_IMPL(smartlist_t *, circuit_get_global_list,(void)) { @@ -562,6 +562,16 @@ circuit_get_global_list,(void)) return global_circuitlist; } +/** */ +/** Return a pointer to the global list of origin circuits. */ +smartlist_t * +circuit_get_global_origin_circuit_list(void) +{ + if (NULL == global_origin_circuit_list) + global_origin_circuit_list = smartlist_new(); + return global_circuitlist; +} + /** Function to make circ-\>state human-readable */ const char * circuit_state_to_string(int state) diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 73039cc06e..e2102a118b 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -15,6 +15,7 @@ #include "testsupport.h" MOCK_DECL(smartlist_t *, circuit_get_global_list, (void)); +smartlist_t *circuit_get_global_origin_circuit_list(void); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index b9f94fb3a2..b925729e01 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -800,6 +800,25 @@ circuit_expire_building(void) } SMARTLIST_FOREACH_END(victim); } +/** + * Mark for close all circuits that start here, that were built through a + * guard we weren't sure if we wanted to use, and that have been waiting + * around for way too long. + */ +void +circuit_expire_waiting_for_better_guard(void) +{ + SMARTLIST_FOREACH_BEGIN(circuit_get_global_origin_circuit_list(), + origin_circuit_t *, circ) { + if (TO_CIRCUIT(circ)->marked_for_close) + continue; + if (circ->guard_state == NULL) + continue; + if (entry_guard_state_should_expire(circ->guard_state)) + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NONE); + } SMARTLIST_FOREACH_END(circ); +} + /** For debugging #8387: track when we last called * circuit_expire_old_circuits_clientside. */ static time_t last_expired_clientside_circuits = 0; diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 5973978c45..110bdda5b2 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -13,6 +13,7 @@ #define TOR_CIRCUITUSE_H void circuit_expire_building(void); +void circuit_expire_waiting_for_better_guard(void); void circuit_remove_handled_ports(smartlist_t *needed_ports); int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port, int min); diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 951ce15f85..1c9349ee03 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1605,9 +1605,6 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, "circuit had higher priority, so not upgrading.", n_complete, n_waiting); - /* XXXX prop271 implement: "(Time them out after a - {NONPRIMARY_GUARD_IDLE_TIMEOUT} seconds.)" - */ return 0; } } @@ -1671,6 +1668,21 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, return 1; } +/** + * Return true iff the circuit whose state is guard_state should + * expire. + */ +int +entry_guard_state_should_expire(circuit_guard_state_t *guard_state) +{ + if (guard_state == NULL) + return 0; + const time_t expire_if_waiting_since = + approx_time() - NONPRIMARY_GUARD_IDLE_TIMEOUT; + return (guard_state->state == GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD + && guard_state->state_set_at < expire_if_waiting_since); +} + /** * Update all derived pieces of the guard selection state in gs. * Return true iff we should stop using all previously generated circuits. diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index ec24011377..648e599310 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -337,6 +337,7 @@ int entry_guards_update_all(guard_selection_t *gs); int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, const smartlist_t *all_circuits, smartlist_t *newly_complete_out); +int entry_guard_state_should_expire(circuit_guard_state_t *guard_state); void entry_guards_note_internet_connectivity(guard_selection_t *gs); /* Used by bridges.c only. */ diff --git a/src/or/main.c b/src/or/main.c index 16106612a9..96ff442c68 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1402,6 +1402,7 @@ run_scheduled_events(time_t now) /* (If our circuit build timeout can ever become lower than a second (which * it can't, currently), we should do this more often.) */ circuit_expire_building(); + circuit_expire_waiting_for_better_guard(); /* 3b. Also look at pending streams and prune the ones that 'began' * a long time ago but haven't gotten a 'connected' yet. -- cgit v1.2.3-54-g00ecf From 404e9e5611eff39866c2e45133a60b40d7492f7e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 28 Nov 2016 07:41:45 -0500 Subject: Have multiple guard contexts we can switch between. Currently, this code doesn't actually have the contexts behave differently, (except for the legacy context), but it does switch back and forth between them nicely. --- src/or/config.c | 7 -- src/or/entrynodes.c | 270 ++++++++++++++++++++++++++++++++++++++++----- src/or/entrynodes.h | 50 +++++++-- src/or/main.c | 7 +- src/test/test_entrynodes.c | 59 +++++----- 5 files changed, 321 insertions(+), 72 deletions(-) (limited to 'src/or/main.c') diff --git a/src/or/config.c b/src/or/config.c index b7b5cff35a..22e5dfdaa0 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -4536,13 +4536,6 @@ options_transition_allowed(const or_options_t *old, return -1; } - if (old->UseDeprecatedGuardAlgorithm != - new_val->UseDeprecatedGuardAlgorithm) { - *msg = tor_strdup("While Tor is running, changing " - "UseDeprecatedGuardAlgorithm is not allowed."); - return -1; - } - if (sandbox_is_active()) { #define SB_NOCHANGE_STR(opt) \ do { \ diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 6f6853e782..59205a8bcc 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -159,6 +159,10 @@ static void entry_guard_set_filtered_flags(const or_options_t *options, entry_guard_t *guard); static void pathbias_check_use_success_count(entry_guard_t *guard); static void pathbias_check_close_success_count(entry_guard_t *guard); +static int node_is_possible_guard(guard_selection_t *gs, const node_t *node); +static int node_passes_guard_filter(const or_options_t *options, + guard_selection_t *gs, + const node_t *node); /** Return 0 if we should apply guardfraction information found in the * consensus. A specific consensus can be specified with the @@ -186,12 +190,25 @@ should_apply_guardfraction(const networkstatus_t *ns) * Allocate and return a new guard_selection_t, with the name name. */ STATIC guard_selection_t * -guard_selection_new(const char *name) +guard_selection_new(const char *name, + guard_selection_type_t type) { guard_selection_t *gs; + if (type == GS_TYPE_INFER) { + if (!strcmp(name, "legacy")) + type = GS_TYPE_LEGACY; + else if (!strcmp(name, "bridges")) + type = GS_TYPE_BRIDGE; + else if (!strcmp(name, "restricted")) + type = GS_TYPE_RESTRICTED; + else + type = GS_TYPE_NORMAL; + } + gs = tor_malloc_zero(sizeof(*gs)); gs->name = tor_strdup(name); + gs->type = type; gs->chosen_entry_guards = smartlist_new(); gs->sampled_entry_guards = smartlist_new(); gs->confirmed_entry_guards = smartlist_new(); @@ -206,7 +223,9 @@ guard_selection_new(const char *name) * is none, and create_if_absent is false, then return NULL. */ STATIC guard_selection_t * -get_guard_selection_by_name(const char *name, int create_if_absent) +get_guard_selection_by_name(const char *name, + guard_selection_type_t type, + int create_if_absent) { if (!guard_contexts) { guard_contexts = smartlist_new(); @@ -219,31 +238,42 @@ get_guard_selection_by_name(const char *name, int create_if_absent) if (! create_if_absent) return NULL; - guard_selection_t *new_selection = guard_selection_new(name); + log_debug(LD_GUARD, "Creating a guard selection called %s", name); + guard_selection_t *new_selection = guard_selection_new(name, type); smartlist_add(guard_contexts, new_selection); - const char *default_name = get_options()->UseDeprecatedGuardAlgorithm ? - "legacy" : "default"; - - if (!strcmp(name, default_name)) - curr_guard_context = new_selection; - return new_selection; } -/** Get current default guard_selection_t, creating it if necessary */ -guard_selection_t * -get_guard_selection_info(void) +/** + * Allocate the first guard context that we're planning to use, + * and make it the current context. + */ +static void +create_initial_guard_context(void) { + tor_assert(! curr_guard_context); if (!guard_contexts) { guard_contexts = smartlist_new(); } + guard_selection_type_t type = GS_TYPE_INFER; + const char *name = choose_guard_selection( + get_options(), + networkstatus_get_live_consensus(approx_time()), + NULL, + &type); + tor_assert(name); // "name" can only be NULL if we had an old name. + tor_assert(type != GS_TYPE_INFER); + log_notice(LD_GUARD, "Starting with guard context \"%s\"", name); + curr_guard_context = get_guard_selection_by_name_and_type(name, type); +} +/** Get current default guard_selection_t, creating it if necessary */ +guard_selection_t * +get_guard_selection_info(void) +{ if (!curr_guard_context) { - const char *name = get_options()->UseDeprecatedGuardAlgorithm ? - "legacy" : "default"; - curr_guard_context = guard_selection_new(name); - smartlist_add(guard_contexts, curr_guard_context); + create_initial_guard_context(); } return curr_guard_context; @@ -431,10 +461,184 @@ get_nonprimary_guard_idle_timeout(void) { return networkstatus_get_param(NULL, "guard-nonprimary-guard-idle-timeout", - (10*60), 1, INT32_MAX); + DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT, + 1, INT32_MAX); +} +/** + * If our configuration retains fewer than this fraction of guards from the + * torrc, we are in a restricted setting. + */ +STATIC double +get_meaningful_restriction_threshold(void) +{ + int32_t pct = networkstatus_get_param(NULL, + "guard-meaningful-restriction-percent", + DFLT_MEANINGFUL_RESTRICTION_PERCENT, + 1, INT32_MAX); + return pct / 100.0; +} +/** + * If our configuration retains fewer than this fraction of guards from the + * torrc, we are in an extremely restricted setting, and should warn. + */ +STATIC double +get_extreme_restriction_threshold(void) +{ + int32_t pct = networkstatus_get_param(NULL, + "guard-extreme-restriction-percent", + DFLT_EXTREME_RESTRICTION_PERCENT, + 1, INT32_MAX); + return pct / 100.0; } /**@}*/ +/** + * Given our options and our list of nodes, return the name of the + * guard selection that we should use. Return NULL for "use the + * same selection you were using before. + */ +STATIC const char * +choose_guard_selection(const or_options_t *options, + const networkstatus_t *live_ns, + const char *old_selection, + guard_selection_type_t *type_out) +{ + tor_assert(options); + tor_assert(type_out); + if (options->UseDeprecatedGuardAlgorithm) { + *type_out = GS_TYPE_LEGACY; + return "legacy"; + } + + if (options->UseBridges) { + *type_out = GS_TYPE_BRIDGE; + return "bridges"; + } + + if (! live_ns) { + /* without a networkstatus, we can't tell any more than that. */ + *type_out = GS_TYPE_NORMAL; + return "default"; + } + + const smartlist_t *nodes = nodelist_get_list(); + int n_guards = 0, n_passing_filter = 0; + SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) { + if (node_is_possible_guard(NULL, node)) { + ++n_guards; + if (node_passes_guard_filter(options, NULL, node)) { + ++n_passing_filter; + } + } + } SMARTLIST_FOREACH_END(node); + + /* XXXX prop271 spec deviation -- separate 'high' and 'low' thresholds + * to prevent flapping */ + const int meaningful_threshold_high = + (int)(n_guards * get_meaningful_restriction_threshold() * 1.05); + const int meaningful_threshold_mid = + (int)(n_guards * get_meaningful_restriction_threshold()); + const int meaningful_threshold_low = + (int)(n_guards * get_meaningful_restriction_threshold() * .95); + const int extreme_threshold = + (int)(n_guards * get_extreme_restriction_threshold()); + + /* + If we have no previous selection, then we're "restricted" iff we are + below the meaningful restriction threshold. That's easy enough. + + But if we _do_ have a previous selection, we make it a little + "sticky": we only move from "restricted" to "default" when we find + that we're above the threshold plus 5%, and we only move from + "default" to "restricted" when we're below the threshold minus 5%. + That should prevent us from flapping back and forth if we happen to + be hovering very close to the default. + + The extreme threshold is for warning only. + */ + + static int have_warned_extreme_threshold = 0; + if (n_passing_filter < extreme_threshold && + ! have_warned_extreme_threshold) { + have_warned_extreme_threshold = 1; + const double exclude_frac = + (n_guards - n_passing_filter) / (double)n_guards; + log_warn(LD_GUARD, "Your configuration excludes %d%% of all possible " + "guards. That's likely to make you stand out from the " + "rest of the world.", (int)(exclude_frac * 100)); + } + + /* Easy case: no previous selection */ + if (old_selection == NULL) { + if (n_passing_filter >= meaningful_threshold_mid) { + *type_out = GS_TYPE_NORMAL; + return "default"; + } else { + *type_out = GS_TYPE_RESTRICTED; + return "restricted"; + } + } + + /* Trickier case: we do have a previous selection */ + if (n_passing_filter >= meaningful_threshold_high) { + *type_out = GS_TYPE_NORMAL; + return "default"; + } else if (n_passing_filter < meaningful_threshold_low) { + *type_out = GS_TYPE_RESTRICTED; + return "restricted"; + } else { + return NULL; + } +} + +/** + * Check whether we should switch from our current guard selection to a + * different one. If so, switch and return 1. Return 0 otherwise. + * + * On a 1 return, the caller should mark all currently live circuits + * unusable for new streams. + */ +int +update_guard_selection_choice(const or_options_t *options) +{ + if (!curr_guard_context) { + create_initial_guard_context(); + return 1; + } + + const char *cur_name = curr_guard_context->name; + guard_selection_type_t type = GS_TYPE_INFER; + const char *new_name = choose_guard_selection( + options, + networkstatus_get_live_consensus(approx_time()), + cur_name, + &type); + tor_assert(new_name); + tor_assert(type != GS_TYPE_INFER); + + if (! strcmp(cur_name, new_name)) { + log_debug(LD_GUARD, + "Staying with guard context \"%s\" (no change)", new_name); + return 0; // No change + } + + log_notice(LD_GUARD, "Switching to guard context \"%s\" (was using \"%s\")", + new_name, cur_name); + guard_selection_t *new_guard_context; + new_guard_context = get_guard_selection_by_name(new_name, type, 1); + tor_assert(new_guard_context); + tor_assert(new_guard_context != curr_guard_context); + curr_guard_context = new_guard_context; + + /* + Be sure to call: + circuit_mark_all_unused_circs(); + circuit_mark_all_dirty_circs_as_unusable(); + */ + + return 1; +} + /** * Return true iff node has all the flags needed for us to consider it * a possible guard when sampling guards. @@ -446,7 +650,7 @@ node_is_possible_guard(guard_selection_t *gs, const node_t *node) * holds. */ /* XXXX -- prop271 spec deviation. We require node_is_dir() here. */ - (void)gs; + (void)gs; /* Remove this argument */ tor_assert(node); return (node->is_possible_guard && node->is_stable && @@ -552,7 +756,7 @@ entry_guards_expand_sample(guard_selection_t *gs) int n_sampled = smartlist_len(gs->sampled_entry_guards); entry_guard_t *added_guard = NULL; - smartlist_t *nodes = nodelist_get_list(); + const smartlist_t *nodes = nodelist_get_list(); /* Construct eligible_guards as GUARDS - SAMPLED_GUARDS */ smartlist_t *eligible_guards = smartlist_new(); int n_guards = 0; // total size of "GUARDS" @@ -565,13 +769,13 @@ entry_guards_expand_sample(guard_selection_t *gs) digestset_add(sampled_guard_ids, guard->identity); } SMARTLIST_FOREACH_END(guard); - SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { + SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) { if (! node_is_possible_guard(gs, node)) continue; ++n_guards; if (digestset_contains(sampled_guard_ids, node->identity)) continue; - smartlist_add(eligible_guards, node); + smartlist_add(eligible_guards, (node_t*)node); } SMARTLIST_FOREACH_END(node); /* Now we can free that bloom filter. */ @@ -817,6 +1021,8 @@ static int node_passes_guard_filter(const or_options_t *options, guard_selection_t *gs, const node_t *node) { + /* XXXX prop271 remote the gs option; it is unused, and sometimes NULL. */ + /* NOTE: Make sure that this function stays in sync with * options_transition_affects_entry_guards */ @@ -2221,7 +2427,8 @@ entry_guards_load_guards_from_state(or_state_t *state, int set) if (set) { guard_selection_t *gs; - gs = get_guard_selection_by_name(guard->selection_name, 1); + gs = get_guard_selection_by_name(guard->selection_name, + GS_TYPE_INFER, 1); tor_assert(gs); smartlist_add(gs->sampled_entry_guards, guard); } else { @@ -3854,7 +4061,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) int r1 = entry_guards_load_guards_from_state(state, set); int r2 = entry_guards_parse_state_for_guard_selection( - get_guard_selection_by_name("legacy", 1), + get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 1), state, set, msg); entry_guards_dirty = 0; @@ -3926,7 +4133,8 @@ entry_guards_update_state(or_state_t *state) entry_guards_dirty = 0; - guard_selection_t *gs = get_guard_selection_by_name("legacy", 0); + guard_selection_t *gs; + gs = get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 0); if (!gs) return; // nothign to save. tor_assert(gs->chosen_entry_guards != NULL); @@ -4212,12 +4420,20 @@ entries_retry_all(const or_options_t *options) int guards_update_all(void) { - if (get_options()->UseDeprecatedGuardAlgorithm) { + int mark_circuits = 0; + if (update_guard_selection_choice(get_options())) + mark_circuits = 1; + + tor_assert(curr_guard_context); + + if (curr_guard_context->type == GS_TYPE_LEGACY) { entry_guards_compute_status(get_options(), approx_time()); - return 0; } else { - return entry_guards_update_all(get_guard_selection_info()); + if (entry_guards_update_all(get_guard_selection_info())) + mark_circuits = 1; } + + return mark_circuits; } /** Helper: pick a guard for a circuit, with whatever algorithm is diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index a0f4c2e3f1..0164667d22 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -194,6 +194,26 @@ struct entry_guard_t { guard_pathbias_t pb; }; +/** + * Possible rules for a guard selection to follow + */ +typedef enum guard_selection_type_t { + /** Infer the type of this selection from its name. */ + GS_TYPE_INFER=0, + /** Use the normal guard selection algorithm, taking our sample from the + * complete list of guards in the consensus. */ + GS_TYPE_NORMAL=1, + /** Use the normal guard selection algorithm, taking our sample from the + * configured bridges, and allowing it to grow as large as all the configured + * bridges */ + GS_TYPE_BRIDGE, + /** Use the normal guard selection algorithm, taking our sample from the + * set of filtered nodes. */ + GS_TYPE_RESTRICTED, + /** Use the legacy (pre-prop271) guard selection algorithm and fields */ + GS_TYPE_LEGACY, +} guard_selection_type_t; + /** * All of the the context for guard selection on a particular client. * @@ -212,6 +232,11 @@ struct guard_selection_s { */ char *name; + /** + * What rules does this guard-selection object follow? + */ + guard_selection_type_t type; + /** * A value of 1 means that primary_entry_guards is up-to-date; 0 * means we need to recalculate it before using primary_entry_guards @@ -340,6 +365,8 @@ int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, int entry_guard_state_should_expire(circuit_guard_state_t *guard_state); void entry_guards_note_internet_connectivity(guard_selection_t *gs); +int update_guard_selection_choice(const or_options_t *options); + /* Used by bridges.c only. */ void add_bridge_as_entry_guard(guard_selection_t *gs, const node_t *chosen); @@ -396,15 +423,17 @@ int num_bridges_usable(void); * If a circuit has been sitting around in 'waiting for better guard' state * for at least this long, we'll expire it. */ -#define DLFT_NONPRIMARY_GUARD_IDLE_TIMEOUT (10*60) +#define DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT (10*60) /** - * DOCDOC. not yet used; see prop271. + * If our configuration retains fewer than this fraction of guards from the + * torrc, we are in a restricted setting. */ -#define DFLT_MEANINGFUL_RESTRICTION_FRAC 0.2 +#define DFLT_MEANINGFUL_RESTRICTION_PERCENT 20 /** - * DOCDOC. not yet used. see prop271. + * If our configuration retains fewer than this fraction of guards from the + * torrc, we are in an extremely restricted setting, and should warn. */ -#define DFLT_EXTREME_RESTRICTION_FRAC 0.01 +#define DFLT_EXTREME_RESTRICTION_PERCENT 1 /**@}*/ STATIC double get_max_sample_threshold(void); @@ -416,13 +445,20 @@ STATIC int get_n_primary_guards(void); STATIC int get_internet_likely_down_interval(void); STATIC int get_nonprimary_guard_connect_timeout(void); STATIC int get_nonprimary_guard_idle_timeout(void); +STATIC double get_meaningful_restriction_threshold(void); +STATIC double get_extreme_restriction_threshold(void); // ---------- XXXX these functions and definitions are post-prop271. HANDLE_DECL(entry_guard, entry_guard_t, STATIC) -STATIC guard_selection_t *guard_selection_new(const char *name); +STATIC guard_selection_t *guard_selection_new(const char *name, + guard_selection_type_t type); STATIC guard_selection_t *get_guard_selection_by_name( - const char *name, int create_if_absent); + const char *name, guard_selection_type_t type, int create_if_absent); STATIC void guard_selection_free(guard_selection_t *gs); +STATIC const char *choose_guard_selection(const or_options_t *options, + const networkstatus_t *ns, + const char *old_selection, + guard_selection_type_t *type_out); STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs, const uint8_t *rsa_id); diff --git a/src/or/main.c b/src/or/main.c index 96ff442c68..25f8b1270c 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -980,8 +980,11 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs) /* if we have enough dir info, then update our guard status with * whatever we just learned. */ int invalidate_circs = guards_update_all(); - // This shouldn't be able to occur at this point. - tor_assert_nonfatal(! invalidate_circs); + + if (invalidate_circs) { + circuit_mark_all_unused_circs(); + circuit_mark_all_dirty_circs_as_unusable(); + } /* Don't even bother trying to get extrainfo until the rest of our * directory info is up-to-date */ diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index eaaadce152..4595e5d675 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -1243,30 +1243,30 @@ test_entry_guard_get_guard_selection_by_name(void *arg) (void)arg; guard_selection_t *gs1, *gs2, *gs3; - gs1 = get_guard_selection_by_name("unlikely", 0); + gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0); tt_assert(gs1 == NULL); - gs1 = get_guard_selection_by_name("unlikely", 1); + gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1); tt_assert(gs1 != NULL); - gs2 = get_guard_selection_by_name("unlikely", 1); + gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1); tt_assert(gs2 == gs1); - gs2 = get_guard_selection_by_name("unlikely", 0); + gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0); tt_assert(gs2 == gs1); - gs2 = get_guard_selection_by_name("implausible", 0); + gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0); tt_assert(gs2 == NULL); - gs2 = get_guard_selection_by_name("implausible", 1); + gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 1); tt_assert(gs2 != NULL); tt_assert(gs2 != gs1); - gs3 = get_guard_selection_by_name("implausible", 0); + gs3 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0); tt_assert(gs3 == gs2); - gs3 = get_guard_selection_by_name("default", 0); + gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0); tt_assert(gs3 == NULL); - gs3 = get_guard_selection_by_name("default", 1); + gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 1); tt_assert(gs3 != NULL); tt_assert(gs3 != gs2); tt_assert(gs3 != gs1); - tt_assert(gs3 == get_guard_selection_info()); + // XXXX prop271 re-enable this. tt_assert(gs3 == get_guard_selection_info()); #if 0 or_options_t *options = get_options_mutable(); @@ -1287,7 +1287,7 @@ static void test_entry_guard_add_single_guard(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); /* 1: Add a single guard to the sample. */ node_t *n1 = smartlist_get(big_fake_net_nodes, 0); @@ -1327,7 +1327,7 @@ static void test_entry_guard_node_filter(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); bridge_line_t *bl = NULL; /* Initialize a bunch of node objects that are all guards. */ @@ -1416,7 +1416,7 @@ static void test_entry_guard_expand_sample(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); digestmap_t *node_by_id = digestmap_new(); entry_guard_t *guard = entry_guards_expand_sample(gs); @@ -1510,7 +1510,7 @@ static void test_entry_guard_expand_sample_small_net(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); /* Fun corner case: not enough guards to make up our whole sample size. */ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, { @@ -1543,7 +1543,7 @@ test_entry_guard_update_from_consensus_status(void *arg) (void)arg; int i; time_t start = approx_time(); - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); networkstatus_t *ns_tmp = NULL; /* Don't randomly backdate stuff; it will make correctness harder to check.*/ @@ -1648,7 +1648,7 @@ test_entry_guard_update_from_consensus_repair(void *arg) (void)arg; int i; time_t start = approx_time(); - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); /* Don't randomly backdate stuff; it will make correctness harder to check.*/ MOCK(randomize_time, mock_randomize_time_no_randomization); @@ -1711,7 +1711,7 @@ test_entry_guard_update_from_consensus_remove(void *arg) (void)arg; //int i; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); smartlist_t *keep_ids = smartlist_new(); smartlist_t *remove_ids = smartlist_new(); @@ -1809,7 +1809,7 @@ test_entry_guard_confirming_guards(void *arg) (void)arg; /* Now let's check the logic responsible for manipulating the list * of confirmed guards */ - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); MOCK(randomize_time, mock_randomize_time_no_randomization); /* Create the sample. */ @@ -1879,7 +1879,7 @@ static void test_entry_guard_sample_reachable_filtered(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); entry_guards_expand_sample(gs); const int N = 10000; bitarray_t *selected = NULL; @@ -1950,7 +1950,7 @@ static void test_entry_guard_sample_reachable_filtered_empty(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); /* What if we try to sample from a set of 0? */ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, n->is_possible_guard = 0); @@ -1966,7 +1966,7 @@ static void test_entry_guard_retry_unreachable(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); entry_guards_expand_sample(gs); /* Let's say that we have two guards, and they're down. @@ -2025,7 +2025,7 @@ static void test_entry_guard_manage_primary(void *arg) { (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); smartlist_t *prev_guards = smartlist_new(); /* If no guards are confirmed, we should pick a few reachable guards and @@ -2146,7 +2146,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg) { /* Simpler cases: no gaurds are confirmed yet. */ (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); /* simple starting configuration */ entry_guards_update_primary(gs); @@ -2230,7 +2230,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg) guards, we use a confirmed guard. */ (void)arg; int i; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); const int N_CONFIRMED = 10; /* slightly more complicated simple starting configuration */ @@ -2307,7 +2307,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg) /* Play around with selecting primary guards for circuits and markign * them up and down */ (void)arg; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); time_t start = approx_time(); @@ -2426,7 +2426,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg) * primary, and we should get it next time. */ time_t start = approx_time(); - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); circuit_guard_state_t *guard = NULL; int i, r; const node_t *node = NULL; @@ -2488,7 +2488,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg) * primary, and we should get it next time. */ time_t start = approx_time(); - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); circuit_guard_state_t *guard = NULL, *guard2 = NULL; int i, r; const node_t *node = NULL; @@ -2566,7 +2566,7 @@ test_entry_guard_select_and_cancel(void *arg) int i,r; const node_t *node = NULL; circuit_guard_state_t *guard; - guard_selection_t *gs = guard_selection_new("default"); + guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL); entry_guard_t *g; /* Once more, we mark all the primary guards down. */ @@ -2624,7 +2624,8 @@ static void * upgrade_circuits_setup(const struct testcase_t *testcase) { upgrade_circuits_data_t *data = tor_malloc_zero(sizeof(*data)); - guard_selection_t *gs = data->gs = guard_selection_new("default"); + guard_selection_t *gs = data->gs = + guard_selection_new("default", GS_TYPE_NORMAL); circuit_guard_state_t *guard; const node_t *node; entry_guard_t *g; -- cgit v1.2.3-54-g00ecf