From 381766ce4b11454607f025aafb6767aa9789d271 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 14 Sep 2009 22:15:57 -0400 Subject: Implement proposal 167: Authorities vote on network parameters. This code adds a new field to vote on: "params". It consists of a list of sorted key=int pairs. The output is computed as the median of all the integers for any key on which anybody voted. Improved with input from Roger. --- src/common/torint.h | 3 ++ src/or/dirvote.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++- src/or/networkstatus.c | 4 ++ src/or/or.h | 10 +++-- src/or/routerparse.c | 31 +++++++++++++++ src/or/test.c | 62 +++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/common/torint.h b/src/common/torint.h index 1f7421174a..be624e04c6 100644 --- a/src/common/torint.h +++ b/src/common/torint.h @@ -117,6 +117,9 @@ typedef unsigned int uint32_t; #ifndef INT32_MAX #define INT32_MAX 0x7fffffffu #endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif #endif #if (SIZEOF_LONG == 4) diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 58b02da5cb..c2f0a33448 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -24,7 +24,9 @@ static int dirvote_publish_consensus(void); static char *make_consensus_method_list(int low, int high); /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 6 +#define MAX_SUPPORTED_CONSENSUS_METHOD 7 + +#define MIN_METHOD_FOR_PARAMS 7 /* ===== * Voting @@ -97,6 +99,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key, char fu[ISO_TIME_LEN+1]; char vu[ISO_TIME_LEN+1]; char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL); + char *params; authority_cert_t *cert = v3_ns->cert; char *methods = make_consensus_method_list(1, MAX_SUPPORTED_CONSENSUS_METHOD); @@ -105,6 +108,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key, format_iso_time(fu, v3_ns->fresh_until); format_iso_time(vu, v3_ns->valid_until); + if (v3_ns->net_params) + params = smartlist_join_strings(v3_ns->net_params, " ", 0, NULL); + else + params = tor_strdup(""); + tor_assert(cert); tor_snprintf(status, len, "network-status-version 3\n" @@ -117,6 +125,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key, "voting-delay %d %d\n" "%s" /* versions */ "known-flags %s\n" + "params %s\n" "dir-source %s %s %s %s %d %d\n" "contact %s\n", v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", @@ -125,9 +134,11 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key, v3_ns->vote_seconds, v3_ns->dist_seconds, version_lines, flags, + params, voter->nickname, fingerprint, voter->address, ipaddr, voter->dir_port, voter->or_port, voter->contact); + tor_free(params); tor_free(flags); tor_free(methods); outp = status + strlen(status); @@ -507,6 +518,89 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning) return result; } +/** Helper: given a list of valid networkstatus_t, return a new string + * containing the contents of the consensus network parameter set. + */ +/* private */ char * +dirvote_compute_params(smartlist_t *votes) +{ + int i; + int32_t *vals; + + int cur_param_len; + const char *cur_param; + const char *eq; + char *result; + + const int n_votes = smartlist_len(votes); + smartlist_t *output; + smartlist_t *param_list = smartlist_create(); + + /* We require that the parameter lists in the votes are well-formed: that + is, that their keywords are unique and sorted, and that their values are + between INT32_MIN and INT32_MAX inclusive. This should be guaranteed by + the parsing code. */ + + vals = tor_malloc(sizeof(int)*n_votes); + + SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { + if (!v->net_params) + continue; + smartlist_add_all(param_list, v->net_params); + } SMARTLIST_FOREACH_END(v); + + if (smartlist_len(param_list) == 0) { + tor_free(vals); + smartlist_free(param_list); + return NULL; + } + + smartlist_sort_strings(param_list); + i = 0; + cur_param = smartlist_get(param_list, 0); + eq = strchr(cur_param, '='); + tor_assert(eq); + cur_param_len = eq+1 - cur_param; + + output = smartlist_create(); + + SMARTLIST_FOREACH_BEGIN(param_list, const char *, param) { + const char *next_param; + int ok=0; + eq = strchr(param, '='); + tor_assert(iargs[i])); + goto err; + } + tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL); + if (!ok) { + log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); + goto err; + } + if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) { + log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]); + inorder = 0; + } + smartlist_add(ns->net_params, tor_strdup(tok->args[i])); + } + if (!inorder) { + log_warn(LD_DIR, "params not in order"); + goto err; + } + } + ns->voters = smartlist_create(); SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { diff --git a/src/or/test.c b/src/or/test.c index d34fc452b9..338195fd25 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -3355,6 +3355,54 @@ done: return; } +static void +test_dirutil_param_voting(void) +{ + networkstatus_t vote1, vote2, vote3, vote4; + smartlist_t *votes = smartlist_create(); + char *res = NULL; + + /* dirvote_compute_params only looks at the net_params field of the votes, + so that's all we need to set. + */ + memset(&vote1, 0, sizeof(vote1)); + memset(&vote2, 0, sizeof(vote2)); + memset(&vote3, 0, sizeof(vote3)); + memset(&vote4, 0, sizeof(vote4)); + vote1.net_params = smartlist_create(); + vote2.net_params = smartlist_create(); + vote3.net_params = smartlist_create(); + vote4.net_params = smartlist_create(); + smartlist_split_string(vote1.net_params, + "ab=90 abcd=20 cw=50 x-yz=-99", NULL, 0, 0); + smartlist_split_string(vote2.net_params, + "ab=27 cw=5 x-yz=88", NULL, 0, 0); + smartlist_split_string(vote3.net_params, + "abcd=20 c=60 cw=500 x-yz=-9 zzzzz=101", NULL, 0, 0); + smartlist_split_string(vote4.net_params, + "ab=900 abcd=200 c=1 cw=51 x-yz=100", NULL, 0, 0); + smartlist_add(votes, &vote1); + smartlist_add(votes, &vote2); + smartlist_add(votes, &vote3); + smartlist_add(votes, &vote4); + + res = dirvote_compute_params(votes); + test_streq(res, + "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101"); + + done: + tor_free(res); + SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(vote2.net_params, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(vote3.net_params, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(vote4.net_params, char *, cp, tor_free(cp)); + smartlist_free(vote1.net_params); + smartlist_free(vote2.net_params); + smartlist_free(vote3.net_params); + smartlist_free(vote4.net_params); + +} + extern const char AUTHORITY_CERT_1[]; extern const char AUTHORITY_SIGNKEY_1[]; extern const char AUTHORITY_CERT_2[]; @@ -3512,6 +3560,9 @@ test_v3_networkstatus(void) crypto_pk_get_digest(cert1->identity_key, voter->identity_digest); smartlist_add(vote->voters, voter); vote->cert = authority_cert_dup(cert1); + vote->net_params = smartlist_create(); + smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990", + NULL, 0, 0); vote->routerstatus_list = smartlist_create(); /* add the first routerstatus. */ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); @@ -3653,6 +3704,9 @@ test_v3_networkstatus(void) vote->dist_seconds = 300; authority_cert_free(vote->cert); vote->cert = authority_cert_dup(cert2); + vote->net_params = smartlist_create(); + smartlist_split_string(vote->net_params, "bar=2000000000 circuitwindow=20", + NULL, 0, 0); tor_free(vote->client_versions); tor_free(vote->server_versions); voter = smartlist_get(vote->voters, 0); @@ -3691,6 +3745,9 @@ test_v3_networkstatus(void) vote->dist_seconds = 250; authority_cert_free(vote->cert); vote->cert = authority_cert_dup(cert3); + vote->net_params = smartlist_create(); + smartlist_split_string(vote->net_params, "circuitwindow=80 foo=660", + NULL, 0, 0); smartlist_add(vote->supported_methods, tor_strdup("4")); vote->client_versions = tor_strdup("0.1.2.14,0.1.2.17"); vote->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16"); @@ -3747,6 +3804,10 @@ test_v3_networkstatus(void) test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:" "Running:Stable:V2Dir:Valid"); tor_free(cp); + cp = smartlist_join_strings(con->net_params, ":", 0, NULL); + test_streq(cp, "bar=2000000000:circuitwindow=80:foo=660"); + tor_free(cp); + test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/ /* The voter id digests should be in this order. */ test_assert(memcmp(cert2->cache_info.identity_digest, @@ -4866,6 +4927,7 @@ static struct { ENT(dir_format), ENT(dirutil), SUBENT(dirutil, measured_bw), + SUBENT(dirutil, param_voting), ENT(v3_networkstatus), ENT(policies), ENT(rend_fns), -- cgit v1.2.3-54-g00ecf