aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/util.c94
-rw-r--r--src/common/util.h4
-rw-r--r--src/or/circuitbuild.c83
-rw-r--r--src/or/circuitbuild.h8
-rw-r--r--src/or/circuituse.c21
-rw-r--r--src/or/config.c20
-rw-r--r--src/or/connection_edge.c14
-rw-r--r--src/or/connection_or.c45
-rw-r--r--src/or/connection_or.h2
-rw-r--r--src/or/dirserv.c12
-rw-r--r--src/or/dirvote.c279
-rw-r--r--src/or/eventdns.c3
-rw-r--r--src/or/geoip.c2
-rw-r--r--src/or/main.c6
-rw-r--r--src/or/ntmain.c3
-rw-r--r--src/or/or.h16
-rw-r--r--src/or/router.c27
-rw-r--r--src/or/router.h2
-rw-r--r--src/or/routerlist.c12
-rw-r--r--src/test/test_util.c72
20 files changed, 620 insertions, 105 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 1d770458f7..b4f3052e19 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -26,6 +26,7 @@
#include <io.h>
#include <direct.h>
#include <process.h>
+#include <tchar.h>
#else
#include <dirent.h>
#include <pwd.h>
@@ -2284,7 +2285,40 @@ unescape_string(const char *s, char **result, size_t *size_out)
const char *
parse_config_line_from_str(const char *line, char **key_out, char **value_out)
{
+ /* I believe the file format here is supposed to be:
+ FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
+
+ EMPTYLASTLINE = SPACE* | COMMENT
+ EMPTYLINE = EMPTYLASTLINE NL
+ SPACE = ' ' | '\r' | '\t'
+ COMMENT = '#' NOT-NL*
+ NOT-NL = Any character except '\n'
+ NL = '\n'
+
+ LASTLINE = SPACE* KEY SPACE* VALUES
+ LINE = LASTLINE NL
+ KEY = KEYCHAR+
+ KEYCHAR = Any character except ' ', '\r', '\n', '\t', '#', "\"
+
+ VALUES = QUOTEDVALUE | NORMALVALUE
+ QUOTEDVALUE = QUOTE QVITEM* QUOTE EOLSPACE?
+ QUOTE = '"'
+ QVCHAR = KEYCHAR | ESC ('n' | 't' | 'r' | '"' | ESC |'\'' | OCTAL | HEX)
+ ESC = "\\"
+ OCTAL = ODIGIT (ODIGIT ODIGIT?)?
+ HEX = ('x' | 'X') HEXDIGIT HEXDIGIT
+ ODIGIT = '0' .. '7'
+ HEXDIGIT = '0'..'9' | 'a' .. 'f' | 'A' .. 'F'
+ EOLSPACE = SPACE* COMMENT?
+
+ NORMALVALUE = (VALCHAR | ESC ESC_IGNORE | CONTINUATION)* EOLSPACE?
+ VALCHAR = Any character except ESC, '#', and '\n'
+ ESC_IGNORE = Any character except '#' or '\n'
+ CONTINUATION = ESC NL ( COMMENT NL )*
+ */
+
const char *key, *val, *cp;
+ int continuation = 0;
tor_assert(key_out);
tor_assert(value_out);
@@ -2308,9 +2342,10 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
return line;
}
- /* Skip until the next space. */
+ /* Skip until the next space or \ followed by newline. */
key = line;
- while (*line && !TOR_ISSPACE(*line) && *line != '#')
+ while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
+ ! (line[0] == '\\' && line[1] == '\n'))
++line;
*key_out = tor_strndup(key, line-key);
@@ -2321,7 +2356,7 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
val = line;
/* Find the end of the line. */
- if (*line == '\"') {
+ if (*line == '\"') { // XXX No continuation handling is done here
if (!(line = unescape_string(line, value_out, NULL)))
return NULL;
while (*line == ' ' || *line == '\t')
@@ -2329,18 +2364,53 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
if (*line && *line != '#' && *line != '\n')
return NULL;
} else {
- while (*line && *line != '\n' && *line != '#')
- ++line;
+ /* Look for the end of the line. */
+ while (*line && *line != '\n' && (*line != '#' || continuation)) {
+ if (*line == '\\' && line[1] == '\n') {
+ continuation = 1;
+ line += 2;
+ } else if (*line == '#') {
+ do {
+ ++line;
+ } while (*line && *line != '\n');
+ if (*line == '\n')
+ ++line;
+ } else {
+ ++line;
+ }
+ }
+
if (*line == '\n') {
cp = line++;
} else {
cp = line;
}
+ /* Now back cp up to be the last nonspace character */
while (cp>val && TOR_ISSPACE(*(cp-1)))
--cp;
tor_assert(cp >= val);
+
+ /* Now copy out and decode the value. */
*value_out = tor_strndup(val, cp-val);
+ if (continuation) {
+ char *v_out, *v_in;
+ v_out = v_in = *value_out;
+ while (*v_in) {
+ if (*v_in == '#') {
+ do {
+ ++v_in;
+ } while (*v_in && *v_in != '\n');
+ if (*v_in == '\n')
+ ++v_in;
+ } else if (v_in[0] == '\\' && v_in[1] == '\n') {
+ v_in += 2;
+ } else {
+ *v_out++ = *v_in++;
+ }
+ }
+ *v_out = '\0';
+ }
}
if (*line == '#') {
@@ -2793,3 +2863,17 @@ write_pidfile(char *filename)
}
}
+#ifdef MS_WINDOWS
+HANDLE
+load_windows_system_library(const TCHAR *library_name)
+{
+ TCHAR path[MAX_PATH];
+ unsigned n;
+ n = GetSystemDirectory(path, MAX_PATH);
+ if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH)
+ return 0;
+ _tcscat(path, TEXT("\\"));
+ _tcscat(path, library_name);
+ return LoadLibrary(path);
+}
+#endif
diff --git a/src/common/util.h b/src/common/util.h
index 4a31c277e3..833fd904c7 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -340,6 +340,10 @@ void start_daemon(void);
void finish_daemon(const char *desired_cwd);
void write_pidfile(char *filename);
+#ifdef MS_WINDOWS
+HANDLE load_windows_system_library(const TCHAR *library_name);
+#endif
+
const char *libor_get_digests(void);
#endif
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);
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 8a13597978..a14d548b8e 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -100,6 +100,15 @@ test_util_config_line(void)
"k4#a\n" "k5#abc\n" "k6 val #with comment\n"
"kseven \"a quoted 'string\"\n"
"k8 \"a \\x71uoted\\n\\\"str\\\\ing\\t\\001\\01\\1\\\"\"\n"
+ "k9 a line that\\\n spans two lines.\n\n"
+ "k10 more than\\\n one contin\\\nuation\n"
+ "k11 \\\ncontinuation at the start\n"
+ "k12 line with a\\\n#comment\n embedded\n"
+ "k13\\\ncontinuation at the very start\n"
+ "k14 a line that has a comment and # ends with a slash \\\n"
+ "k15 this should be the next new line\n"
+ "k16 a line that has a comment and # ends without a slash \n"
+ "k17 this should be the next new line\n"
, sizeof(buf));
str = buf;
@@ -161,7 +170,54 @@ test_util_config_line(void)
test_streq(k, "k8");
test_streq(v, "a quoted\n\"str\\ing\t\x01\x01\x01\"");
tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k9");
+ test_streq(v, "a line that spans two lines.");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k10");
+ test_streq(v, "more than one continuation");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k11");
+ test_streq(v, "continuation at the start");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k12");
+ test_streq(v, "line with a embedded");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k13");
+ test_streq(v, "continuation at the very start");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k14");
+ test_streq(v, "a line that has a comment and" );
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k15");
+ test_streq(v, "this should be the next new line");
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k16");
+ test_streq(v, "a line that has a comment and" );
+ tor_free(k); tor_free(v);
+
+ str = parse_config_line_from_str(str, &k, &v);
+ test_streq(k, "k17");
+ test_streq(v, "this should be the next new line");
+ tor_free(k); tor_free(v);
+
test_streq(str, "");
+
done:
tor_free(k);
tor_free(v);
@@ -1139,6 +1195,19 @@ test_util_listdir(void *ptr)
}
}
+#ifdef MS_WINDOWS
+static void
+test_util_load_win_lib(void *ptr)
+{
+ HANDLE h = load_windows_system_library("advapi32.dll");
+
+ tt_assert(h);
+ done:
+ if (h)
+ CloseHandle(h);
+}
+#endif
+
#define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@@ -1162,6 +1231,9 @@ struct testcase_t util_tests[] = {
UTIL_TEST(find_str_at_start_of_line, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
+#ifdef MS_WINDOWS
+ UTIL_TEST(load_win_lib, 0),
+#endif
END_OF_TESTCASES
};