mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 13:53:31 +01:00
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.
This commit is contained in:
parent
0edc39303d
commit
381766ce4b
@ -1,4 +1,9 @@
|
||||
Changes in version 0.2.2.2-alpha - 2009-09-??
|
||||
o Major features:
|
||||
- Authorities can now vote on arbitary integer values as part of the
|
||||
consensus process. This is designed to help set network parameters.
|
||||
Implements proposal 167.
|
||||
|
||||
o Minor bugfixes:
|
||||
- Fix an extremely rare infinite recursion bug that could occur if
|
||||
we tried to log a message after shutting down the log subsystem.
|
||||
|
@ -1098,6 +1098,20 @@
|
||||
enough votes were counted for the consensus for an authoritative
|
||||
opinion to have been formed about their status.
|
||||
|
||||
"params" SP [Parameters] NL
|
||||
|
||||
[At most once]
|
||||
|
||||
Parameter ::= Keyword '=' Int32
|
||||
Int32 ::= A decimal integer between -2147483648 and 2147483647.
|
||||
Parameters ::= Parameter | Parameters SP Parameter
|
||||
|
||||
The parameters list, if present, contains a space-separated list of
|
||||
key-value pairs, sorted in lexical order by their keyword. Each
|
||||
parameter has its own meaning.
|
||||
|
||||
(Only included when the vote is generated with consensus-method 7 or
|
||||
later.)
|
||||
|
||||
The authority section of a vote contains the following items, followed
|
||||
in turn by the authority's current key certificate:
|
||||
@ -1406,6 +1420,10 @@
|
||||
|
||||
Known-flags is the union of all flags known by any voter.
|
||||
|
||||
Entries are given on the "params" line for every keyword on which any
|
||||
authority voted. The values given are the low-median of all votes on
|
||||
that keyword.
|
||||
|
||||
"client-versions" and "server-versions" are sorted in ascending
|
||||
order; A version is recommended in the consensus if it is recommended
|
||||
by more than half of the voting authorities that included a
|
||||
@ -1473,6 +1491,9 @@
|
||||
a router, the authorities produce a consensus containing a
|
||||
Bandwidth= keyword equal to the median of the Measured= votes.
|
||||
|
||||
* If consensus-method 7 or later is in use, the params line is
|
||||
included in the output.
|
||||
|
||||
The signatures at the end of a consensus document are sorted in
|
||||
ascending order by identity digest.
|
||||
|
||||
|
@ -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)
|
||||
|
105
src/or/dirvote.c
105
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(i<n_votes);
|
||||
vals[i++] = (int32_t)
|
||||
tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
|
||||
tor_assert(ok);
|
||||
|
||||
if (param_sl_idx+1 == smartlist_len(param_list))
|
||||
next_param = NULL;
|
||||
else
|
||||
next_param = smartlist_get(param_list, param_sl_idx+1);
|
||||
if (!next_param || strncmp(next_param, param, cur_param_len)) {
|
||||
/* We've reached the end of a series. */
|
||||
int32_t median = median_int32(vals, i);
|
||||
char *out_string = tor_malloc(64+cur_param_len);
|
||||
memcpy(out_string, param, cur_param_len);
|
||||
tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
|
||||
smartlist_add(output, out_string);
|
||||
|
||||
i = 0;
|
||||
if (next_param) {
|
||||
eq = strchr(next_param, '=');
|
||||
cur_param_len = eq+1 - next_param;
|
||||
}
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(param);
|
||||
|
||||
result = smartlist_join_strings(output, " ", 0, NULL);
|
||||
SMARTLIST_FOREACH(output, char *, cp, tor_free(cp));
|
||||
smartlist_free(output);
|
||||
smartlist_free(param_list);
|
||||
tor_free(vals);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
|
||||
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
|
||||
* and the number of <b>total_authorities</b> that we believe exist in our
|
||||
@ -659,6 +753,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
tor_free(flaglist);
|
||||
}
|
||||
|
||||
if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
|
||||
char *params = dirvote_compute_params(votes);
|
||||
if (params) {
|
||||
smartlist_add(chunks, tor_strdup("params "));
|
||||
smartlist_add(chunks, params);
|
||||
smartlist_add(chunks, tor_strdup("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the votes. */
|
||||
smartlist_sort(votes, _compare_votes_by_authority_id);
|
||||
/* Add the authority sections. */
|
||||
|
@ -286,6 +286,10 @@ networkstatus_vote_free(networkstatus_t *ns)
|
||||
SMARTLIST_FOREACH(ns->known_flags, char *, c, tor_free(c));
|
||||
smartlist_free(ns->known_flags);
|
||||
}
|
||||
if (ns->net_params) {
|
||||
SMARTLIST_FOREACH(ns->net_params, char *, c, tor_free(c));
|
||||
smartlist_free(ns->net_params);
|
||||
}
|
||||
if (ns->supported_methods) {
|
||||
SMARTLIST_FOREACH(ns->supported_methods, char *, c, tor_free(c));
|
||||
smartlist_free(ns->supported_methods);
|
||||
|
10
src/or/or.h
10
src/or/or.h
@ -1672,6 +1672,10 @@ typedef struct networkstatus_t {
|
||||
* not listed here, the voter has no opinion on what its value should be. */
|
||||
smartlist_t *known_flags;
|
||||
|
||||
/** List of key=value strings for the parameters in this vote or
|
||||
* consensus, sorted by key. */
|
||||
smartlist_t *net_params;
|
||||
|
||||
/** List of networkstatus_voter_info_t. For a vote, only one element
|
||||
* is included. For a consensus, one element is included for every voter
|
||||
* whose vote contributed to the consensus. */
|
||||
@ -3661,9 +3665,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
|
||||
authority_cert_t *cert);
|
||||
|
||||
#ifdef DIRVOTE_PRIVATE
|
||||
char *
|
||||
format_networkstatus_vote(crypto_pk_env_t *private_key,
|
||||
networkstatus_t *v3_ns);
|
||||
char *format_networkstatus_vote(crypto_pk_env_t *private_key,
|
||||
networkstatus_t *v3_ns);
|
||||
char *dirvote_compute_params(smartlist_t *votes);
|
||||
#endif
|
||||
|
||||
/********************************* dns.c ***************************/
|
||||
|
@ -102,6 +102,7 @@ typedef enum {
|
||||
K_VOTING_DELAY,
|
||||
|
||||
K_KNOWN_FLAGS,
|
||||
K_PARAMS,
|
||||
K_VOTE_DIGEST,
|
||||
K_CONSENSUS_DIGEST,
|
||||
K_CONSENSUS_METHODS,
|
||||
@ -433,6 +434,7 @@ static token_rule_t networkstatus_token_table[] = {
|
||||
T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
|
||||
T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
|
||||
T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
|
||||
T01("params", K_PARAMS, ARGS, NO_OBJ ),
|
||||
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||
|
||||
CERTIFICATE_MEMBERS
|
||||
@ -470,6 +472,7 @@ static token_rule_t networkstatus_consensus_token_table[] = {
|
||||
T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
|
||||
T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
|
||||
T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ),
|
||||
T01("params", K_PARAMS, ARGS, NO_OBJ ),
|
||||
|
||||
END_OF_TABLE
|
||||
};
|
||||
@ -2408,6 +2411,34 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
|
||||
goto err;
|
||||
}
|
||||
|
||||
tok = find_opt_by_keyword(tokens, K_PARAMS);
|
||||
if (tok) {
|
||||
inorder = 1;
|
||||
ns->net_params = smartlist_create();
|
||||
for (i = 0; i < tok->n_args; ++i) {
|
||||
int ok=0;
|
||||
char *eq = strchr(tok->args[i], '=');
|
||||
if (!eq) {
|
||||
log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[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) {
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user