diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuitbuild.c | 83 | ||||
-rw-r--r-- | src/or/circuitbuild.h | 8 | ||||
-rw-r--r-- | src/or/circuituse.c | 21 | ||||
-rw-r--r-- | src/or/config.c | 20 | ||||
-rw-r--r-- | src/or/connection_edge.c | 14 | ||||
-rw-r--r-- | src/or/connection_or.c | 45 | ||||
-rw-r--r-- | src/or/connection_or.h | 2 | ||||
-rw-r--r-- | src/or/dirserv.c | 12 | ||||
-rw-r--r-- | src/or/dirvote.c | 279 | ||||
-rw-r--r-- | src/or/eventdns.c | 3 | ||||
-rw-r--r-- | src/or/geoip.c | 2 | ||||
-rw-r--r-- | src/or/main.c | 6 | ||||
-rw-r--r-- | src/or/ntmain.c | 3 | ||||
-rw-r--r-- | src/or/or.h | 16 | ||||
-rw-r--r-- | src/or/router.c | 27 | ||||
-rw-r--r-- | src/or/router.h | 2 | ||||
-rw-r--r-- | src/or/routerlist.c | 12 |
17 files changed, 455 insertions, 100 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index be435b950a..fde2e7f494 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -3228,8 +3228,6 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri, char buf[HEX_DIGEST_LEN+1]; int changed = 0; - tor_assert(options); - *reason = NULL; /* Do we want to mark this guard as bad? */ @@ -3487,9 +3485,8 @@ add_an_entry_guard(routerinfo_t *chosen, int reset_status) /** If the use of entry guards is configured, choose more entry guards * until we have enough in the list. */ static void -pick_entry_guards(void) +pick_entry_guards(or_options_t *options) { - or_options_t *options = get_options(); int changed = 0; tor_assert(entry_guards); @@ -3521,10 +3518,9 @@ entry_guard_free(entry_guard_t *e) * or which was selected by a version of Tor that's known to select * entry guards badly. */ static int -remove_obsolete_entry_guards(void) +remove_obsolete_entry_guards(time_t now) { int changed = 0, i; - time_t now = time(NULL); for (i = 0; i < smartlist_len(entry_guards); ++i) { entry_guard_t *entry = smartlist_get(entry_guards, i); @@ -3584,11 +3580,10 @@ remove_obsolete_entry_guards(void) * long that we don't think they'll come up again. Return 1 if we * removed any, or 0 if we did nothing. */ static int -remove_dead_entry_guards(void) +remove_dead_entry_guards(time_t now) { char dbuf[HEX_DIGEST_LEN+1]; char tbuf[ISO_TIME_LEN+1]; - time_t now = time(NULL); int i; int changed = 0; @@ -3623,23 +3618,18 @@ remove_dead_entry_guards(void) * think that things are unlisted. */ void -entry_guards_compute_status(void) +entry_guards_compute_status(or_options_t *options, time_t now) { - time_t now; int changed = 0; int severity = LOG_DEBUG; - or_options_t *options; digestmap_t *reasons; if (! entry_guards) return; - options = get_options(); if (options->EntryNodes) /* reshuffle the entry guard list if needed */ entry_nodes_should_be_added(); - now = time(NULL); - reasons = digestmap_new(); SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { @@ -3655,7 +3645,7 @@ entry_guards_compute_status(void) } SMARTLIST_FOREACH_END(entry); - if (remove_dead_entry_guards()) + if (remove_dead_entry_guards(now)) changed = 1; severity = changed ? LOG_DEBUG : LOG_INFO; @@ -3820,9 +3810,8 @@ entry_nodes_should_be_added(void) /** Add all nodes in EntryNodes that aren't currently guard nodes to the list * of guard nodes, at the front. */ static void -entry_guards_prepend_from_config(void) +entry_guards_prepend_from_config(or_options_t *options) { - or_options_t *options = get_options(); smartlist_t *entry_routers, *entry_fps; smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; tor_assert(entry_guards); @@ -3950,11 +3939,11 @@ choose_random_entry(cpath_build_state_t *state) entry_guards = smartlist_create(); if (should_add_entry_nodes) - entry_guards_prepend_from_config(); + entry_guards_prepend_from_config(options); if (!entry_list_is_constrained(options) && smartlist_len(entry_guards) < options->NumEntryGuards) - pick_entry_guards(); + pick_entry_guards(options); retry: smartlist_clear(live_entry_guards); @@ -4183,7 +4172,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) entry_guards_dirty = 0; /* XXX022 hand new_entry_guards to this func, and move it up a * few lines, so we don't have to re-dirty it */ - if (remove_obsolete_entry_guards()) + if (remove_obsolete_entry_guards(now)) entry_guards_dirty = 1; } digestmap_free(added_by, _tor_free); @@ -4488,9 +4477,8 @@ retry_bridge_descriptor_fetch_directly(const char *digest) * descriptor, fetch a new copy of its descriptor -- either directly * from the bridge or via a bridge authority. */ void -fetch_bridge_descriptors(time_t now) +fetch_bridge_descriptors(or_options_t *options, time_t now) { - or_options_t *options = get_options(); int num_bridge_auths = get_n_authorities(BRIDGE_AUTHORITY); int ask_bridge_directly; int can_use_bridge_authority; @@ -4570,6 +4558,10 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) add_an_entry_guard(ri, 1); log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname, from_cache ? "cached" : "fresh"); + /* set entry->made_contact so if it goes down we don't drop it from + * our entry node list */ + entry_guard_register_connect_status(ri->cache_info.identity_digest, + 1, 0, now); if (first) routerlist_retry_directory_downloads(now); } @@ -4610,48 +4602,63 @@ any_pending_bridge_descriptor_fetches(void) return 0; } -/** Return 1 if we have at least one descriptor for a bridge and - * all descriptors we know are down. Else return 0. If <b>act</b> is - * 1, then mark the down bridges up; else just observe and report. */ +/** Return 1 if we have at least one descriptor for an entry guard + * (bridge or member of EntryNodes) and all descriptors we know are + * down. Else return 0. If <b>act</b> is 1, then mark the down guards + * up; else just observe and report. */ static int -bridges_retry_helper(int act) +entries_retry_helper(or_options_t *options, int act) { routerinfo_t *ri; int any_known = 0; int any_running = 0; + int purpose = options->UseBridges ? + ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL; if (!entry_guards) entry_guards = smartlist_create(); SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { ri = router_get_by_digest(e->identity); - if (ri && ri->purpose == ROUTER_PURPOSE_BRIDGE) { + if (ri && ri->purpose == purpose) { any_known = 1; if (ri->is_running) - any_running = 1; /* some bridge is both known and running */ - else if (act) { /* mark it for retry */ - ri->is_running = 1; + any_running = 1; /* some entry is both known and running */ + else if (act) { + /* Mark all current connections to this OR as unhealthy, since + * otherwise there could be one that started 30 seconds + * ago, and in 30 seconds it will time out, causing us to mark + * the node down and undermine the retry attempt. We mark even + * the established conns, since if the network just came back + * we'll want to attach circuits to fresh conns. */ + connection_or_set_bad_connections(ri->cache_info.identity_digest, 1); + + /* mark this entry node for retry */ + router_set_status(ri->cache_info.identity_digest, 1); e->can_retry = 1; e->bad_since = 0; } } }); - log_debug(LD_DIR, "any_known %d, any_running %d", any_known, any_running); + log_debug(LD_DIR, "%d: any_known %d, any_running %d", + act, any_known, any_running); return any_known && !any_running; } -/** Do we know any descriptors for our bridges, and are they all - * down? */ +/** Do we know any descriptors for our bridges / entrynodes, and are + * all the ones we have descriptors for down? */ int -bridges_known_but_down(void) +entries_known_but_down(or_options_t *options) { - return bridges_retry_helper(0); + tor_assert(entry_list_is_constrained(options)); + return entries_retry_helper(options, 0); } -/** Mark all down known bridges up. */ +/** Mark all down known bridges / entrynodes up. */ void -bridges_retry_all(void) +entries_retry_all(or_options_t *options) { - bridges_retry_helper(1); + tor_assert(entry_list_is_constrained(options)); + entries_retry_helper(options, 1); } /** Release all storage held by the list of entry guards and related diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 7cc5c2877a..9a8e4c3879 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -50,7 +50,7 @@ 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 entry_guards_compute_status(void); +void entry_guards_compute_status(or_options_t *options, time_t now); int entry_guard_register_connect_status(const char *digest, int succeeded, int mark_relay_status, time_t now); void entry_nodes_should_be_added(void); @@ -69,12 +69,12 @@ learned_router_identity(tor_addr_t *addr, uint16_t port, const char *digest); void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest); void retry_bridge_descriptor_fetch_directly(const char *digest); -void fetch_bridge_descriptors(time_t now); +void fetch_bridge_descriptors(or_options_t *options, time_t now); void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); int any_bridge_descriptors_known(void); int any_pending_bridge_descriptor_fetches(void); -int bridges_known_but_down(void); -void bridges_retry_all(void); +int entries_known_but_down(or_options_t *options); +void entries_retry_all(or_options_t *options); void entry_guards_free_all(void); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index d9c16c139e..36dc1c1643 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -974,8 +974,19 @@ circuit_build_failed(origin_circuit_t *circ) * to blame, blame it. Also, avoid this relay for a while, and * fail any one-hop directory fetches destined for it. */ const char *n_conn_id = circ->cpath->extend_info->identity_digest; + int already_marked = 0; if (circ->_base.n_conn) { or_connection_t *n_conn = circ->_base.n_conn; + if (n_conn->is_bad_for_new_circs) { + /* We only want to blame this router when a fresh healthy + * connection fails. So don't mark this router as newly failed, + * since maybe this was just an old circuit attempt that's + * finally timing out now. Also, there's no need to blow away + * circuits/streams/etc, since the failure of an unhealthy conn + * doesn't tell us much about whether a healthy conn would + * succeed. */ + already_marked = 1; + } log_info(LD_OR, "Our circuit failed to get a response from the first hop " "(%s:%d). I'm going to try to rotate to a better connection.", @@ -985,7 +996,7 @@ circuit_build_failed(origin_circuit_t *circ) log_info(LD_OR, "Our circuit died before the first hop with no connection"); } - if (n_conn_id) { + if (n_conn_id && !already_marked) { entry_guard_register_connect_status(n_conn_id, 0, 1, time(NULL)); /* if there are any one-hop streams waiting on this circuit, fail * them now so they can retry elsewhere. */ @@ -1211,11 +1222,13 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, int severity = LOG_NOTICE; /* FFFF if this is a tunneled directory fetch, don't yell * as loudly. the user doesn't even know it's happening. */ - if (options->UseBridges && bridges_known_but_down()) { + if (entry_list_is_constrained(options) && + entries_known_but_down(options)) { log_fn(severity, LD_APP|LD_DIR, "Application request when we haven't used client functionality " - "lately. Optimistically trying known bridges again."); - bridges_retry_all(); + "lately. Optimistically trying known %s again.", + options->UseBridges ? "bridges" : "entrynodes"); + entries_retry_all(options); } else if (!options->UseBridges || any_bridge_descriptors_known()) { log_fn(severity, LD_APP|LD_DIR, "Application request when we haven't used client functionality " diff --git a/src/or/config.c b/src/or/config.c index 8febe7a56b..d66f9136b7 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -327,7 +327,7 @@ static config_var_t _option_vars[] = { V(RecommendedClientVersions, LINELIST, NULL), V(RecommendedServerVersions, LINELIST, NULL), OBSOLETE("RedirectExit"), - V(RefuseUnknownExits, BOOL, "0"), + V(RefuseUnknownExits, STRING, "auto"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), @@ -1231,6 +1231,18 @@ options_act(or_options_t *old_options) if (accounting_is_enabled(options)) configure_accounting(time(NULL)); + /* parse RefuseUnknownExits tristate */ + if (!strcmp(options->RefuseUnknownExits, "0")) + options->RefuseUnknownExits_ = 0; + else if (!strcmp(options->RefuseUnknownExits, "1")) + options->RefuseUnknownExits_ = 1; + else if (!strcmp(options->RefuseUnknownExits, "auto")) + options->RefuseUnknownExits_ = -1; + else { + /* Should have caught this in options_validate */ + return -1; + } + /* Change the cell EWMA settings */ cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus()); @@ -2997,6 +3009,12 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Failed to resolve/guess local address. See logs for details."); } + if (strcmp(options->RefuseUnknownExits, "0") && + strcmp(options->RefuseUnknownExits, "1") && + strcmp(options->RefuseUnknownExits, "auto")) { + REJECT("RefuseUnknownExits must be 0, 1, or auto"); + } + #ifndef MS_WINDOWS if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname)) REJECT("Can't use a relative path to torrc when RunAsDaemon is set."); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 6a3a5ef0a9..da0fc1856c 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -2488,6 +2488,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) char *address=NULL; uint16_t port; or_circuit_t *or_circ = NULL; + or_options_t *options = get_options(); assert_circuit_ok(circ); if (!CIRCUIT_IS_ORIGIN(circ)) @@ -2500,7 +2501,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) * that we have a stream connected to a circuit, and we don't connect to a * circuit until we have a pending/successful resolve. */ - if (!server_mode(get_options()) && + if (!server_mode(options) && circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay begin cell at non-server. Closing."); @@ -2533,19 +2534,16 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) tor_free(address); return 0; } - if (or_circ && or_circ->p_conn && !get_options()->AllowSingleHopExits && + if (or_circ && or_circ->p_conn && !options->AllowSingleHopExits && (or_circ->is_first_hop || (!connection_or_digest_is_known_relay( or_circ->p_conn->identity_digest) && -// XXX022 commented out so we can test it first in 0.2.2.11 -RD -// networkstatus_get_param(NULL, "refuseunknownexits", 1)))) { - get_options()->RefuseUnknownExits))) { + should_refuse_unknown_exits(options)))) { /* Don't let clients use us as a single-hop proxy, unless the user * has explicitly allowed that in the config. It attracts attackers * and users who'd be better off with, well, single-hop proxies. */ -// log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - log_notice(LD_PROTOCOL, + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Attempt by %s to open a stream %s. Closing.", safe_str(or_circ->p_conn->_base.address), or_circ->is_first_hop ? "on first hop of circuit" : @@ -2559,7 +2557,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) return 0; } } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) { - if (!directory_permits_begindir_requests(get_options()) || + if (!directory_permits_begindir_requests(options) || circ->purpose != CIRCUIT_PURPOSE_OR) { relay_send_end_cell_from_edge(rh.stream_id, circ, END_STREAM_REASON_NOTDIRECTORY, NULL); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 6b648b124d..09f310a3df 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -606,11 +606,24 @@ connection_or_get_for_extend(const char *digest, #define TIME_BEFORE_OR_CONN_IS_TOO_OLD (60*60*24*7) /** Given the head of the linked list for all the or_connections with a given - * identity, set elements of that list as is_bad_for_new_circs() as - * appropriate. Helper for connection_or_set_bad_connections(). + * identity, set elements of that list as is_bad_for_new_circs as + * appropriate. Helper for connection_or_set_bad_connections(). + * + * Specifically, we set the is_bad_for_new_circs flag on: + * - all connections if <b>force</b> is true. + * - all connections that are too old. + * - all open non-canonical connections for which a canonical connection + * exists to the same router. + * - all open canonical connections for which a 'better' canonical + * connection exists to the same router. + * - all open non-canonical connections for which a 'better' non-canonical + * connection exists to the same router at the same address. + * + * See connection_or_is_better() for our idea of what makes one OR connection + * better than another. */ static void -connection_or_group_set_badness(or_connection_t *head) +connection_or_group_set_badness(or_connection_t *head, int force) { or_connection_t *or_conn = NULL, *best = NULL; int n_old = 0, n_inprogress = 0, n_canonical = 0, n_other = 0; @@ -622,8 +635,9 @@ connection_or_group_set_badness(or_connection_t *head) if (or_conn->_base.marked_for_close || or_conn->is_bad_for_new_circs) continue; - if (or_conn->_base.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD - < now) { + if (force || + or_conn->_base.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD + < now) { log_info(LD_OR, "Marking OR conn to %s:%d as too old for new circuits " "(fd %d, %d secs old).", @@ -718,27 +732,20 @@ connection_or_group_set_badness(or_connection_t *head) } } -/** Go through all the OR connections, and set the is_bad_for_new_circs - * flag on: - * - all connections that are too old. - * - all open non-canonical connections for which a canonical connection - * exists to the same router. - * - all open canonical connections for which a 'better' canonical - * connection exists to the same router. - * - all open non-canonical connections for which a 'better' non-canonical - * connection exists to the same router at the same address. - * - * See connection_or_is_better() for our idea of what makes one OR connection - * better than another. +/** Go through all the OR connections (or if <b>digest</b> is non-NULL, just + * the OR connections with that digest), and set the is_bad_for_new_circs + * flag based on the rules in connection_or_group_set_badness() (or just + * always set it if <b>force</b> is true). */ void -connection_or_set_bad_connections(void) +connection_or_set_bad_connections(const char *digest, int force) { if (!orconn_identity_map) return; DIGESTMAP_FOREACH(orconn_identity_map, identity, or_connection_t *, conn) { - connection_or_group_set_badness(conn); + if (!digest || !memcmp(digest, conn->identity_digest, DIGEST_LEN)) + connection_or_group_set_badness(conn, force); } DIGESTMAP_FOREACH_END; } diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 717630217c..216a9bd648 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -18,7 +18,7 @@ or_connection_t *connection_or_get_for_extend(const char *digest, const tor_addr_t *target_addr, const char **msg_out, int *launch_out); -void connection_or_set_bad_connections(void); +void connection_or_set_bad_connections(const char *digest, int force); int connection_or_reached_eof(or_connection_t *conn); int connection_or_process_inbuf(or_connection_t *conn); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 3fcf1783d7..8ae03424a2 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1153,18 +1153,21 @@ directory_fetches_from_authorities(or_options_t *options) { routerinfo_t *me; uint32_t addr; + int refuseunknown; if (options->FetchDirInfoEarly) return 1; if (options->BridgeRelay == 1) return 0; if (server_mode(options) && router_pick_published_address(options, &addr)<0) return 1; /* we don't know our IP address; ask an authority. */ - if (options->DirPort == 0 && !options->RefuseUnknownExits) + refuseunknown = router_my_exit_policy_is_reject_star() && + should_refuse_unknown_exits(options); + if (options->DirPort == 0 && !refuseunknown) return 0; if (!server_mode(options) || !advertised_server_mode()) return 0; me = router_get_my_routerinfo(); - if (!me || (!me->dir_port && !options->RefuseUnknownExits)) + if (!me || (!me->dir_port && !refuseunknown)) return 0; /* if dirport not advertised, return 0 too */ return 1; } @@ -1208,7 +1211,10 @@ directory_caches_dir_info(or_options_t *options) return 1; if (!server_mode(options) || !advertised_server_mode()) return 0; - return options->RefuseUnknownExits; + /* We need an up-to-date view of network info if we're going to try to + * block exit attempts from unknown relays. */ + return router_my_exit_policy_is_reject_star() && + should_refuse_unknown_exits(options); } /** Return 1 if we want to allow remote people to ask us directory diff --git a/src/or/dirvote.c b/src/or/dirvote.c index eae3bc8a40..dd36a0f911 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -50,7 +50,7 @@ static int dirvote_publish_consensus(void); static char *make_consensus_method_list(int low, int high, const char *sep); /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 9 +#define MAX_SUPPORTED_CONSENSUS_METHOD 10 /** Lowest consensus method that contains a 'directory-footer' marker */ #define MIN_METHOD_FOR_FOOTER 9 @@ -766,15 +766,275 @@ networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg, if (berr) { log_info(LD_DIR, "Bw weight mismatch %d. G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d", berr, I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg); } return berr; } +/** + * This function computes the bandwidth weights for consensus method 10. + * + * It returns true if weights could be computed, false otherwise. + */ +static int +networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, + int64_t M, int64_t E, int64_t D, + int64_t T, int64_t weight_scale) +{ + bw_weights_error_t berr = 0; + int64_t Wgg = -1, Wgd = -1; + int64_t Wmg = -1, Wme = -1, Wmd = -1; + int64_t Wed = -1, Wee = -1; + const char *casename; + char buf[512]; + int r; + + if (G <= 0 || M <= 0 || E <= 0 || D <= 0) { + log_warn(LD_DIR, "Consensus with empty bandwidth: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT + " D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + return 0; + } + + /* + * Computed from cases in 3.4.3 of dir-spec.txt + * + * 1. Neither are scarce + * 2. Both Guard and Exit are scarce + * a. R+D <= S + * b. R+D > S + * 3. One of Guard or Exit is scarce + * a. S+D < T/3 + * b. S+D >= T/3 + */ + if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3 + /* Case 1: Neither are scarce. */ + casename = "Case 1 (Wgd=Wmd=Wed)"; + Wgd = weight_scale/3; + Wed = weight_scale/3; + Wmd = weight_scale/3; + Wee = (weight_scale*(E+G+M))/(3*E); + Wme = weight_scale - Wee; + Wmg = (weight_scale*(2*G-E-M))/(3*G); + Wgg = weight_scale - Wmg; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + + if (berr) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3 + int64_t R = MIN(E, G); + int64_t S = MAX(E, G); + /* + * Case 2: Both Guards and Exits are scarce + * Balance D between E and G, depending upon + * D capacity and scarcity. + */ + if (R+D < S) { // Subcase a + Wgg = weight_scale; + Wee = weight_scale; + Wmg = 0; + Wme = 0; + Wmd = 0; + if (E < G) { + casename = "Case 2a (E scarce)"; + Wed = weight_scale; + Wgd = 0; + } else { /* E >= G */ + casename = "Case 2a (G scarce)"; + Wed = 0; + Wgd = weight_scale; + } + } else { // Subcase b: R+D >= S + casename = "Case 2b1 (Wgg=1, Wmd=Wgd)"; + Wee = (weight_scale*(E - G + M))/E; + Wed = (weight_scale*(D - 2*E + 4*G - 2*M))/(3*D); + Wme = (weight_scale*(G-M))/E; + Wmg = 0; + Wgg = weight_scale; + Wmd = (weight_scale - Wed)/2; + Wgd = (weight_scale - Wed)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed, + weight_scale, G, M, E, D, T, 10, 1); + + if (berr) { + casename = "Case 2b2 (Wgg=1, Wee=1)"; + Wgg = weight_scale; + Wee = weight_scale; + Wed = (weight_scale*(D - 2*E + G + M))/(3*D); + Wmd = (weight_scale*(D - 2*M + G + E))/(3*D); + Wme = 0; + Wmg = 0; + + if (Wmd < 0) { // Can happen if M > T/3 + casename = "Case 2b3 (Wmd=0)"; + Wmd = 0; + log_warn(LD_DIR, + "Too much Middle bandwidth on the network to calculate " + "balanced bandwidth-weights. Consider increasing the " + "number of Guard nodes by lowering the requirements."); + } + Wgd = weight_scale - Wed - Wmd; + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr != BW_WEIGHTS_NO_ERROR && + berr != BW_WEIGHTS_BALANCE_MID_ERROR) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } + } else { // if (E < T/3 || G < T/3) { + int64_t S = MIN(E, G); + // Case 3: Exactly one of Guard or Exit is scarce + if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) { + log_warn(LD_BUG, + "Bw-Weights Case 3 v10 but with G="I64_FORMAT" M=" + I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + } + + if (3*(S+D) < T) { // Subcase a: S+D < T/3 + if (G < E) { + casename = "Case 3a (G scarce)"; + Wgg = Wgd = weight_scale; + Wmd = Wed = Wmg = 0; + // Minor subcase, if E is more scarce than M, + // keep its bandwidth in place. + if (E < M) Wme = 0; + else Wme = (weight_scale*(E-M))/(2*E); + Wee = weight_scale-Wme; + } else { // G >= E + casename = "Case 3a (E scarce)"; + Wee = Wed = weight_scale; + Wmd = Wgd = Wme = 0; + // Minor subcase, if G is more scarce than M, + // keep its bandwidth in place. + if (G < M) Wmg = 0; + else Wmg = (weight_scale*(G-M))/(2*G); + Wgg = weight_scale-Wmg; + } + } else { // Subcase b: S+D >= T/3 + // D != 0 because S+D >= T/3 + if (G < E) { + casename = "Case 3bg (G scarce, Wgg=1, Wmd == Wed)"; + Wgg = weight_scale; + Wgd = (weight_scale*(D - 2*G + E + M))/(3*D); + Wmg = 0; + Wee = (weight_scale*(E+M))/(2*E); + Wme = weight_scale - Wee; + Wmd = (weight_scale - Wgd)/2; + Wed = (weight_scale - Wgd)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } else { // G >= E + casename = "Case 3be (E scarce, Wee=1, Wmd == Wgd)"; + Wee = weight_scale; + Wed = (weight_scale*(D - 2*E + G + M))/(3*D); + Wme = 0; + Wgg = (weight_scale*(G+M))/(2*G); + Wmg = weight_scale - Wgg; + Wmd = (weight_scale - Wed)/2; + Wgd = (weight_scale - Wed)/2; + + berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, + Wed, weight_scale, G, M, E, D, T, 10, 1); + } + if (berr) { + log_warn(LD_DIR, + "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT + " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" + " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", + berr, casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, + (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); + return 0; + } + } + } + + /* We cast down the weights to 32 bit ints on the assumption that + * weight_scale is ~= 10000. We need to ensure a rogue authority + * doesn't break this assumption to rig our weights */ + tor_assert(0 < weight_scale && weight_scale < INT32_MAX); + + /* + * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine + * that middle nodes need different bandwidth weights for dirport traffic, + * or that weird exit policies need special weight, or that bridges + * need special weight. + * + * NOTE: This list is sorted. + */ + r = tor_snprintf(buf, sizeof(buf), + "bandwidth-weights Wbd=%d Wbe=%d Wbg=%d Wbm=%d " + "Wdb=%d " + "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d " + "Wgb=%d Wgd=%d Wgg=%d Wgm=%d " + "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n", + (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale, + (int)weight_scale, + (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee, + (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg, + (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale); + if (r<0) { + log_warn(LD_BUG, + "Not enough space in buffer for bandwidth-weights line."); + *buf = '\0'; + return 0; + } + smartlist_add(chunks, tor_strdup(buf)); + + log_notice(LD_CIRC, "Computed bandwidth weights for %s with v10: " + "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT + " T="I64_FORMAT, + casename, + I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), + I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + return 1; +} +/** + * This function computes the bandwidth weights for consensus method 9. + * + * It has been obsoleted in favor of consensus method 10. + */ static void networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M, int64_t E, int64_t D, int64_t T, @@ -1064,7 +1324,7 @@ networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M, *buf = '\0'; } smartlist_add(chunks, tor_strdup(buf)); - log_notice(LD_CIRC, "Computed bandwidth weights for %s: " + log_notice(LD_CIRC, "Computed bandwidth weights for %s with v9: " "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT " T="I64_FORMAT, casename, @@ -1101,6 +1361,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const routerstatus_format_type_t rs_format = flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC; char *params = NULL; + int added_weights = 0; tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC); tor_assert(total_authorities >= smartlist_len(votes)); @@ -1783,7 +2044,13 @@ networkstatus_compute_consensus(smartlist_t *votes, } } - networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale); + if (consensus_method < 10) { + networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale); + added_weights = 1; + } else { + added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, + T, weight_scale); + } } /* Add a signature. */ @@ -1873,7 +2140,7 @@ networkstatus_compute_consensus(smartlist_t *votes, return NULL; } // Verify balancing parameters - if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) { + if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) { networkstatus_verify_bw_weights(c); } networkstatus_vote_free(c); diff --git a/src/or/eventdns.c b/src/or/eventdns.c index 8ebfb79353..b929303fd5 100644 --- a/src/or/eventdns.c +++ b/src/or/eventdns.c @@ -3131,8 +3131,7 @@ load_nameservers_with_getnetworkparams(void) IP_ADDR_STRING *ns; GetNetworkParams_fn_t fn; - /* XXXX Possibly, we should hardcode the location of this DLL. */ - if (!(handle = LoadLibrary(TEXT("iphlpapi.dll")))) { + if (!(handle = load_windows_system_library(TEXT("iphlpapi.dll")))) { log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); /* right now status = 0, doesn't that mean "good" - mikec */ status = -1; diff --git a/src/or/geoip.c b/src/or/geoip.c index 7f1052e98d..ee8d72ee1d 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -254,6 +254,8 @@ geoip_get_country_by_ip(uint32_t ipaddr) int geoip_get_n_countries(void) { + if (!geoip_countries) + init_geoip_countries(); return (int) smartlist_len(geoip_countries); } diff --git a/src/or/main.c b/src/or/main.c index 477a274d54..582a1c287b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -710,7 +710,7 @@ directory_info_has_arrived(time_t now, int from_cache) /* if we have enough dir info, then update our guard status with * whatever we just learned. */ - entry_guards_compute_status(); + entry_guards_compute_status(options, now); /* Don't even bother trying to get extrainfo until the rest of our * directory info is up-to-date */ if (options->DownloadExtraInfo) @@ -912,7 +912,7 @@ run_scheduled_events(time_t now) update_router_descriptor_downloads(now); update_extrainfo_downloads(now); if (options->UseBridges) - fetch_bridge_descriptors(now); + fetch_bridge_descriptors(options, now); if (router_have_minimum_dir_info()) time_to_try_getting_descriptors = now + LAZY_DESCRIPTOR_RETRY_INTERVAL; else @@ -1173,7 +1173,7 @@ run_scheduled_events(time_t now) circuit_expire_old_circuits_serverside(now); /** 5. We do housekeeping for each connection... */ - connection_or_set_bad_connections(); + connection_or_set_bad_connections(NULL, 0); for (i=0;i<smartlist_len(connection_array);i++) { run_connection_housekeeping(i, now); } diff --git a/src/or/ntmain.c b/src/or/ntmain.c index 0b611f0bf1..46e7afb78b 100644 --- a/src/or/ntmain.c +++ b/src/or/ntmain.c @@ -138,8 +138,7 @@ nt_service_loadlibrary(void) if (service_fns.loaded) return; - /* XXXX Possibly, we should hardcode the location of this DLL. */ - if (!(library = LoadLibrary(TEXT("advapi32.dll")))) { + if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) { log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use " "NT services on Windows 98? That doesn't work."); goto err; diff --git a/src/or/or.h b/src/or/or.h index 2399ecff39..69b0d6be29 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1047,7 +1047,10 @@ typedef struct or_connection_t { * NETINFO cell listed the address we're connected to as recognized. */ unsigned int is_canonical:1; /** True iff this connection shouldn't get any new circs attached to it, - * because the connection is too old, or because there's a better one, etc. + * because the connection is too old, or because there's a better one. + * More generally, this flag is used to note an unhealthy connection; + * for example, if a bad connection fails we shouldn't assume that the + * router itself has a problem. */ unsigned int is_bad_for_new_circs:1; uint8_t link_proto; /**< What protocol version are we using? 0 for @@ -2472,10 +2475,13 @@ typedef struct { int ConstrainedSockets; /**< Shrink xmit and recv socket buffers. */ uint64_t ConstrainedSockSize; /**< Size of constrained buffers. */ - /** Whether we should drop exit streams from Tors that we don't know - * are relays. XXX022 In here for 0.2.2.11 as a temporary test before - * we switch over to putting it in consensusparams. -RD */ - int RefuseUnknownExits; + /** Whether we should drop exit streams from Tors that we don't know are + * relays. One of "0" (never refuse), "1" (always refuse), or "auto" (do + * what the consensus says, defaulting to 'refuse' if the consensus says + * nothing). */ + char *RefuseUnknownExits; + /** Parsed version of RefuseUnknownExits. -1 for auto. */ + int RefuseUnknownExits_; /** Application ports that require all nodes in circ to have sufficient * uptime. */ diff --git a/src/or/router.c b/src/or/router.c index 978078bf78..621cbaace5 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -18,6 +18,7 @@ #include "geoip.h" #include "hibernate.h" #include "main.h" +#include "networkstatus.h" #include "policies.h" #include "relay.h" #include "rephist.h" @@ -975,6 +976,19 @@ server_mode(or_options_t *options) return (options->ORPort != 0 || options->ORListenAddress); } +/** Return true iff the combination of options in <b>options</b> and parameters + * in the consensus mean that we don't want to allow exits from circuits + * we got from addresses not known to be servers. */ +int +should_refuse_unknown_exits(or_options_t *options) +{ + if (options->RefuseUnknownExits_ != -1) { + return options->RefuseUnknownExits_; + } else { + return networkstatus_get_param(NULL, "refuseunknownexits", 1); + } +} + /** Remember if we've advertised ourselves to the dirservers. */ static int server_is_advertised=0; @@ -1137,6 +1151,17 @@ router_compare_to_my_exit_policy(edge_connection_t *conn) desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; } +/** Return true iff my exit policy is reject *:*. Return -1 if we don't + * have a descriptor */ +int +router_my_exit_policy_is_reject_star(void) +{ + if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */ + return -1; + + return desc_routerinfo->policy_is_reject_star; +} + /** Return true iff I'm a server and <b>digest</b> is equal to * my identity digest. */ int @@ -1300,6 +1325,8 @@ router_rebuild_descriptor(int force) policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy, options->ExitPolicyRejectPrivate, ri->address, !options->BridgeRelay); + ri->policy_is_reject_star = + policy_is_reject_star(ri->exit_policy); if (desc_routerinfo) { /* inherit values */ ri->is_valid = desc_routerinfo->is_valid; diff --git a/src/or/router.h b/src/or/router.h index d90a7cff90..c17fc78bd0 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -51,6 +51,7 @@ int server_mode(or_options_t *options); int advertised_server_mode(void); int proxy_mode(or_options_t *options); void consider_publishable_server(int force); +int should_refuse_unknown_exits(or_options_t *options); void router_upload_dir_desc_to_dirservers(int force); void mark_my_descriptor_dirty_if_older_than(time_t when); @@ -60,6 +61,7 @@ void check_descriptor_ipaddress_changed(time_t now); void router_new_address_suggestion(const char *suggestion, const dir_connection_t *d_conn); int router_compare_to_my_exit_policy(edge_connection_t *conn); +int router_my_exit_policy_is_reject_star(void); routerinfo_t *router_get_my_routerinfo(void); extrainfo_t *router_get_my_extrainfo(void); const char *router_get_my_descriptor(void); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 5fb4fe13c2..a6ca03cde3 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1610,6 +1610,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl, double *bandwidths; double tmp = 0; unsigned int i; + int have_unknown = 0; /* true iff sl contains element not in consensus. */ /* Can't choose exit and guard at same time */ tor_assert(rule == NO_WEIGHTING || @@ -1726,6 +1727,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl, this_bw = kb_to_bytes(rs->bandwidth); } else { /* bridge or other descriptor not in our consensus */ this_bw = router_get_advertised_bandwidth_capped(router); + have_unknown = 1; } if (router_digest_is_me(router->cache_info.identity_digest)) is_me = 1; @@ -1756,9 +1758,11 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl, /* If there is no bandwidth, choose at random */ if (DBL_TO_U64(weighted_bw) == 0) { - log_warn(LD_CIRC, - "Weighted bandwidth is %lf in node selection for rule %s", - weighted_bw, bandwidth_weight_rule_to_string(rule)); + /* Don't warn when using bridges/relays not in the consensus */ + if (!have_unknown) + log_warn(LD_CIRC, + "Weighted bandwidth is %lf in node selection for rule %s", + weighted_bw, bandwidth_weight_rule_to_string(rule)); tor_free(bandwidths); return smartlist_choose(sl); } @@ -4782,7 +4786,7 @@ update_router_have_minimum_dir_info(void) count_usable_descriptors(&num_present, &num_usable, consensus, options, now, options->EntryNodes); - if (num_usable && (num_present == 0)) { + if (!num_usable || !num_present) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable entry node descriptors.", num_present, num_usable); |