r15965@catbus: nickm | 2007-10-19 13:32:11 -0400

Client-side implementation for proposal 122.


svn:r12051
This commit is contained in:
Nick Mathewson 2007-10-19 18:56:24 +00:00
parent ee2b770dee
commit 7bb202fd19
7 changed files with 91 additions and 12 deletions

View File

@ -16,6 +16,9 @@ Changes in version 0.2.0.9-alpha - 2007-10-??
that it shouldn't be considered to exist at all anymore. Now we that it shouldn't be considered to exist at all anymore. Now we
clear all the flags for routers that fall out of the networkstatus clear all the flags for routers that fall out of the networkstatus
consensus. Fixes bug 529. consensus. Fixes bug 529.
- If the consensus list a router as "Unnamed", the name is assigned
to a different router: do not identify the router by that name.
(Partially implements proposal 122.)
o Minor features (v3 directory protocol): o Minor features (v3 directory protocol):
- Allow tor-gencert to generate a new certificate without replacing the - Allow tor-gencert to generate a new certificate without replacing the

View File

@ -93,11 +93,11 @@ Things we'd like to do in 0.2.0.x:
- 105: Version negotiation for the Tor protocol - 105: Version negotiation for the Tor protocol
. 111: Prioritize local traffic over relayed. . 111: Prioritize local traffic over relayed.
- Merge into tor-spec.txt. - Merge into tor-spec.txt.
- 122: Network status entries need an Unnamed flag . 122: Network status entries need an Unnamed flag
- Merge into dir-spec.txt - Merge into dir-spec.txt
- Implement voting side - Implement voting side
- Implement consensus side - Implement consensus side
- Implement client side o Implement client side
- Refactoring: - Refactoring:
. Make cells get buffered on circuit, not on the or_conn. . Make cells get buffered on circuit, not on the or_conn.

View File

@ -4,7 +4,7 @@ Version: $Revision$
Last-Modified: $Date$ Last-Modified: $Date$
Author: Roger Dingledine Author: Roger Dingledine
Created: 04-Oct-2007 Created: 04-Oct-2007
Status: Open Status: Accepted
1. Overview: 1. Overview:

View File

