|
@@ -0,0 +1,529 @@
|
|
|
+Filename: 156-tracking-blocked-ports.txt
|
|
|
+Title: Tracking blocked ports on the client side
|
|
|
+Version: $Revision$
|
|
|
+Last-Modified: $Date$
|
|
|
+Author: Robert Hogan
|
|
|
+Created: 14-Oct-2008
|
|
|
+Status: Open
|
|
|
+Target: 0.2.?
|
|
|
+
|
|
|
+Motivation:
|
|
|
+Tor clients that are behind extremely restrictive firewalls can end up
|
|
|
+waiting a while for their first successful OR connection to a node on the
|
|
|
+network. Worse, the more restrictive their firewall the more susceptible
|
|
|
+they are to an attacker guessing their entry nodes. Tor routers that
|
|
|
+are behind extremely restrictive firewalls can only offer a limited,
|
|
|
+'partitioned' service to other routers and clients on the network. Exit
|
|
|
+nodes behind extremely restrictive firewalls may advertise ports that they
|
|
|
+are actually not able to connect to, wasting network resources in circuit
|
|
|
+constructions that are doomed to fail at the last hop on first use.
|
|
|
+
|
|
|
+Proposal:
|
|
|
+
|
|
|
+When a client attempts to connect to an entry guard it should avoid
|
|
|
+further attempts on ports that fail once until it has connected to at
|
|
|
+least one entry guard successfully. (Maybe it should wait for more than
|
|
|
+one failure to reduce the skew on the first node selection.) Thereafter
|
|
|
+it should select entry guards regardless of port and warn the user if
|
|
|
+it observes that connections to a given port have failed every multiple
|
|
|
+of 5 times without success or since the last success.
|
|
|
+
|
|
|
+Tor should warn the operators of exit, middleman and entry nodes if it
|
|
|
+observes that connections to a given port have failed a multiple of 5
|
|
|
+times without success or since the last success. If attempts on a port
|
|
|
+fail 20 or more times without or since success, Tor should add the port
|
|
|
+to a 'blocked-ports' entry in its descriptor's extra-info. Some thought
|
|
|
+needs to be given to what the authorities might do with this information.
|
|
|
+
|
|
|
+Related TODO item:
|
|
|
+ "- Automatically determine what ports are reachable and start using
|
|
|
+ those, if circuits aren't working and it's a pattern we
|
|
|
+ recognize ("port 443 worked once and port 9001 keeps not
|
|
|
+ working")."
|
|
|
+
|
|
|
+
|
|
|
+I've had a go at implementing all of this in the attached.
|
|
|
+
|
|
|
+Addendum:
|
|
|
+Just a note on the patch, storing the digest of each router that uses the port
|
|
|
+is a bit of a memory hog, and its only real purpose is to provide a count of
|
|
|
+routers using that port when warning the user. That could be achieved when
|
|
|
+warning the user by iterating through the routerlist instead.
|
|
|
+
|
|
|
+Index: src/or/connection_or.c
|
|
|
+===================================================================
|
|
|
+--- src/or/connection_or.c (revision 17104)
|
|
|
++++ src/or/connection_or.c (working copy)
|
|
|
+@@ -502,6 +502,9 @@
|
|
|
+ connection_or_connect_failed(or_connection_t *conn,
|
|
|
+ int reason, const char *msg)
|
|
|
+ {
|
|
|
++ if ((reason == END_OR_CONN_REASON_NO_ROUTE) ||
|
|
|
++ (reason == END_OR_CONN_REASON_REFUSED))
|
|
|
++ or_port_hist_failure(conn->identity_digest,TO_CONN(conn)->port);
|
|
|
+ control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason);
|
|
|
+ if (!authdir_mode_tests_reachability(get_options()))
|
|
|
+ control_event_bootstrap_problem(msg, reason);
|
|
|
+@@ -580,6 +583,7 @@
|
|
|
+ /* already marked for close */
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
++
|
|
|
+ return conn;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -909,6 +913,7 @@
|
|
|
+ control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0);
|
|
|
+
|
|
|
+ if (started_here) {
|
|
|
++ or_port_hist_success(TO_CONN(conn)->port);
|
|
|
+ rep_hist_note_connect_succeeded(conn->identity_digest, now);
|
|
|
+ if (entry_guard_register_connect_status(conn->identity_digest,
|
|
|
+ 1, now) < 0) {
|
|
|
+Index: src/or/rephist.c
|
|
|
+===================================================================
|
|
|
+--- src/or/rephist.c (revision 17104)
|
|
|
++++ src/or/rephist.c (working copy)
|
|
|
+@@ -18,6 +18,7 @@
|
|
|
+ static void bw_arrays_init(void);
|
|
|
+ static void predicted_ports_init(void);
|
|
|
+ static void hs_usage_init(void);
|
|
|
++static void or_port_hist_init(void);
|
|
|
+
|
|
|
+ /** Total number of bytes currently allocated in fields used by rephist.c. */
|
|
|
+ uint64_t rephist_total_alloc=0;
|
|
|
+@@ -89,6 +90,25 @@
|
|
|
+ digestmap_t *link_history_map;
|
|
|
+ } or_history_t;
|
|
|
+
|
|
|
++/** or_port_hist_t contains our router/client's knowledge of
|
|
|
++ all OR ports offered on the network, and how many servers with each port we
|
|
|
++ have succeeded or failed to connect to. */
|
|
|
++typedef struct {
|
|
|
++ /** The port this entry is tracking. */
|
|
|
++ uint16_t or_port;
|
|
|
++ /** Have we ever connected to this port on another OR?. */
|
|
|
++ unsigned int success:1;
|
|
|
++ /** The ORs using this port. */
|
|
|
++ digestmap_t *ids;
|
|
|
++ /** The ORs using this port we have failed to connect to. */
|
|
|
++ digestmap_t *failure_ids;
|
|
|
++ /** Are we excluding ORs with this port during entry selection?*/
|
|
|
++ unsigned int excluded;
|
|
|
++} or_port_hist_t;
|
|
|
++
|
|
|
++static unsigned int still_searching = 0;
|
|
|
++static smartlist_t *or_port_hists;
|
|
|
++
|
|
|
+ /** When did we last multiply all routers' weighted_run_length and
|
|
|
+ * total_run_weights by STABILITY_ALPHA? */
|
|
|
+ static time_t stability_last_downrated = 0;
|
|
|
+@@ -164,6 +184,16 @@
|
|
|
+ tor_free(hist);
|
|
|
+ }
|
|
|
+
|
|
|
++/** Helper: free storage held by a single OR port history entry. */
|
|
|
++static void
|
|
|
++or_port_hist_free(or_port_hist_t *p)
|
|
|
++{
|
|
|
++ tor_assert(p);
|
|
|
++ digestmap_free(p->ids,NULL);
|
|
|
++ digestmap_free(p->failure_ids,NULL);
|
|
|
++ tor_free(p);
|
|
|
++}
|
|
|
++
|
|
|
+ /** Update an or_history_t object <b>hist</b> so that its uptime/downtime
|
|
|
+ * count is up-to-date as of <b>when</b>.
|
|
|
+ */
|
|
|
+@@ -1639,7 +1669,7 @@
|
|
|
+ tmp_time = smartlist_get(predicted_ports_times, i);
|
|
|
+ if (*tmp_time + PREDICTED_CIRCS_RELEVANCE_TIME < now) {
|
|
|
+ tmp_port = smartlist_get(predicted_ports_list, i);
|
|
|
+- log_debug(LD_CIRC, "Expiring predicted port %d", *tmp_port);
|
|
|
++ log_debug(LD_HIST, "Expiring predicted port %d", *tmp_port);
|
|
|
+ smartlist_del(predicted_ports_list, i);
|
|
|
+ smartlist_del(predicted_ports_times, i);
|
|
|
+ rephist_total_alloc -= sizeof(uint16_t)+sizeof(time_t);
|
|
|
+@@ -1821,6 +1851,12 @@
|
|
|
+ tor_free(last_stability_doc);
|
|
|
+ built_last_stability_doc_at = 0;
|
|
|
+ predicted_ports_free();
|
|
|
++ if (or_port_hists) {
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, p,
|
|
|
++ or_port_hist_free(p));
|
|
|
++ smartlist_free(or_port_hists);
|
|
|
++ or_port_hists = NULL;
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /****************** hidden service usage statistics ******************/
|
|
|
+@@ -2356,3 +2392,225 @@
|
|
|
+ tor_free(fname);
|
|
|
+ }
|
|
|
+
|
|
|
++/** Create a new entry in the port tracking cache for the or_port in
|
|
|
++ * <b>ri</b>. */
|
|
|
++void
|
|
|
++or_port_hist_new(const routerinfo_t *ri)
|
|
|
++{
|
|
|
++ or_port_hist_t *result;
|
|
|
++ const char *id=ri->cache_info.identity_digest;
|
|
|
++
|
|
|
++ if (!or_port_hists)
|
|
|
++ or_port_hist_init();
|
|
|
++
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ /* Cope with routers that change their advertised OR port or are
|
|
|
++ dropped from the networkstatus. We don't discard the failures of
|
|
|
++ dropped routers because they are still valid when counting
|
|
|
++ consecutive failures on a port.*/
|
|
|
++ if (digestmap_get(tp->ids, id) && (tp->or_port != ri->or_port)) {
|
|
|
++ digestmap_remove(tp->ids, id);
|
|
|
++ }
|
|
|
++ if (tp->or_port == ri->or_port) {
|
|
|
++ if (!(digestmap_get(tp->ids, id)))
|
|
|
++ digestmap_set(tp->ids, id, (void*)1);
|
|
|
++ return;
|
|
|
++ }
|
|
|
++ });
|
|
|
++
|
|
|
++ result = tor_malloc_zero(sizeof(or_port_hist_t));
|
|
|
++ result->or_port=ri->or_port;
|
|
|
++ result->success=0;
|
|
|
++ result->ids=digestmap_new();
|
|
|
++ digestmap_set(result->ids, id, (void*)1);
|
|
|
++ result->failure_ids=digestmap_new();
|
|
|
++ result->excluded=0;
|
|
|
++ smartlist_add(or_port_hists, result);
|
|
|
++}
|
|
|
++
|
|
|
++/** Create the port tracking cache. */
|
|
|
++/*XXX: need to call this when we rebuild/update our network status */
|
|
|
++static void
|
|
|
++or_port_hist_init(void)
|
|
|
++{
|
|
|
++ routerlist_t *rl = router_get_routerlist();
|
|
|
++
|
|
|
++ if (!or_port_hists)
|
|
|
++ or_port_hists=smartlist_create();
|
|
|
++
|
|
|
++ if (rl && rl->routers) {
|
|
|
++ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri,
|
|
|
++ {
|
|
|
++ or_port_hist_new(ri);
|
|
|
++ });
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
++#define NOT_BLOCKED 0
|
|
|
++#define FAILURES_OBSERVED 1
|
|
|
++#define POSSIBLY_BLOCKED 5
|
|
|
++#define PROBABLY_BLOCKED 10
|
|
|
++/** Return the list of blocked ports for our router's extra-info.*/
|
|
|
++char *
|
|
|
++or_port_hist_get_blocked_ports(void)
|
|
|
++{
|
|
|
++ char blocked_ports[2048];
|
|
|
++ char *bp;
|
|
|
++
|
|
|
++ tor_snprintf(blocked_ports,sizeof(blocked_ports),"blocked-ports");
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ if (digestmap_size(tp->failure_ids) >= PROBABLY_BLOCKED)
|
|
|
++ tor_snprintf(blocked_ports+strlen(blocked_ports),
|
|
|
++ sizeof(blocked_ports)," %u,",tp->or_port);
|
|
|
++ });
|
|
|
++ if (strlen(blocked_ports) == 13)
|
|
|
++ return NULL;
|
|
|
++ bp=tor_strdup(blocked_ports);
|
|
|
++ bp[strlen(bp)-1]='\n';
|
|
|
++ bp[strlen(bp)]='\0';
|
|
|
++ return bp;
|
|
|
++}
|
|
|
++
|
|
|
++/** Revert to client-only mode if we have seen to many failures on a port or
|
|
|
++ * range of ports.*/
|
|
|
++static void
|
|
|
++or_port_hist_report_block(unsigned int min_severity)
|
|
|
++{
|
|
|
++ or_options_t *options=get_options();
|
|
|
++ char failures_observed[2048],possibly_blocked[2048],probably_blocked[2048];
|
|
|
++ char port[1024];
|
|
|
++
|
|
|
++ memset(failures_observed,0,sizeof(failures_observed));
|
|
|
++ memset(possibly_blocked,0,sizeof(possibly_blocked));
|
|
|
++ memset(probably_blocked,0,sizeof(probably_blocked));
|
|
|
++
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ unsigned int failures = digestmap_size(tp->failure_ids);
|
|
|
++ if (failures >= min_severity) {
|
|
|
++ tor_snprintf(port, sizeof(port), " %u (%u failures %s out of %u on the"
|
|
|
++ " network)",tp->or_port,failures,
|
|
|
++ (!tp->success)?"and no successes": "since last success",
|
|
|
++ digestmap_size(tp->ids));
|
|
|
++ if (failures >= PROBABLY_BLOCKED) {
|
|
|
++ strlcat(probably_blocked, port, sizeof(probably_blocked));
|
|
|
++ } else if (failures >= POSSIBLY_BLOCKED)
|
|
|
++ strlcat(possibly_blocked, port, sizeof(possibly_blocked));
|
|
|
++ else if (failures >= FAILURES_OBSERVED)
|
|
|
++ strlcat(failures_observed, port, sizeof(failures_observed));
|
|
|
++ }
|
|
|
++ });
|
|
|
++
|
|
|
++ log_warn(LD_HIST,"%s%s%s%s%s%s%s%s",
|
|
|
++ server_mode(options) &&
|
|
|
++ ((min_severity==FAILURES_OBSERVED) || strlen(probably_blocked))?
|
|
|
++ "You should consider disabling your Tor server.":"",
|
|
|
++ (min_severity==FAILURES_OBSERVED)?
|
|
|
++ "Tor appears to be blocked from connecting to a range of ports "
|
|
|
++ "with the result that it cannot connect to one tenth of the Tor "
|
|
|
++ "network. ":"",
|
|
|
++ strlen(failures_observed)?
|
|
|
++ "Tor has observed failures on the following ports: ":"",
|
|
|
++ failures_observed,
|
|
|
++ strlen(possibly_blocked)?
|
|
|
++ "Tor is possibly blocked on the following ports: ":"",
|
|
|
++ possibly_blocked,
|
|
|
++ strlen(probably_blocked)?
|
|
|
++ "Tor is almost certainly blocked on the following ports: ":"",
|
|
|
++ probably_blocked);
|
|
|
++
|
|
|
++}
|
|
|
++
|
|
|
++/** Record the success of our connection to <b>digest</b>'s
|
|
|
++ * OR port. */
|
|
|
++void
|
|
|
++or_port_hist_success(uint16_t or_port)
|
|
|
++{
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ if (tp->or_port != or_port)
|
|
|
++ continue;
|
|
|
++ /*Reset our failure stats so we can notice if this port ever gets
|
|
|
++ blocked again.*/
|
|
|
++ tp->success=1;
|
|
|
++ if (digestmap_size(tp->failure_ids)) {
|
|
|
++ digestmap_free(tp->failure_ids,NULL);
|
|
|
++ tp->failure_ids=digestmap_new();
|
|
|
++ }
|
|
|
++ if (still_searching) {
|
|
|
++ still_searching=0;
|
|
|
++ SMARTLIST_FOREACH(or_port_hists,or_port_hist_t *,t,t->excluded=0;);
|
|
|
++ }
|
|
|
++ return;
|
|
|
++ });
|
|
|
++}
|
|
|
++/** Record the failure of our connection to <b>digest</b>'s
|
|
|
++ * OR port. Warn, exclude the port from future entry guard selection, or
|
|
|
++ * add port to blocked-ports in our server's extra-info as appropriate. */
|
|
|
++void
|
|
|
++or_port_hist_failure(const char *digest, uint16_t or_port)
|
|
|
++{
|
|
|
++ int total_failures=0, ports_excluded=0, report_block=0;
|
|
|
++ int total_routers=smartlist_len(router_get_routerlist()->routers);
|
|
|
++
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ ports_excluded += tp->excluded;
|
|
|
++ total_failures+=digestmap_size(tp->failure_ids);
|
|
|
++ if (tp->or_port != or_port)
|
|
|
++ continue;
|
|
|
++ /* We're only interested in unique failures */
|
|
|
++ if (digestmap_get(tp->failure_ids, digest))
|
|
|
++ return;
|
|
|
++
|
|
|
++ total_failures++;
|
|
|
++ digestmap_set(tp->failure_ids, digest, (void*)1);
|
|
|
++ if (still_searching && !tp->success) {
|
|
|
++ tp->excluded=1;
|
|
|
++ ports_excluded++;
|
|
|
++ }
|
|
|
++ if ((digestmap_size(tp->ids) >= POSSIBLY_BLOCKED) &&
|
|
|
++ !(digestmap_size(tp->failure_ids) % POSSIBLY_BLOCKED))
|
|
|
++ report_block=POSSIBLY_BLOCKED;
|
|
|
++ });
|
|
|
++
|
|
|
++ if (total_failures >= (int)(total_routers/10))
|
|
|
++ or_port_hist_report_block(FAILURES_OBSERVED);
|
|
|
++ else if (report_block)
|
|
|
++ or_port_hist_report_block(report_block);
|
|
|
++
|
|
|
++ if (ports_excluded >= smartlist_len(or_port_hists)) {
|
|
|
++ log_warn(LD_HIST,"During entry node selection Tor tried every port "
|
|
|
++ "offered on the network on at least one server "
|
|
|
++ "and didn't manage a single "
|
|
|
++ "successful connection. This suggests you are behind an "
|
|
|
++ "extremely restrictive firewall. Tor will keep trying to find "
|
|
|
++ "a reachable entry node.");
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp, tp->excluded=0;);
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
++/** Add any ports marked as excluded in or_port_hist_t to <b>rt</b> */
|
|
|
++void
|
|
|
++or_port_hist_exclude(routerset_t *rt)
|
|
|
++{
|
|
|
++ SMARTLIST_FOREACH(or_port_hists, or_port_hist_t *, tp,
|
|
|
++ {
|
|
|
++ char portpolicy[9];
|
|
|
++ if (tp->excluded) {
|
|
|
++ tor_snprintf(portpolicy,sizeof(portpolicy),"*:%u", tp->or_port);
|
|
|
++ log_warn(LD_HIST,"Port %u may be blocked, excluding it temporarily "
|
|
|
++ "from entry guard selection.", tp->or_port);
|
|
|
++ routerset_parse(rt, portpolicy, "Ports");
|
|
|
++ }
|
|
|
++ });
|
|
|
++}
|
|
|
++
|
|
|
++/** Allow the exclusion of ports during our search for an entry node. */
|
|
|
++void
|
|
|
++or_port_hist_search_again(void)
|
|
|
++{
|
|
|
++ still_searching=1;
|
|
|
++}
|
|
|
+Index: src/or/or.h
|
|
|
+===================================================================
|
|
|
+--- src/or/or.h (revision 17104)
|
|
|
++++ src/or/or.h (working copy)
|
|
|
+@@ -3864,6 +3864,13 @@
|
|
|
+ int any_predicted_circuits(time_t now);
|
|
|
+ int rep_hist_circbuilding_dormant(time_t now);
|
|
|
+
|
|
|
++void or_port_hist_failure(const char *digest, uint16_t or_port);
|
|
|
++void or_port_hist_success(uint16_t or_port);
|
|
|
++void or_port_hist_new(const routerinfo_t *ri);
|
|
|
++void or_port_hist_exclude(routerset_t *rt);
|
|
|
++void or_port_hist_search_again(void);
|
|
|
++char *or_port_hist_get_blocked_ports(void);
|
|
|
++
|
|
|
+ /** Possible public/private key operations in Tor: used to keep track of where
|
|
|
+ * we're spending our time. */
|
|
|
+ typedef enum {
|
|
|
+Index: src/or/routerparse.c
|
|
|
+===================================================================
|
|
|
+--- src/or/routerparse.c (revision 17104)
|
|
|
++++ src/or/routerparse.c (working copy)
|
|
|
+@@ -1401,6 +1401,8 @@
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
++ or_port_hist_new(router);
|
|
|
++
|
|
|
+ if (!router->platform) {
|
|
|
+ router->platform = tor_strdup("<unknown>");
|
|
|
+ }
|
|
|
+Index: src/or/router.c
|
|
|
+===================================================================
|
|
|
+--- src/or/router.c (revision 17104)
|
|
|
++++ src/or/router.c (working copy)
|
|
|
+@@ -1818,6 +1818,7 @@
|
|
|
+ char published[ISO_TIME_LEN+1];
|
|
|
+ char digest[DIGEST_LEN];
|
|
|
+ char *bandwidth_usage;
|
|
|
++ char *blocked_ports;
|
|
|
+ int result;
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+@@ -1825,7 +1826,6 @@
|
|
|
+ extrainfo->cache_info.identity_digest, DIGEST_LEN);
|
|
|
+ format_iso_time(published, extrainfo->cache_info.published_on);
|
|
|
+ bandwidth_usage = rep_hist_get_bandwidth_lines(1);
|
|
|
+-
|
|
|
+ result = tor_snprintf(s, maxlen,
|
|
|
+ "extra-info %s %s\n"
|
|
|
+ "published %s\n%s",
|
|
|
+@@ -1835,6 +1835,16 @@
|
|
|
+ if (result<0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
++ blocked_ports = or_port_hist_get_blocked_ports();
|
|
|
++ if (blocked_ports) {
|
|
|
++ result = tor_snprintf(s+strlen(s), maxlen-strlen(s),
|
|
|
++ "%s",
|
|
|
++ blocked_ports);
|
|
|
++ tor_free(blocked_ports);
|
|
|
++ if (result<0)
|
|
|
++ return -1;
|
|
|
++ }
|
|
|
++
|
|
|
+ if (should_record_bridge_info(options)) {
|
|
|
+ static time_t last_purged_at = 0;
|
|
|
+ char *geoip_summary;
|
|
|
+Index: src/or/circuitbuild.c
|
|
|
+===================================================================
|
|
|
+--- src/or/circuitbuild.c (revision 17104)
|
|
|
++++ src/or/circuitbuild.c (working copy)
|
|
|
+@@ -62,6 +62,7 @@
|
|
|
+
|
|
|
+ static void entry_guards_changed(void);
|
|
|
+ static time_t start_of_month(time_t when);
|
|
|
++static int num_live_entry_guards(void);
|
|
|
+
|
|
|
+ /** Iterate over values of circ_id, starting from conn-\>next_circ_id,
|
|
|
+ * and with the high bit specified by conn-\>circ_id_type, until we get
|
|
|
+@@ -1627,12 +1628,14 @@
|
|
|
+ smartlist_t *excluded;
|
|
|
+ or_options_t *options = get_options();
|
|
|
+ router_crn_flags_t flags = 0;
|
|
|
++ routerset_t *_ExcludeNodes;
|
|
|
+
|
|
|
+ if (state && options->UseEntryGuards &&
|
|
|
+ (purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) {
|
|
|
+ return choose_random_entry(state);
|
|
|
+ }
|
|
|
+
|
|
|
++ _ExcludeNodes = routerset_new();
|
|
|
+ excluded = smartlist_create();
|
|
|
+
|
|
|
+ if (state && (r = build_state_get_exit_router(state))) {
|
|
|
+@@ -1670,12 +1673,18 @@
|
|
|
+ if (options->_AllowInvalid & ALLOW_INVALID_ENTRY)
|
|
|
+ flags |= CRN_ALLOW_INVALID;
|
|
|
+
|
|
|
++ if (options->ExcludeNodes)
|
|
|
++ routerset_union(_ExcludeNodes,options->ExcludeNodes);
|
|
|
++
|
|
|
++ or_port_hist_exclude(_ExcludeNodes);
|
|
|
++
|
|
|
+ choice = router_choose_random_node(
|
|
|
+ NULL,
|
|
|
+ excluded,
|
|
|
+- options->ExcludeNodes,
|
|
|
++ _ExcludeNodes,
|
|
|
+ flags);
|
|
|
+ smartlist_free(excluded);
|
|
|
++ routerset_free(_ExcludeNodes);
|
|
|
+ return choice;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -2727,6 +2736,7 @@
|
|
|
+ entry_guards_update_state(or_state_t *state)
|
|
|
+ {
|
|
|
+ config_line_t **next, *line;
|
|
|
++ unsigned int have_reachable_entry=0;
|
|
|
+ if (! entry_guards_dirty)
|
|
|
+ return;
|
|
|
+
|
|
|
+@@ -2740,6 +2750,7 @@
|
|
|
+ char dbuf[HEX_DIGEST_LEN+1];
|
|
|
+ if (!e->made_contact)
|
|
|
+ continue; /* don't write this one to disk */
|
|
|
++ have_reachable_entry=1;
|
|
|
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
|
|
|
+ line->key = tor_strdup("EntryGuard");
|
|
|
+ line->value = tor_malloc(HEX_DIGEST_LEN+MAX_NICKNAME_LEN+2);
|
|
|
+@@ -2785,6 +2796,11 @@
|
|
|
+ if (!get_options()->AvoidDiskWrites)
|
|
|
+ or_state_mark_dirty(get_or_state(), 0);
|
|
|
+ entry_guards_dirty = 0;
|
|
|
++
|
|
|
++ /* XXX: Is this the place to decide that we no longer have any reachable
|
|
|
++ guards? */
|
|
|
++ if (!have_reachable_entry)
|
|
|
++ or_port_hist_search_again();
|
|
|
+ }
|
|
|
+
|
|
|
+ /** If <b>question</b> is the string "entry-guards", then dump
|
|
|
+
|