aboutsummaryrefslogtreecommitdiff
path: root/src/or/circuitbuild.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r--src/or/circuitbuild.c142
1 files changed, 137 insertions, 5 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 972d48951..4b14e16f6 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -25,6 +25,10 @@ extern circuit_t *global_circuitlist;
typedef struct {
char nickname[MAX_NICKNAME_LEN+1];
char identity[DIGEST_LEN];
+ time_t chosen_on_date; /**< Approximately when was this guard added?
+ * "0" if we don't know. */
+ char *chosen_by_version; /**< What tor version added this guard? NULL
+ * if we don't know. */
unsigned int made_contact : 1; /**< 0 if we have never connected to this
* router, 1 if we have. */
unsigned int can_retry : 1; /**< Should we retry connecting to this entry,
@@ -56,6 +60,7 @@ static int count_acceptable_routers(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
+static time_t start_of_month(time_t when);
/** 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
@@ -2054,6 +2059,8 @@ add_an_entry_guard(routerinfo_t *chosen, int reset_status)
log_info(LD_CIRC, "Chose '%s' as new entry guard.", router->nickname);
strlcpy(entry->nickname, router->nickname, sizeof(entry->nickname));
memcpy(entry->identity, router->cache_info.identity_digest, DIGEST_LEN);
+ entry->chosen_on_date = start_of_month(time(NULL));
+ entry->chosen_by_version = tor_strdup(VERSION);
if (chosen) /* prepend */
smartlist_insert(entry_guards, 0, entry);
else /* append */
@@ -2087,11 +2094,62 @@ pick_entry_guards(void)
* unlisted, excluded, or otherwise nonusable before we give up on it? */
#define ENTRY_GUARD_REMOVE_AFTER (30*24*60*60)
+/** Release all storage held by <b>e</b>. */
+static void
+entry_guard_free(entry_guard_t *e)
+{
+ tor_assert(e);
+ tor_free(e->chosen_by_version);
+ tor_free(e);
+}
+
+/** DOCDOC */
+static int
+remove_obsolete_entry_guards(void)
+{
+ int changed, i;
+ for (i = 0; i < smartlist_len(entry_guards); ++i) {
+ entry_guard_t *entry = smartlist_get(entry_guards, i);
+ const char *ver = entry->chosen_by_version;
+ const char *msg = NULL;
+ tor_version_t v;
+ int version_is_bad = 0;
+ if (!ver) {
+ msg = "does not say what version of Tor it was selected by";
+ version_is_bad = 1;
+ } else if (tor_version_parse(ver, &v)) {
+ msg = "does not seem to be from any recognized version of Tor";
+ version_is_bad = 1;
+ } else if ((tor_version_as_new_as(ver, "0.1.0.10-alpha") &&
+ !tor_version_as_new_as(ver, "0.1.2.16-dev")) ||
+ (tor_version_as_new_as(ver, "0.2.0.0-alpha") &&
+ !tor_version_as_new_as(ver, "0.2.0.6-alpha"))) {
+ msg = "was selected without regard for guard bandwidth";
+ version_is_bad = 1;
+ }
+ if (version_is_bad) {
+ char dbuf[HEX_DIGEST_LEN+1];
+ tor_assert(msg);
+ base16_encode(dbuf, sizeof(dbuf), entry->identity, DIGEST_LEN);
+ log_notice(LD_CIRC, "Entry guard '%s' (%s) %s. (Version=%s.) "
+ "Replacing it.",
+ entry->nickname, dbuf, msg, ver?escaped(ver):"none");
+ control_event_guard(entry->nickname, entry->identity, "DROPPED");
+ entry_guard_free(entry);
+ smartlist_del_keeporder(entry_guards, i--);
+ log_entry_guards(LOG_INFO);
+ changed = 1;
+ }
+ }
+
+ return changed ? 1 : 0;
+}
+
/** Remove all entry guards that have been down or unlisted for so
* 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_entries(void)
+remove_dead_entry_guards(void)
{
char dbuf[HEX_DIGEST_LEN+1];
char tbuf[ISO_TIME_LEN+1];
@@ -2110,7 +2168,7 @@ remove_dead_entries(void)
"since %s local time; removing.",
entry->nickname, dbuf, tbuf);
control_event_guard(entry->nickname, entry->identity, "DROPPED");
- tor_free(entry);
+ entry_guard_free(entry);
smartlist_del_keeporder(entry_guards, i);
log_entry_guards(LOG_INFO);
changed = 1;
@@ -2155,7 +2213,7 @@ entry_guards_compute_status(void)
entry_is_live(entry, 0, 1, 0) ? "live" : "not live");
});
- if (remove_dead_entries())
+ if (remove_dead_entry_guards())
changed = 1;
if (changed) {
@@ -2454,6 +2512,19 @@ choose_random_entry(cpath_build_state_t *state)
return r;
}
+/** DOCDOC */
+static time_t
+start_of_month(time_t now)
+{
+ struct tm tm;
+ tor_gmtime_r(&now, &tm);
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+ tm.tm_mday = 1;
+ return tor_timegm(&tm);
+}
+
/** Parse <b>state</b> and learn about the entry guards it describes.
* If <b>set</b> is true, and there are no errors, replace the global
* entry_list with what we find.
@@ -2467,6 +2538,8 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
smartlist_t *new_entry_guards = smartlist_create();
config_line_t *line;
time_t now = time(NULL);
+ const char *state_version = state->TorVersion;
+ digestmap_t *added_by = digestmap_new();
*msg = NULL;
for (line = state->EntryGuards; line; line = line->next) {
@@ -2496,7 +2569,8 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
smartlist_free(args);
if (*msg)
break;
- } else {
+ } else if (!strcasecmp(line->key, "EntryGuardDownSince") ||
+ !strcasecmp(line->key, "EntryGuardUnlistedSince")) {
time_t when;
time_t last_try = 0;
if (!node) {
@@ -2524,9 +2598,46 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
} else {
node->bad_since = when;
}
+ } else if (!strcasecmp(line->key, "EntryGuardAddedBy")) {
+ char d[DIGEST_LEN];
+ /* format is digest version date */
+ if (strlen(line->value) < HEX_DIGEST_LEN+1+1+1+ISO_TIME_LEN) {
+ log_warn(LD_BUG, "EntryGuardAddedBy line is not long enough.");
+ continue;
+ }
+ if (base16_decode(d, sizeof(d), line->value, HEX_DIGEST_LEN)<0 ||
+ line->value[HEX_DIGEST_LEN] != ' ') {
+ log_warn(LD_BUG, "EntryGuardAddedBy line %s does not begin with "
+ "hex digest", escaped(line->value));
+ continue;
+ }
+ digestmap_set(added_by, d, tor_strdup(line->value+HEX_DIGEST_LEN+1));
+ } else {
+ log_warn(LD_BUG, "Unexpected key %s", line->key);
}
}
+ SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
+ {
+ char *sp;
+ char *val = digestmap_get(added_by, e->identity);
+ if (val && (sp = strchr(val, ' '))) {
+ time_t when;
+ *sp++ = '\0';
+ if (parse_iso_time(sp, &when)<0) {
+ log_warn(LD_BUG, "Can't read time %s in EntryGuardAddedBy", sp);
+ } else {
+ e->chosen_by_version = tor_strdup(val);
+ e->chosen_on_date = when;
+ }
+ } else {
+ if (state_version) {
+ e->chosen_by_version = tor_strdup(state_version);
+ e->chosen_on_date = start_of_month(time(NULL));
+ }
+ }
+ });
+
if (*msg || !set) {
SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e, tor_free(e));
smartlist_free(new_entry_guards);
@@ -2537,7 +2648,10 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
}
entry_guards = new_entry_guards;
entry_guards_dirty = 0;
+ if (remove_obsolete_entry_guards())
+ entry_guards_dirty = 1;
}
+ digestmap_free(added_by, _tor_free);
return *msg ? -1 : 0;
}
@@ -2603,6 +2717,22 @@ entry_guards_update_state(or_state_t *state)
format_iso_time(line->value, e->bad_since);
next = &(line->next);
}
+ if (e->chosen_on_date && e->chosen_by_version &&
+ !strchr(e->chosen_by_version, ' ')) {
+ char d[HEX_DIGEST_LEN+1];
+ char t[ISO_TIME_LEN+1];
+ size_t val_len;
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup("EntryGuardAddedBy");
+ val_len = (HEX_DIGEST_LEN+1+strlen(e->chosen_by_version)
+ +1+ISO_TIME_LEN+1);
+ line->value = tor_malloc(val_len);
+ base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
+ format_iso_time(t, e->chosen_on_date);
+ tor_snprintf(line->value, val_len, "%s %s %s",
+ d, e->chosen_by_version, t);
+ next = &(line->next);
+ }
});
if (!get_options()->AvoidDiskWrites)
or_state_mark_dirty(get_or_state(), 0);
@@ -2670,6 +2800,7 @@ getinfo_helper_entry_guards(control_connection_t *conn,
return 0;
}
+/** DOCDOC */
typedef struct {
uint32_t addr;
uint16_t port;
@@ -2920,7 +3051,8 @@ void
entry_guards_free_all(void)
{
if (entry_guards) {
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, tor_free(e));
+ SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
+ entry_guard_free(e));
smartlist_free(entry_guards);
entry_guards = NULL;
}