@ -25,8 +25,11 @@ static smartlist_t *networkstatus_v2_list = NULL;
* time we called download_status_map_update_from_v2_networkstatus() */ * time we called download_status_map_update_from_v2_networkstatus() */
static int networkstatus_v2_list_has_changed = 0; static int networkstatus_v2_list_has_changed = 0;
/** Map from lowercase nickname to digest of named server, if any. */ /** Map from lowercase nickname to identity digest of named server, if any. */
static strmap_t *named_server_map = NULL; static strmap_t *named_server_map = NULL;
/** Map from lowercase nickname to (void*)1 for all names that are listed
* as unnamed for some server in the consensus. */
static strmap_t *unnamed_server_map = NULL;
/** Most recently received and validated v3 consensus network status. */ /** Most recently received and validated v3 consensus network status. */
static networkstatus_vote_t *current_consensus = NULL; static networkstatus_vote_t *current_consensus = NULL;
@ -579,6 +582,7 @@ router_get_consensus_status_by_nickname(const char *nickname,
routerstatus_t *best=NULL; routerstatus_t *best=NULL;
smartlist_t *matches=NULL; smartlist_t *matches=NULL;
const char *named_id=NULL; const char *named_id=NULL;
int any_unnamed=0;
if (!current_consensus || !nickname) if (!current_consensus || !nickname)
return NULL; return NULL;
@ -597,6 +601,10 @@ router_get_consensus_status_by_nickname(const char *nickname,
if (named_id) if (named_id)
return networkstatus_vote_find_entry(current_consensus, named_id); return networkstatus_vote_find_entry(current_consensus, named_id);
if (unnamed_server_map &&
strmap_get_lc(named_server_map, nickname))
return NULL; /* XXXX020 should we warn? */
/*XXXX020 is this behavior really what we want? */ /*XXXX020 is this behavior really what we want? */
matches = smartlist_create(); matches = smartlist_create();
SMARTLIST_FOREACH(current_consensus->routerstatus_list, SMARTLIST_FOREACH(current_consensus->routerstatus_list,
@ -604,16 +612,22 @@ router_get_consensus_status_by_nickname(const char *nickname,
{ {
if (!strcasecmp(lrs->nickname, nickname)) { if (!strcasecmp(lrs->nickname, nickname)) {
if (lrs->is_named) { if (lrs->is_named) {
/* XXXX020 this should never happen. */
smartlist_free(matches); smartlist_free(matches);
return lrs; return lrs;
} else { } else {
if (lrs->is_unnamed)
smartlist_free(matches); /* nor should this. */
smartlist_add(matches, lrs); smartlist_add(matches, lrs);
best = lrs; best = lrs;
} }
} }
}); });
if (smartlist_len(matches)>1 && warn_if_unnamed) { if (any_unnamed) {
/* XXXX020 should we warn? */
return NULL;
} else if (smartlist_len(matches)>1 && warn_if_unnamed) {
int any_unwarned=0; int any_unwarned=0;
SMARTLIST_FOREACH(matches, routerstatus_t *, lrs, SMARTLIST_FOREACH(matches, routerstatus_t *, lrs,
{ {
@ -654,6 +668,13 @@ networkstatus_get_router_digest_by_nickname(const char *nickname)
return strmap_get_lc(named_server_map, nickname); return strmap_get_lc(named_server_map, nickname);
} }
/** DOCDOC */
int
networkstatus_nickname_is_unnamed(const char *nickname)
{
return strmap_get_lc(named_server_map, nickname) != NULL;
}
/** How frequently do directory authorities re-download fresh networkstatus /** How frequently do directory authorities re-download fresh networkstatus
* documents? */ * documents? */
#define AUTHORITY_NS_CACHE_INTERVAL (5*60) #define AUTHORITY_NS_CACHE_INTERVAL (5*60)
@ -1061,6 +1082,11 @@ routers_update_all_from_networkstatus(time_t now)
log_info(LD_GENERAL, "The latest consensus does not list us." log_info(LD_GENERAL, "The latest consensus does not list us."
"Are you misconfigured?"); "Are you misconfigured?");
have_warned_about_invalid_status = 1; have_warned_about_invalid_status = 1;
} else if (rs->is_unnamed) {
/* XXXX020 this isn't a useful warning. */
log_info(LD_GENERAL, "The directory have assigned the nickname "
"you're using to a different identity.");
have_warned_about_invalid_status = 1;
} else if (!rs->is_named) { } else if (!rs->is_named) {
/*XXXX020 this isn't a correct warning. */ /*XXXX020 this isn't a correct warning. */
log_info(LD_GENERAL, "The directory authorities do not recognize " log_info(LD_GENERAL, "The directory authorities do not recognize "
@ -1150,12 +1176,18 @@ routerstatus_list_update_named_server_map(void)
if (named_server_map) if (named_server_map)
strmap_free(named_server_map, _tor_free); strmap_free(named_server_map, _tor_free);
named_server_map = strmap_new(); named_server_map = strmap_new();
if (unnamed_server_map)
strmap_free(unnamed_server_map, NULL);
named_server_map = strmap_new();
SMARTLIST_FOREACH(current_consensus->routerstatus_list, routerstatus_t *, rs, SMARTLIST_FOREACH(current_consensus->routerstatus_list, routerstatus_t *, rs,
{ {
if (rs->is_named) { if (rs->is_named) {
strmap_set(named_server_map, rs->nickname, strmap_set_lc(named_server_map, rs->nickname,
tor_memdup(rs->identity_digest, DIGEST_LEN)); tor_memdup(rs->identity_digest, DIGEST_LEN));
} }
if (rs->is_unnamed) {
strmap_set_lc(unnamed_server_map, rs->nickname, (void*)1);
}
}); });
} }
@ -1348,5 +1380,8 @@ networkstatus_free_all(void)
if (named_server_map) { if (named_server_map) {
strmap_free(named_server_map, _tor_free); strmap_free(named_server_map, _tor_free);
} }
if (unnamed_server_map) {
strmap_free(unnamed_server_map, NULL);
}
} }

View File

@ -1221,6 +1221,8 @@ typedef struct routerstatus_t {
unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ unsigned int is_fast:1; /**< True iff this router has good bandwidth. */
unsigned int is_running:1; /**< True iff this router is up. */ unsigned int is_running:1; /**< True iff this router is up. */
unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */
unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another
* router. */
unsigned int is_valid:1; /**< True iff this router is validated. */ unsigned int is_valid:1; /**< True iff this router is validated. */
unsigned int is_v2_dir:1; /**< True iff this router can serve directory unsigned int is_v2_dir:1; /**< True iff this router can serve directory
* information with v2 of the directory * information with v2 of the directory
@ -1349,6 +1351,11 @@ typedef struct networkstatus_vote_t {
time_t valid_until; /**< Time after which this vote or consensus should not time_t valid_until; /**< Time after which this vote or consensus should not
* be used. */ * be used. */
/** Consensus only: what method was used to produce this consensus? */
int consensus_method;
/** Vote only: what methods is this voter willing to use? */
smartlist_t *supported_methods;
/** How long does this vote/consensus claim that authorities take to /** How long does this vote/consensus claim that authorities take to
* distribute their votes to one another? */ * distribute their votes to one another? */
int vote_seconds; int vote_seconds;
@ -3091,6 +3098,7 @@ routerstatus_t *router_get_consensus_status_by_descriptor_digest(
routerstatus_t *router_get_consensus_status_by_nickname(const char *nickname, routerstatus_t *router_get_consensus_status_by_nickname(const char *nickname,
int warn_if_unnamed); int warn_if_unnamed);
const char *networkstatus_get_router_digest_by_nickname(const char *nickname); const char *networkstatus_get_router_digest_by_nickname(const char *nickname);
int networkstatus_nickname_is_unnamed(const char *nickname);
void networkstatus_consensus_download_failed(int status_code); void networkstatus_consensus_download_failed(int status_code);
int should_delay_dir_fetches(or_options_t *options); int should_delay_dir_fetches(or_options_t *options);
void update_networkstatus_downloads(time_t now); void update_networkstatus_downloads(time_t now);

View File

@ -1701,6 +1701,8 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
if ((named_digest = networkstatus_get_router_digest_by_nickname(nickname))) { if ((named_digest = networkstatus_get_router_digest_by_nickname(nickname))) {
return rimap_get(routerlist->identity_map, named_digest); return rimap_get(routerlist->identity_map, named_digest);
} }
if (networkstatus_nickname_is_unnamed(nickname))
return NULL;
/* If we reach this point, there's no canonical value for the nickname. */ /* If we reach this point, there's no canonical value for the nickname. */

View File

@ -1534,12 +1534,17 @@ find_start_of_next_routerstatus(const char *s)
* router status. Return NULL and advance *<b>s</b> on error. * router status. Return NULL and advance *<b>s</b> on error.
* *
* If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
* routerstatus but use <b>vote_rs</b> instead * routerstatus but use <b>vote_rs</b> instead.
*
* If <b>consensus_method</b> is nonzero, this routerstatus is part of a
* consensus, and we should parse it according to the method used to
* make that consensus.
**/ **/
static routerstatus_t * static routerstatus_t *
routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens, routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens,
networkstatus_vote_t *vote, networkstatus_vote_t *vote,
vote_routerstatus_t *vote_rs) vote_routerstatus_t *vote_rs,
int consensus_method)
{ {
const char *eos; const char *eos;
routerstatus_t *rs = NULL; routerstatus_t *rs = NULL;
@ -1645,6 +1650,11 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens,
rs->is_bad_directory = 1; rs->is_bad_directory = 1;
else if (!strcmp(tok->args[i], "Authority")) else if (!strcmp(tok->args[i], "Authority"))
rs->is_authority = 1; rs->is_authority = 1;
else if (!strcmp(tok->args[i], "Unnamed") &&
consensus_method >= 2) {
/* Unnamed is computed right by consensus method 2 and later. */
rs->is_unnamed = 1;
}
} }
} }
if ((tok = find_first_by_keyword(tokens, K_V))) { if ((tok = find_first_by_keyword(tokens, K_V))) {
@ -1830,7 +1840,7 @@ networkstatus_v2_parse_from_string(const char *s)
smartlist_clear(tokens); smartlist_clear(tokens);
while (!strcmpstart(s, "r ")) { while (!strcmpstart(s, "r ")) {
routerstatus_t *rs; routerstatus_t *rs;
if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL))) if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL, 0)))
smartlist_add(ns->entries, rs); smartlist_add(ns->entries, rs);
} }
smartlist_sort(ns->entries, _compare_routerstatus_entries); smartlist_sort(ns->entries, _compare_routerstatus_entries);
@ -1936,6 +1946,26 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
tok = find_first_by_keyword(tokens, K_PUBLISHED); tok = find_first_by_keyword(tokens, K_PUBLISHED);
if (parse_iso_time(tok->args[0], &ns->published)) if (parse_iso_time(tok->args[0], &ns->published))
goto err; goto err;
ns->supported_methods = smartlist_create();
tok = find_first_by_keyword(tokens, K_CONSENSUS_METHODS);
if (tok) {
for (i=0; i < tok->n_args; ++i)
smartlist_add(ns->supported_methods, tok->args[i]);
tok->n_args = 0; /* Prevent double free. */
} else {
smartlist_add(ns->supported_methods, tor_strdup("1"));
}
} else {
tok = find_first_by_keyword(tokens, K_CONSENSUS_METHOD);
if (tok) {
ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
&ok, NULL);
if (!ok)
goto err;
} else {
ns->consensus_method = 1;
}
} }
tok = find_first_by_keyword(tokens, K_VALID_AFTER); tok = find_first_by_keyword(tokens, K_VALID_AFTER);
@ -2086,7 +2116,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
while (!strcmpstart(s, "r ")) { while (!strcmpstart(s, "r ")) {
if (is_vote) { if (is_vote) {
vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t)); vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs)) if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs, 0))
smartlist_add(ns->routerstatus_list, rs); smartlist_add(ns->routerstatus_list, rs);
else { else {
tor_free(rs->version); tor_free(rs->version);
@ -2094,7 +2124,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
} }
} else { } else {
routerstatus_t *rs; routerstatus_t *rs;
if ((rs =routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL))) if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL,
ns->consensus_method)))
smartlist_add(ns->routerstatus_list, rs); smartlist_add(ns->routerstatus_list, rs);
} }
} }