diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-07-25 22:56:44 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-07-25 22:56:44 +0000 |
commit | a66f25935483b1b415a878ed208896886dd1df66 (patch) | |
tree | 5e3009b8c32a3f5a9a0aafd95b6203e5523c4096 /src/or | |
parent | 1b7a704c34443315a1f89280425aa89509a528ee (diff) | |
download | tor-a66f25935483b1b415a878ed208896886dd1df66.tar.gz tor-a66f25935483b1b415a878ed208896886dd1df66.zip |
r13902@catbus: nickm | 2007-07-25 17:43:52 -0400
Some dirvote code to handle generating votes and slinging them around. More code is still needed.
svn:r10927
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/directory.c | 46 | ||||
-rw-r--r-- | src/or/dirserv.c | 6 | ||||
-rw-r--r-- | src/or/dirvote.c | 154 | ||||
-rw-r--r-- | src/or/or.h | 22 | ||||
-rw-r--r-- | src/or/router.c | 8 |
5 files changed, 232 insertions, 4 deletions
diff --git a/src/or/directory.c b/src/or/directory.c index eb3f8ee584..66f182adcf 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -78,6 +78,7 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose) return 1; /* if we have to ask, better make it anonymous */ if (dir_purpose == DIR_PURPOSE_FETCH_DIR || dir_purpose == DIR_PURPOSE_UPLOAD_DIR || + dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || dir_purpose == DIR_PURPOSE_FETCH_RUNNING_LIST || dir_purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS || dir_purpose == DIR_PURPOSE_FETCH_SERVERDESC || @@ -501,6 +502,9 @@ directory_initiate_command(const char *address, uint32_t addr, case DIR_PURPOSE_UPLOAD_RENDDESC: log_debug(LD_REND,"initiating hidden-service descriptor upload"); break; + case DIR_PURPOSE_UPLOAD_VOTE: + log_debug(LD_OR,"initiating server vote upload"); + break; case DIR_PURPOSE_FETCH_RUNNING_LIST: log_debug(LD_DIR,"initiating running-routers fetch"); break; @@ -685,6 +689,12 @@ directory_send_command(dir_connection_t *conn, httpcommand = "POST"; url = tor_strdup("/tor/"); break; + case DIR_PURPOSE_UPLOAD_VOTE: + tor_assert(!resource); + tor_assert(payload); + httpcommand = "POST"; + url = tor_strdup("/tor/post/vote"); + break; case DIR_PURPOSE_FETCH_RENDDESC: tor_assert(resource); tor_assert(!payload); @@ -1367,6 +1377,30 @@ connection_dir_client_reached_eof(dir_connection_t *conn) * dirservers down just because they don't like us. */ } + if (conn->_base.purpose == DIR_PURPOSE_UPLOAD_VOTE) { + switch (status_code) { + case 200: { + log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d", + conn->_base.address, conn->_base.port); + } + break; + case 400: + log_warn(LD_GENERAL,"http status 400 (%s) response after uploading " + "vote to dirserver '%s:%d'. Please correct.", + escaped(reason), conn->_base.address, conn->_base.port); + break; + default: + log_warn(LD_GENERAL, + "http status %d (%s) reason unexpected while uploading " + "vote to server '%s:%d').", + status_code, escaped(reason), conn->_base.address, + conn->_base.port); + break; + } + /* return 0 in all cases, since we don't want to mark any + * dirservers down just because they don't like us. */ + } + if (conn->_base.purpose == DIR_PURPOSE_FETCH_RENDDESC) { log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", @@ -2075,6 +2109,18 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, goto done; } + if (authdir_mode_v3(options) && + !strcmp(url,"/tor/post/vote")) { /* server descriptor post */ + const char *msg = "OK"; + if (dirserv_add_vote(body, &msg)) { + write_http_status_line(conn, 200, "Vote stored"); + } else { + tor_assert(msg); + write_http_status_line(conn, 400, msg); + } + goto done; + } + /* we didn't recognize the url */ write_http_status_line(conn, 404, "Not found"); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 33b3efd9a8..b0716d46f2 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1116,7 +1116,7 @@ cached_dir_decref(cached_dir_t *d) /** Allocate and return a new cached_dir_t containing the string <b>s</b>, * published at <b>published</b>. */ -static cached_dir_t * +cached_dir_t * new_cached_dir(char *s, time_t published) { cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t)); @@ -2075,7 +2075,9 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key, return status; } -static cached_dir_t * +/** DOCDOC */ +/* XXXX020 possibly rename and relocate to dirvote.c? */ +cached_dir_t * generate_v3_networkstatus(void) { crypto_pk_env_t *key = get_my_v3_authority_signing_key(); diff --git a/src/or/dirvote.c b/src/or/dirvote.c index c722c0861f..9c1b90a2e2 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -866,3 +866,157 @@ dirvote_recalculate_timing(time_t now) voting_schedule.voting_starts = start - vote_delay - dist_delay; } +/** DOCDOC */ +typedef struct pending_vote_t { + cached_dir_t *vote_body; + networkstatus_vote_t *vote; +} pending_vote_t; + +/** DOCDOC */ +static smartlist_t *pending_vote_list = NULL; +/** DOCDOC */ +static char *pending_consensus_body = NULL; + +/** DOCDOC */ +void +dirvote_perform_vote(void) +{ + cached_dir_t *new_vote = generate_v3_networkstatus(); + pending_vote_t *pending_vote; + const char *msg = ""; + + if ((pending_vote = dirvote_add_vote(tor_memdup(new_vote->dir, + new_vote->dir_len), &msg))) { + log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)", + msg); + return; + } + + directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE, + ROUTER_PURPOSE_GENERAL, + V3_AUTHORITY, + pending_vote->vote_body->dir, + pending_vote->vote_body->dir_len, 0); +} + +/** DOCDOC */ +void +dirvote_clear_pending_votes(void) +{ + if (!pending_vote_list) + return; + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, { + cached_dir_decref(v->vote_body); + v->vote_body = NULL; + networkstatus_vote_free(v->vote); + tor_free(v); + }); + smartlist_clear(pending_vote_list); +} + +/** DOCDOC */ +pending_vote_t * +dirvote_add_vote(char *vote_body, const char **msg_out) +{ + networkstatus_vote_t *vote; + networkstatus_voter_info_t *vi; + trusted_dir_server_t *ds; + pending_vote_t *pending_vote = NULL; + tor_assert(vote_body); + tor_assert(msg_out); + + if (!pending_vote_list) + pending_vote_list = smartlist_create(); + *msg_out = NULL; + + vote = networkstatus_parse_vote_from_string(vote_body, 1); + if (!vote) { + *msg_out = "Unable to parse vote"; + goto err; + } + tor_assert(smartlist_len(vote->voters) == 1); + vi = smartlist_get(vote->voters, 0); + tor_assert(vi->good_signature == 1); + ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest); + if (!ds || !(ds->type & V3_AUTHORITY)) { + *msg_out = "Vote not from a recognized v3 authority"; + goto err; + } + /* XXXX020 check times; make sure epochs match. */ + + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, { + if (! memcmp(v->vote->cert->cache_info.identity_digest, + vote->cert->cache_info.identity_digest, + DIGEST_LEN)) { + log_notice(LD_DIR, "We already have a pending vote from this dir"); + if (v->vote->published < vote->published) { + cached_dir_decref(v->vote_body); + networkstatus_vote_free(v->vote); + v->vote_body = new_cached_dir(vote_body, vote->published); + v->vote = vote; + *msg_out = "ok"; + return v; + } else { + *msg_out = "Already have a newer pending vote"; + goto err; + } + } + }); + + pending_vote = tor_malloc_zero(sizeof(pending_vote_t)); + pending_vote->vote_body = new_cached_dir(vote_body, vote->published); + pending_vote->vote = vote; + smartlist_add(pending_vote_list, pending_vote); + + *msg_out = "ok"; + return pending_vote; + err: + tor_free(vote_body); + if (vote) + networkstatus_vote_free(vote); + if (!*msg_out) + *msg_out = "Error adding vote"; + /*XXXX020 free other fields */ + return NULL; +} + +/** DOCDOC */ +int +dirvote_compute_consensus(void) +{ + /* Have we got enough votes to try? */ + int n_votes, n_voters; + smartlist_t *votes = NULL; + char *consensus_body = NULL; + authority_cert_t *my_cert; + + if (!pending_vote_list) + pending_vote_list = smartlist_create(); + + n_voters = get_n_authorities(V3_AUTHORITY); + n_votes = smartlist_len(pending_vote_list); + /* XXXX020 see if there are enough to go ahead. */ + + if (!(my_cert = get_my_v3_authority_cert())) { + log_warn(LD_DIR, "Can't generate consensus without a certificate."); + goto err; + } + + votes = smartlist_create(); + SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, + smartlist_add(votes, v->vote)); + + consensus_body = networkstatus_compute_consensus( + votes, n_voters, + my_cert->identity_key, + get_my_v3_authority_signing_key()); + + tor_free(pending_consensus_body); + pending_consensus_body = consensus_body; + + return 0; + err: + if (votes) + smartlist_free(votes); + return -1; +} diff --git a/src/or/or.h b/src/or/or.h index 2d2b5fad46..4af1b90f90 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -368,9 +368,14 @@ typedef enum { /** A connection to a directory server: upload a rendezvous * descriptor. */ #define DIR_PURPOSE_UPLOAD_RENDDESC 9 +/** A connection to a directory server: upload a v3 networkstatus vote. */ +#define DIR_PURPOSE_UPLOAD_VOTE 10 +/** A connection to a directory server: fetch a v3 networkstatus vote. */ +#define DIR_PURPOSE_FETCH_VOTE 11 + /** Purpose for connection at a directory server. */ -#define DIR_PURPOSE_SERVER 10 -#define _DIR_PURPOSE_MAX 10 +#define DIR_PURPOSE_SERVER 12 +#define _DIR_PURPOSE_MAX 12 #define _EXIT_PURPOSE_MIN 1 /** This exit stream wants to do an ordinary connect. */ @@ -2765,6 +2770,9 @@ int routerstatus_format_entry(char *buf, size_t buf_len, int first_line_only); void dirserv_free_all(void); void cached_dir_decref(cached_dir_t *d); +cached_dir_t *new_cached_dir(char *s, time_t published); + +cached_dir_t *generate_v3_networkstatus(void); #ifdef DIRSERV_PRIVATE char * @@ -2774,6 +2782,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_key, /********************************* dirvote.c ************************/ +/* vote manipulation */ void networkstatus_vote_free(networkstatus_vote_t *ns); char *networkstatus_compute_consensus(smartlist_t *votes, int total_authorities, @@ -2784,6 +2793,7 @@ networkstatus_voter_info_t *networkstatus_get_voter_by_id( const char *identity); int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus); +/* cert manipulation */ void authority_cert_free(authority_cert_t *cert); authority_cert_t *authority_cert_dup(authority_cert_t *cert); @@ -2794,10 +2804,17 @@ typedef struct vote_timing_t { int vote_delay; int dist_delay; } vote_timing_t; +/* vote scheduling */ void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); time_t dirvote_get_start_of_next_interval(time_t now, int interval); void dirvote_recalculate_timing(time_t now); +/* invoked on timers and by outside triggers. */ +void dirvote_perform_vote(void); +void dirvote_clear_pending_votes(void); +struct pending_vote_t * dirvote_add_vote(char *vote_body,const char **msg_out); +int dirvote_compute_consensus(void); + #ifdef DIRVOTE_PRIVATE int networkstatus_check_voter_signature(networkstatus_vote_t *consensus, networkstatus_voter_info_t *voter, @@ -3187,6 +3204,7 @@ void router_perform_bandwidth_test(int num_circs, time_t now); int authdir_mode(or_options_t *options); int authdir_mode_v1(or_options_t *options); int authdir_mode_v2(or_options_t *options); +int authdir_mode_v3(or_options_t *options); int authdir_mode_handles_descs(or_options_t *options); int authdir_mode_publishes_statuses(or_options_t *options); int authdir_mode_tests_reachability(or_options_t *options); diff --git a/src/or/router.c b/src/or/router.c index 77bcf19b7b..22b3eb4e42 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -714,6 +714,14 @@ authdir_mode_v2(or_options_t *options) { return authdir_mode(options) && options->V2AuthoritativeDir != 0; } +/** Return true iff we believe ourselves to be a v3 authoritative + * directory server. + */ +int +authdir_mode_v3(or_options_t *options) +{ + return authdir_mode(options) && options->V3AuthoritativeDir != 0; +} /** Return true iff we are an authoritative directory server that * is willing to receive or serve descriptors on its dirport. */ |