mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
Merge commit 'mikeperry/bandwidth-voting-final'
This commit is contained in:
commit
b9e45cc508
@ -1029,13 +1029,20 @@
|
|||||||
descriptors if they would cause "v" lines to be over 128 characters
|
descriptors if they would cause "v" lines to be over 128 characters
|
||||||
long.
|
long.
|
||||||
|
|
||||||
"w" SP "Bandwidth=" INT NL
|
"w" SP "Bandwidth=" INT [SP "Measured=" INT] NL
|
||||||
|
|
||||||
[At most once.]
|
[At most once.]
|
||||||
|
|
||||||
An estimate of the bandwidth of this server, in an arbitrary
|
An estimate of the bandwidth of this server, in an arbitrary
|
||||||
unit (currently kilobytes per second). Used to weight router
|
unit (currently kilobytes per second). Used to weight router
|
||||||
selection. Other weighting keywords may be added later.
|
selection.
|
||||||
|
|
||||||
|
Additionally, the Measured= keyword is present in votes by
|
||||||
|
participating bandwidth measurement authorites to indicate
|
||||||
|
a measured bandwidth currently produced by measuring stream
|
||||||
|
capacities.
|
||||||
|
|
||||||
|
Other weighting keywords may be added later.
|
||||||
Clients MUST ignore keywords they do not recognize.
|
Clients MUST ignore keywords they do not recognize.
|
||||||
|
|
||||||
"p" SP ("accept" / "reject") SP PortList NL
|
"p" SP ("accept" / "reject") SP PortList NL
|
||||||
@ -1178,6 +1185,13 @@
|
|||||||
rate limit from the router descriptor. It is given in kilobytes
|
rate limit from the router descriptor. It is given in kilobytes
|
||||||
per second, and capped at some arbitrary value (currently 10 MB/s).
|
per second, and capped at some arbitrary value (currently 10 MB/s).
|
||||||
|
|
||||||
|
The Measured= keyword on a "w" line vote is currently computed
|
||||||
|
by multiplying the previous published consensus bandwidth by the
|
||||||
|
ratio of the measured average node stream capacity to the network
|
||||||
|
average. If 3 or more authorities provide a Measured= keyword for
|
||||||
|
a router, the authorites produce a consensus containing a "w"
|
||||||
|
Bandwidth= keyword equal to the median of the Measured= votes.
|
||||||
|
|
||||||
The ports listed in a "p" line should be taken as those ports for
|
The ports listed in a "p" line should be taken as those ports for
|
||||||
which the router's exit policy permits 'most' addresses, ignoring any
|
which the router's exit policy permits 'most' addresses, ignoring any
|
||||||
accept not for all addresses, ignoring all rejects for private
|
accept not for all addresses, ignoring all rejects for private
|
||||||
@ -1260,6 +1274,11 @@
|
|||||||
one, breaking ties in favor of the lexicographically larger
|
one, breaking ties in favor of the lexicographically larger
|
||||||
vote.) The port list is encoded as specified in 3.4.2.
|
vote.) The port list is encoded as specified in 3.4.2.
|
||||||
|
|
||||||
|
* If consensus-method 6 or later is in use and if 3 or more
|
||||||
|
authorities provide a Measured= keyword in their votes for
|
||||||
|
a router, the authorities produce a consensus containing a
|
||||||
|
Bandwidth= keyword equal to the median of the Measured= votes.
|
||||||
|
|
||||||
The signatures at the end of a consensus document are sorted in
|
The signatures at the end of a consensus document are sorted in
|
||||||
ascending order by identity digest.
|
ascending order by identity digest.
|
||||||
|
|
||||||
@ -1280,6 +1299,7 @@
|
|||||||
"3" -- Added legacy ID key support to aid in authority ID key rollovers
|
"3" -- Added legacy ID key support to aid in authority ID key rollovers
|
||||||
"4" -- No longer list routers that are not running in the consensus
|
"4" -- No longer list routers that are not running in the consensus
|
||||||
"5" -- adds support for "w" and "p" lines.
|
"5" -- adds support for "w" and "p" lines.
|
||||||
|
"6" -- Prefers measured bandwidth values rather than advertised
|
||||||
|
|
||||||
Before generating a consensus, an authority must decide which consensus
|
Before generating a consensus, an authority must decide which consensus
|
||||||
method to use. To do this, it looks for the highest version number
|
method to use. To do this, it looks for the highest version number
|
||||||
|
@ -398,6 +398,37 @@ const char TOR_TOLOWER_TABLE[256] = {
|
|||||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
|
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Implementation of strtok_r for platforms whose coders haven't figured out
|
||||||
|
* how to write one. Hey guys! You can use this code here for free! */
|
||||||
|
char *
|
||||||
|
tor_strtok_r_impl(char *str, const char *sep, char **lasts)
|
||||||
|
{
|
||||||
|
char *cp, *start;
|
||||||
|
if (str)
|
||||||
|
start = cp = *lasts = str;
|
||||||
|
else if (!*lasts)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
start = cp = *lasts;
|
||||||
|
|
||||||
|
tor_assert(*sep);
|
||||||
|
if (sep[1]) {
|
||||||
|
while (*cp && !strchr(sep, *cp))
|
||||||
|
++cp;
|
||||||
|
} else {
|
||||||
|
tor_assert(strlen(sep) == 1);
|
||||||
|
cp = strchr(cp, *sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cp || !*cp) {
|
||||||
|
*lasts = NULL;
|
||||||
|
} else {
|
||||||
|
*cp++ = '\0';
|
||||||
|
*lasts = cp;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
/** Take a filename and return a pointer to its final element. This
|
/** Take a filename and return a pointer to its final element. This
|
||||||
* function is called on __FILE__ to fix a MSVC nit where __FILE__
|
* function is called on __FILE__ to fix a MSVC nit where __FILE__
|
||||||
|
@ -267,6 +267,13 @@ extern const char TOR_TOLOWER_TABLE[];
|
|||||||
#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c])
|
#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c])
|
||||||
#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c])
|
#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c])
|
||||||
|
|
||||||
|
char *tor_strtok_r_impl(char *str, const char *sep, char **lasts);
|
||||||
|
#ifdef HAVE_STRTOK_R
|
||||||
|
#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts)
|
||||||
|
#else
|
||||||
|
#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
|
#define _SHORT_FILE_ (tor_fix_source_file(__FILE__))
|
||||||
const char *tor_fix_source_file(const char *fname);
|
const char *tor_fix_source_file(const char *fname);
|
||||||
|
@ -338,6 +338,7 @@ static config_var_t _option_vars[] = {
|
|||||||
V(V3AuthDistDelay, INTERVAL, "5 minutes"),
|
V(V3AuthDistDelay, INTERVAL, "5 minutes"),
|
||||||
V(V3AuthNIntervalsValid, UINT, "3"),
|
V(V3AuthNIntervalsValid, UINT, "3"),
|
||||||
V(V3AuthUseLegacyKey, BOOL, "0"),
|
V(V3AuthUseLegacyKey, BOOL, "0"),
|
||||||
|
V(V3BandwidthsFile, FILENAME, NULL),
|
||||||
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
|
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
|
||||||
V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
|
V(VirtualAddrNetwork, STRING, "127.192.0.0/10"),
|
||||||
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
|
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
|
||||||
@ -3210,6 +3211,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||||||
options->V3AuthoritativeDir))
|
options->V3AuthoritativeDir))
|
||||||
REJECT("AuthoritativeDir is set, but none of "
|
REJECT("AuthoritativeDir is set, but none of "
|
||||||
"(Bridge/HS/V1/V2/V3)AuthoritativeDir is set.");
|
"(Bridge/HS/V1/V2/V3)AuthoritativeDir is set.");
|
||||||
|
/* If we have a v3bandwidthsfile and it's broken, complain on startup */
|
||||||
|
if (options->V3BandwidthsFile && !old_options) {
|
||||||
|
dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->AuthoritativeDir && !options->DirPort)
|
if (options->AuthoritativeDir && !options->DirPort)
|
||||||
|
314
src/or/dirserv.c
314
src/or/dirserv.c
@ -63,6 +63,9 @@ static signed_descriptor_t *get_signed_descriptor_by_fp(const char *fp,
|
|||||||
time_t publish_cutoff);
|
time_t publish_cutoff);
|
||||||
static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
|
static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg);
|
||||||
|
|
||||||
|
/************** Measured Bandwidth parsing code ******/
|
||||||
|
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
|
||||||
|
|
||||||
/************** Fingerprint handling code ************/
|
/************** Fingerprint handling code ************/
|
||||||
|
|
||||||
#define FP_NAMED 1 /**< Listed in fingerprint file. */
|
#define FP_NAMED 1 /**< Listed in fingerprint file. */
|
||||||
@ -1855,16 +1858,18 @@ version_from_platform(const char *platform)
|
|||||||
* which has at least <b>buf_len</b> free characters. Do NUL-termination.
|
* which has at least <b>buf_len</b> free characters. Do NUL-termination.
|
||||||
* Use the same format as in network-status documents. If <b>version</b> is
|
* Use the same format as in network-status documents. If <b>version</b> is
|
||||||
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
|
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
|
||||||
* failure. If <b>first_line_only</b> is true, don't include any flags
|
* failure.
|
||||||
* or version line.
|
*
|
||||||
|
* The format argument has three possible values:
|
||||||
|
* NS_V2 - Output an entry suitable for a V2 NS opinion document
|
||||||
|
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
|
||||||
|
* NS_V3_VOTE - Output a complete V3 NS vote
|
||||||
|
* NS_CONTROL_PORT - Output a NS docunent for the control port
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
routerstatus_format_entry(char *buf, size_t buf_len,
|
routerstatus_format_entry(char *buf, size_t buf_len,
|
||||||
routerstatus_t *rs, const char *version,
|
routerstatus_t *rs, const char *version,
|
||||||
int first_line_only, int v2_format)
|
routerstatus_format_type_t format)
|
||||||
/* XXX: first_line_only and v2_format should probably be be both
|
|
||||||
* replaced by a single purpose parameter.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
@ -1895,7 +1900,12 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (first_line_only)
|
|
||||||
|
/* TODO: Maybe we want to pass in what we need to build the rest of
|
||||||
|
* this here, instead of in the caller. Then we could use the
|
||||||
|
* networkstatus_type_t values, with an additional control port value
|
||||||
|
* added -MP */
|
||||||
|
if (format == NS_V3_CONSENSUS)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cp = buf + strlen(buf);
|
cp = buf + strlen(buf);
|
||||||
@ -1932,62 +1942,87 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||||||
cp += strlen(cp);
|
cp += strlen(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v2_format) {
|
if (format != NS_V2) {
|
||||||
routerinfo_t* desc = router_get_by_digest(rs->identity_digest);
|
routerinfo_t* desc = router_get_by_digest(rs->identity_digest);
|
||||||
|
uint32_t bw;
|
||||||
|
|
||||||
/* Blow up more or less nicely if we didn't get anything or not the
|
if (format != NS_CONTROL_PORT) {
|
||||||
* thing we expected.
|
/* Blow up more or less nicely if we didn't get anything or not the
|
||||||
*/
|
* thing we expected.
|
||||||
if (!desc) {
|
*/
|
||||||
char id[HEX_DIGEST_LEN+1];
|
if (!desc) {
|
||||||
char dd[HEX_DIGEST_LEN+1];
|
char id[HEX_DIGEST_LEN+1];
|
||||||
|
char dd[HEX_DIGEST_LEN+1];
|
||||||
|
|
||||||
base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
|
base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
|
||||||
base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
|
base16_encode(dd, sizeof(dd), rs->descriptor_digest, DIGEST_LEN);
|
||||||
log_warn(LD_BUG, "Cannot get any descriptor for %s "
|
log_warn(LD_BUG, "Cannot get any descriptor for %s "
|
||||||
"(wanted descriptor %s).",
|
"(wanted descriptor %s).",
|
||||||
id, dd);
|
id, dd);
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
if (memcmp(desc->cache_info.signed_descriptor_digest,
|
|
||||||
rs->descriptor_digest,
|
|
||||||
DIGEST_LEN)) {
|
|
||||||
char rl_d[HEX_DIGEST_LEN+1];
|
|
||||||
char rs_d[HEX_DIGEST_LEN+1];
|
|
||||||
char id[HEX_DIGEST_LEN+1];
|
|
||||||
|
|
||||||
base16_encode(rl_d, sizeof(rl_d),
|
/* This assert can fire for the control port, because
|
||||||
desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
|
* it can request NS documents before all descriptors
|
||||||
base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
|
* have been fetched. */
|
||||||
base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
|
if (memcmp(desc->cache_info.signed_descriptor_digest,
|
||||||
log_err(LD_BUG, "descriptor digest in routerlist does not match "
|
rs->descriptor_digest,
|
||||||
"the one in routerstatus: %s vs %s "
|
DIGEST_LEN)) {
|
||||||
"(router %s)\n",
|
char rl_d[HEX_DIGEST_LEN+1];
|
||||||
rl_d, rs_d, id);
|
char rs_d[HEX_DIGEST_LEN+1];
|
||||||
|
char id[HEX_DIGEST_LEN+1];
|
||||||
|
|
||||||
tor_assert(!memcmp(desc->cache_info.signed_descriptor_digest,
|
base16_encode(rl_d, sizeof(rl_d),
|
||||||
rs->descriptor_digest,
|
desc->cache_info.signed_descriptor_digest, DIGEST_LEN);
|
||||||
DIGEST_LEN));
|
base16_encode(rs_d, sizeof(rs_d), rs->descriptor_digest, DIGEST_LEN);
|
||||||
};
|
base16_encode(id, sizeof(id), rs->identity_digest, DIGEST_LEN);
|
||||||
|
log_err(LD_BUG, "descriptor digest in routerlist does not match "
|
||||||
|
"the one in routerstatus: %s vs %s "
|
||||||
|
"(router %s)\n",
|
||||||
|
rl_d, rs_d, id);
|
||||||
|
|
||||||
|
tor_assert(!memcmp(desc->cache_info.signed_descriptor_digest,
|
||||||
|
rs->descriptor_digest,
|
||||||
|
DIGEST_LEN));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
|
||||||
|
bw = rs->bandwidth;
|
||||||
|
} else {
|
||||||
|
tor_assert(desc);
|
||||||
|
bw = router_get_advertised_bandwidth_capped(desc) / 1000;
|
||||||
|
}
|
||||||
r = tor_snprintf(cp, buf_len - (cp-buf),
|
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||||
"w Bandwidth=%d\n",
|
"w Bandwidth=%d\n", bw);
|
||||||
router_get_advertised_bandwidth_capped(desc) / 1024);
|
|
||||||
if (r<0) {
|
|
||||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
cp += strlen(cp);
|
|
||||||
|
|
||||||
summary = policy_summarize(desc->exit_policy);
|
|
||||||
r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
|
|
||||||
if (r<0) {
|
if (r<0) {
|
||||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||||
tor_free(summary);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cp += strlen(cp);
|
cp += strlen(cp);
|
||||||
tor_free(summary);
|
if (format == NS_V3_VOTE && rs->has_measured_bw) {
|
||||||
|
*--cp = '\0'; /* Kill "\n" */
|
||||||
|
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||||
|
" Measured=%d\n", rs->measured_bw);
|
||||||
|
if (r<0) {
|
||||||
|
log_warn(LD_BUG, "Not enough space in buffer for weight line.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cp += strlen(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc) {
|
||||||
|
summary = policy_summarize(desc->exit_policy);
|
||||||
|
r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
|
||||||
|
if (r<0) {
|
||||||
|
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||||
|
tor_free(summary);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cp += strlen(cp);
|
||||||
|
tor_free(summary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2190,6 +2225,177 @@ router_clear_status_flags(routerinfo_t *router)
|
|||||||
router->is_bad_exit = router->is_bad_directory = 0;
|
router->is_bad_exit = router->is_bad_directory = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to parse out a line in the measured bandwidth file
|
||||||
|
* into a measured_bw_line_t output structure. Returns -1 on failure
|
||||||
|
* or 0 on success.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
|
||||||
|
{
|
||||||
|
char *line = tor_strdup(orig_line);
|
||||||
|
char *cp = line;
|
||||||
|
int got_bw = 0;
|
||||||
|
int got_node_id = 0;
|
||||||
|
char *strtok_state; /* lame sauce d'jour */
|
||||||
|
cp = tor_strtok_r(cp, " \t", &strtok_state);
|
||||||
|
|
||||||
|
if (!cp) {
|
||||||
|
log_warn(LD_DIRSERV, "Invalid line in bandwidth file: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orig_line[strlen(orig_line)-1] != '\n') {
|
||||||
|
log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (strcmpstart(cp, "bw=") == 0) {
|
||||||
|
int parse_ok = 0;
|
||||||
|
char *endptr;
|
||||||
|
if (got_bw) {
|
||||||
|
log_warn(LD_DIRSERV, "Double bw= in bandwidth file line: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cp+=strlen("bw=");
|
||||||
|
|
||||||
|
out->bw = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr);
|
||||||
|
if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) {
|
||||||
|
log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
got_bw=1;
|
||||||
|
} else if (strcmpstart(cp, "node_id=$") == 0) {
|
||||||
|
if (got_node_id) {
|
||||||
|
log_warn(LD_DIRSERV, "Double node_id= in bandwidth file line: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cp+=strlen("node_id=$");
|
||||||
|
|
||||||
|
if (strlen(cp) != HEX_DIGEST_LEN ||
|
||||||
|
base16_decode(out->node_id, DIGEST_LEN, cp, HEX_DIGEST_LEN)) {
|
||||||
|
log_warn(LD_DIRSERV, "Invalid node_id in bandwidth file line: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(out->node_hex, cp, sizeof(out->node_hex));
|
||||||
|
got_node_id=1;
|
||||||
|
}
|
||||||
|
} while ((cp = tor_strtok_r(NULL, " \t", &strtok_state)));
|
||||||
|
|
||||||
|
if (got_bw && got_node_id) {
|
||||||
|
tor_free(line);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s",
|
||||||
|
escaped(orig_line));
|
||||||
|
tor_free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to apply a parsed measurement line to a list
|
||||||
|
* of bandwidth statuses. Returns true if a line is found,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
measured_bw_line_apply(measured_bw_line_t *parsed_line,
|
||||||
|
smartlist_t *routerstatuses)
|
||||||
|
{
|
||||||
|
routerstatus_t *rs = NULL;
|
||||||
|
if (!routerstatuses)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rs = smartlist_bsearch(routerstatuses, parsed_line->node_id,
|
||||||
|
compare_digest_to_routerstatus_entry);
|
||||||
|
|
||||||
|
if (rs) {
|
||||||
|
rs->has_measured_bw = 1;
|
||||||
|
rs->measured_bw = parsed_line->bw;
|
||||||
|
} else {
|
||||||
|
log_info(LD_DIRSERV, "Node ID %s not found in routerstatus list",
|
||||||
|
parsed_line->node_hex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the measured bandwidth file and apply it to the list of
|
||||||
|
* routerstatuses. Returns -1 on error, 0 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dirserv_read_measured_bandwidths(const char *from_file,
|
||||||
|
smartlist_t *routerstatuses)
|
||||||
|
{
|
||||||
|
char line[256];
|
||||||
|
FILE *fp = fopen(from_file, "r");
|
||||||
|
int applied_lines = 0;
|
||||||
|
time_t file_time;
|
||||||
|
int ok;
|
||||||
|
if (fp == NULL) {
|
||||||
|
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
|
||||||
|
from_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fgets(line, sizeof(line), fp)
|
||||||
|
|| !strlen(line) || line[strlen(line)-1] != '\n') {
|
||||||
|
log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s",
|
||||||
|
escaped(line));
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
line[strlen(line)-1] = '\0';
|
||||||
|
file_time = tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL);
|
||||||
|
if (!ok) {
|
||||||
|
log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s",
|
||||||
|
escaped(line));
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
|
||||||
|
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
|
||||||
|
(unsigned)(time(NULL) - file_time));
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routerstatuses)
|
||||||
|
smartlist_sort(routerstatuses, compare_routerstatus_entries);
|
||||||
|
|
||||||
|
while (!feof(fp)) {
|
||||||
|
measured_bw_line_t parsed_line;
|
||||||
|
if (fgets(line, sizeof(line), fp) && strlen(line)) {
|
||||||
|
if (measured_bw_line_parse(&parsed_line, line) != -1) {
|
||||||
|
if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
|
||||||
|
applied_lines++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
log_notice(LD_DIRSERV,
|
||||||
|
"Bandwidth measurement file successfully read. "
|
||||||
|
"Applied %d measurements.", applied_lines);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a new networkstatus_t* containing our current opinion. (For v3
|
/** Return a new networkstatus_t* containing our current opinion. (For v3
|
||||||
* authorities) */
|
* authorities) */
|
||||||
networkstatus_t *
|
networkstatus_t *
|
||||||
@ -2289,9 +2495,15 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
|
|||||||
smartlist_add(routerstatuses, vrs);
|
smartlist_add(routerstatuses, vrs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
smartlist_free(routers);
|
smartlist_free(routers);
|
||||||
digestmap_free(omit_as_sybil, NULL);
|
digestmap_free(omit_as_sybil, NULL);
|
||||||
|
|
||||||
|
if (options->V3BandwidthsFile) {
|
||||||
|
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
|
||||||
|
routerstatuses);
|
||||||
|
}
|
||||||
|
|
||||||
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
|
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
|
||||||
|
|
||||||
v3_out->type = NS_TYPE_VOTE;
|
v3_out->type = NS_TYPE_VOTE;
|
||||||
@ -2495,7 +2707,7 @@ generate_v2_networkstatus_opinion(void)
|
|||||||
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
||||||
clear_status_flags_on_sybil(&rs);
|
clear_status_flags_on_sybil(&rs);
|
||||||
|
|
||||||
if (routerstatus_format_entry(outp, endp-outp, &rs, version, 0, 1)) {
|
if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2)) {
|
||||||
log_warn(LD_BUG, "Unable to print router status.");
|
log_warn(LD_BUG, "Unable to print router status.");
|
||||||
tor_free(version);
|
tor_free(version);
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -103,7 +103,10 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|||||||
tor_snprintf(status, len,
|
tor_snprintf(status, len,
|
||||||
"network-status-version 3\n"
|
"network-status-version 3\n"
|
||||||
"vote-status %s\n"
|
"vote-status %s\n"
|
||||||
"consensus-methods 1 2 3 4 5\n"
|
/* XXX: If you change this value, you also need to
|
||||||
|
* change consensus_method_is_supported().
|
||||||
|
* Perhaps we should unify these somehow? */
|
||||||
|
"consensus-methods 1 2 3 4 5 6\n"
|
||||||
"published %s\n"
|
"published %s\n"
|
||||||
"valid-after %s\n"
|
"valid-after %s\n"
|
||||||
"fresh-until %s\n"
|
"fresh-until %s\n"
|
||||||
@ -142,7 +145,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
|
|||||||
SMARTLIST_FOREACH(v3_ns->routerstatus_list, vote_routerstatus_t *, vrs,
|
SMARTLIST_FOREACH(v3_ns->routerstatus_list, vote_routerstatus_t *, vrs,
|
||||||
{
|
{
|
||||||
if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
|
if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
|
||||||
vrs->version, 0, 0) < 0) {
|
vrs->version, NS_V3_VOTE) < 0) {
|
||||||
log_warn(LD_BUG, "Unable to print router status.");
|
log_warn(LD_BUG, "Unable to print router status.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -455,7 +458,10 @@ compute_consensus_method(smartlist_t *votes)
|
|||||||
static int
|
static int
|
||||||
consensus_method_is_supported(int method)
|
consensus_method_is_supported(int method)
|
||||||
{
|
{
|
||||||
return (method >= 1) && (method <= 5);
|
/* XXX: If you change this value, you also need to change
|
||||||
|
* format_networkstatus_vote(). Perhaps we should unify
|
||||||
|
* these somehow? */
|
||||||
|
return (method >= 1) && (method <= 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper: given <b>lst</b>, a list of version strings such that every
|
/** Helper: given <b>lst</b>, a list of version strings such that every
|
||||||
@ -701,7 +707,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
smartlist_t *versions = smartlist_create();
|
smartlist_t *versions = smartlist_create();
|
||||||
smartlist_t *exitsummaries = smartlist_create();
|
smartlist_t *exitsummaries = smartlist_create();
|
||||||
uint32_t *bandwidths = tor_malloc(sizeof(uint32_t) * smartlist_len(votes));
|
uint32_t *bandwidths = tor_malloc(sizeof(uint32_t) * smartlist_len(votes));
|
||||||
|
uint32_t *measured_bws = tor_malloc(sizeof(uint32_t) *
|
||||||
|
smartlist_len(votes));
|
||||||
int num_bandwidths;
|
int num_bandwidths;
|
||||||
|
int num_mbws;
|
||||||
|
|
||||||
int *n_voter_flags; /* n_voter_flags[j] is the number of flags that
|
int *n_voter_flags; /* n_voter_flags[j] is the number of flags that
|
||||||
* votes[j] knows about. */
|
* votes[j] knows about. */
|
||||||
@ -835,6 +844,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
smartlist_clear(chosen_flags);
|
smartlist_clear(chosen_flags);
|
||||||
smartlist_clear(versions);
|
smartlist_clear(versions);
|
||||||
num_bandwidths = 0;
|
num_bandwidths = 0;
|
||||||
|
num_mbws = 0;
|
||||||
|
|
||||||
/* Okay, go through all the entries for this digest. */
|
/* Okay, go through all the entries for this digest. */
|
||||||
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
|
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
|
||||||
@ -868,6 +878,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* count bandwidths */
|
/* count bandwidths */
|
||||||
|
if (rs->status.has_measured_bw)
|
||||||
|
measured_bws[num_mbws++] = rs->status.measured_bw;
|
||||||
|
|
||||||
if (rs->status.has_bandwidth)
|
if (rs->status.has_bandwidth)
|
||||||
bandwidths[num_bandwidths++] = rs->status.bandwidth;
|
bandwidths[num_bandwidths++] = rs->status.bandwidth;
|
||||||
} SMARTLIST_FOREACH_END(v);
|
} SMARTLIST_FOREACH_END(v);
|
||||||
@ -945,7 +958,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Pick a bandwidth */
|
/* Pick a bandwidth */
|
||||||
if (consensus_method >= 5 && num_bandwidths > 0) {
|
if (consensus_method >= 6 && num_mbws > 2) {
|
||||||
|
rs_out.has_bandwidth = 1;
|
||||||
|
rs_out.bandwidth = median_uint32(measured_bws, num_mbws);
|
||||||
|
} else if (consensus_method >= 5 && num_bandwidths > 0) {
|
||||||
rs_out.has_bandwidth = 1;
|
rs_out.has_bandwidth = 1;
|
||||||
rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
|
rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
|
||||||
}
|
}
|
||||||
@ -1036,7 +1052,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
|
|
||||||
/* Okay!! Now we can write the descriptor... */
|
/* Okay!! Now we can write the descriptor... */
|
||||||
/* First line goes into "buf". */
|
/* First line goes into "buf". */
|
||||||
routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL, 1, 0);
|
routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL,
|
||||||
|
NS_V3_CONSENSUS);
|
||||||
smartlist_add(chunks, tor_strdup(buf));
|
smartlist_add(chunks, tor_strdup(buf));
|
||||||
/* Second line is all flags. The "\n" is missing. */
|
/* Second line is all flags. The "\n" is missing. */
|
||||||
smartlist_add(chunks,
|
smartlist_add(chunks,
|
||||||
@ -1055,8 +1072,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||||||
log_warn(LD_BUG, "Not enough space in buffer for weight line.");
|
log_warn(LD_BUG, "Not enough space in buffer for weight line.");
|
||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
smartlist_add(chunks, tor_strdup(buf));
|
smartlist_add(chunks, tor_strdup(buf));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Now the exitpolicy summary line. */
|
/* Now the exitpolicy summary line. */
|
||||||
if (rs_out.has_exitsummary) {
|
if (rs_out.has_exitsummary) {
|
||||||
char buf[MAX_POLICY_LINE_LEN+1];
|
char buf[MAX_POLICY_LINE_LEN+1];
|
||||||
|
@ -2889,14 +2889,6 @@ evdns_resolv_set_defaults(int flags) {
|
|||||||
if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
|
if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_STRTOK_R
|
|
||||||
static char *
|
|
||||||
strtok_r(char *s, const char *delim, char **state) {
|
|
||||||
(void)state;
|
|
||||||
return strtok(s, delim);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* helper version of atoi which returns -1 on error */
|
/* helper version of atoi which returns -1 on error */
|
||||||
static int
|
static int
|
||||||
strtoint(const char *const str) {
|
strtoint(const char *const str) {
|
||||||
@ -2973,9 +2965,9 @@ static void
|
|||||||
resolv_conf_parse_line(char *const start, int flags) {
|
resolv_conf_parse_line(char *const start, int flags) {
|
||||||
char *strtok_state;
|
char *strtok_state;
|
||||||
static const char *const delims = " \t";
|
static const char *const delims = " \t";
|
||||||
#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
|
#define NEXT_TOKEN tor_strtok_r(NULL, delims, &strtok_state)
|
||||||
|
|
||||||
char *const first_token = strtok_r(start, delims, &strtok_state);
|
char *const first_token = tor_strtok_r(start, delims, &strtok_state);
|
||||||
if (!first_token) return;
|
if (!first_token) return;
|
||||||
|
|
||||||
if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
|
if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
|
||||||
|
@ -780,8 +780,8 @@ networkstatus_v2_list_clean(time_t now)
|
|||||||
|
|
||||||
/** Helper for bsearching a list of routerstatus_t pointers: compare a
|
/** Helper for bsearching a list of routerstatus_t pointers: compare a
|
||||||
* digest in the key to the identity digest of a routerstatus_t. */
|
* digest in the key to the identity digest of a routerstatus_t. */
|
||||||
static int
|
int
|
||||||
_compare_digest_to_routerstatus_entry(const void *_key, const void **_member)
|
compare_digest_to_routerstatus_entry(const void *_key, const void **_member)
|
||||||
{
|
{
|
||||||
const char *key = _key;
|
const char *key = _key;
|
||||||
const routerstatus_t *rs = *_member;
|
const routerstatus_t *rs = *_member;
|
||||||
@ -794,7 +794,7 @@ routerstatus_t *
|
|||||||
networkstatus_v2_find_entry(networkstatus_v2_t *ns, const char *digest)
|
networkstatus_v2_find_entry(networkstatus_v2_t *ns, const char *digest)
|
||||||
{
|
{
|
||||||
return smartlist_bsearch(ns->entries, digest,
|
return smartlist_bsearch(ns->entries, digest,
|
||||||
_compare_digest_to_routerstatus_entry);
|
compare_digest_to_routerstatus_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
|
/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
|
||||||
@ -803,7 +803,7 @@ routerstatus_t *
|
|||||||
networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest)
|
networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest)
|
||||||
{
|
{
|
||||||
return smartlist_bsearch(ns->routerstatus_list, digest,
|
return smartlist_bsearch(ns->routerstatus_list, digest,
|
||||||
_compare_digest_to_routerstatus_entry);
|
compare_digest_to_routerstatus_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*XXXX make this static once functions are moved into this file. */
|
/*XXXX make this static once functions are moved into this file. */
|
||||||
@ -815,7 +815,7 @@ networkstatus_vote_find_entry_idx(networkstatus_t *ns,
|
|||||||
const char *digest, int *found_out)
|
const char *digest, int *found_out)
|
||||||
{
|
{
|
||||||
return smartlist_bsearch_idx(ns->routerstatus_list, digest,
|
return smartlist_bsearch_idx(ns->routerstatus_list, digest,
|
||||||
_compare_digest_to_routerstatus_entry,
|
compare_digest_to_routerstatus_entry,
|
||||||
found_out);
|
found_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +868,7 @@ router_get_consensus_status_by_id(const char *digest)
|
|||||||
if (!current_consensus)
|
if (!current_consensus)
|
||||||
return NULL;
|
return NULL;
|
||||||
return smartlist_bsearch(current_consensus->routerstatus_list, digest,
|
return smartlist_bsearch(current_consensus->routerstatus_list, digest,
|
||||||
_compare_digest_to_routerstatus_entry);
|
compare_digest_to_routerstatus_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return
|
/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return
|
||||||
@ -1827,7 +1827,7 @@ char *
|
|||||||
networkstatus_getinfo_helper_single(routerstatus_t *rs)
|
networkstatus_getinfo_helper_single(routerstatus_t *rs)
|
||||||
{
|
{
|
||||||
char buf[RS_ENTRY_LEN+1];
|
char buf[RS_ENTRY_LEN+1];
|
||||||
routerstatus_format_entry(buf, sizeof(buf), rs, NULL, 0, 1);
|
routerstatus_format_entry(buf, sizeof(buf), rs, NULL, NS_CONTROL_PORT);
|
||||||
return tor_strdup(buf);
|
return tor_strdup(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
src/or/or.h
34
src/or/or.h
@ -1509,6 +1509,9 @@ typedef struct routerstatus_t {
|
|||||||
|
|
||||||
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
|
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
|
||||||
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
|
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
|
||||||
|
unsigned int has_measured_bw:1; /**< The vote/consensus had a measured bw */
|
||||||
|
|
||||||
|
uint32_t measured_bw; /**< Measured bandwidth (capacity) of the router */
|
||||||
|
|
||||||
uint32_t bandwidth; /**< Bandwidth (capacity) of the router as reported in
|
uint32_t bandwidth; /**< Bandwidth (capacity) of the router as reported in
|
||||||
* the vote/consensus, in kilobytes/sec. */
|
* the vote/consensus, in kilobytes/sec. */
|
||||||
@ -2546,6 +2549,9 @@ typedef struct {
|
|||||||
* migration purposes? */
|
* migration purposes? */
|
||||||
int V3AuthUseLegacyKey;
|
int V3AuthUseLegacyKey;
|
||||||
|
|
||||||
|
/** Location of bandwidth measurement file */
|
||||||
|
char *V3BandwidthsFile;
|
||||||
|
|
||||||
/** The length of time that we think an initial consensus should be fresh.
|
/** The length of time that we think an initial consensus should be fresh.
|
||||||
* Only altered on testing networks. */
|
* Only altered on testing networks. */
|
||||||
int TestingV3AuthInitialVotingInterval;
|
int TestingV3AuthInitialVotingInterval;
|
||||||
@ -3444,8 +3450,8 @@ download_status_mark_impossible(download_status_t *dl)
|
|||||||
* Running Stable Unnamed V2Dir Valid\n". */
|
* Running Stable Unnamed V2Dir Valid\n". */
|
||||||
#define MAX_FLAG_LINE_LEN 96
|
#define MAX_FLAG_LINE_LEN 96
|
||||||
/** Length of "w" line for weighting. Currently at most
|
/** Length of "w" line for weighting. Currently at most
|
||||||
* "w Bandwidth=<uint32t>\n" */
|
* "w Bandwidth=<uint32t> Measured=<uint32t>\n" */
|
||||||
#define MAX_WEIGHT_LINE_LEN (13+10)
|
#define MAX_WEIGHT_LINE_LEN (12+10+10+10+1)
|
||||||
/** Maximum length of an exit policy summary line. */
|
/** Maximum length of an exit policy summary line. */
|
||||||
#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN)
|
#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN)
|
||||||
/** Amount of space to allocate for each entry: r, s, and v lines. */
|
/** Amount of space to allocate for each entry: r, s, and v lines. */
|
||||||
@ -3528,13 +3534,32 @@ int dirserv_remove_old_statuses(smartlist_t *fps, time_t cutoff);
|
|||||||
int dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src);
|
int dirserv_have_any_serverdesc(smartlist_t *fps, int spool_src);
|
||||||
size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
|
size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
|
||||||
int compressed);
|
int compressed);
|
||||||
|
typedef enum {
|
||||||
|
NS_V2, NS_V3_CONSENSUS, NS_V3_VOTE, NS_CONTROL_PORT
|
||||||
|
} routerstatus_format_type_t;
|
||||||
int routerstatus_format_entry(char *buf, size_t buf_len,
|
int routerstatus_format_entry(char *buf, size_t buf_len,
|
||||||
routerstatus_t *rs, const char *platform,
|
routerstatus_t *rs, const char *platform,
|
||||||
int first_line_only, int v2_format);
|
routerstatus_format_type_t format);
|
||||||
void dirserv_free_all(void);
|
void dirserv_free_all(void);
|
||||||
void cached_dir_decref(cached_dir_t *d);
|
void cached_dir_decref(cached_dir_t *d);
|
||||||
cached_dir_t *new_cached_dir(char *s, time_t published);
|
cached_dir_t *new_cached_dir(char *s, time_t published);
|
||||||
|
|
||||||
|
#ifdef DIRSERV_PRIVATE
|
||||||
|
typedef struct measured_bw_line_t {
|
||||||
|
char node_id[DIGEST_LEN];
|
||||||
|
char node_hex[MAX_HEX_NICKNAME_LEN+1];
|
||||||
|
long int bw;
|
||||||
|
} measured_bw_line_t;
|
||||||
|
|
||||||
|
int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
|
||||||
|
|
||||||
|
int measured_bw_line_apply(measured_bw_line_t *parsed_line,
|
||||||
|
smartlist_t *routerstatuses);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int dirserv_read_measured_bandwidths(const char *from_file,
|
||||||
|
smartlist_t *routerstatuses);
|
||||||
|
|
||||||
/********************************* dirvote.c ************************/
|
/********************************* dirvote.c ************************/
|
||||||
|
|
||||||
/** Lowest allowable value for VoteSeconds. */
|
/** Lowest allowable value for VoteSeconds. */
|
||||||
@ -3848,6 +3873,8 @@ int router_set_networkstatus_v2(const char *s, time_t arrived_at,
|
|||||||
v2_networkstatus_source_t source,
|
v2_networkstatus_source_t source,
|
||||||
smartlist_t *requested_fingerprints);
|
smartlist_t *requested_fingerprints);
|
||||||
void networkstatus_v2_list_clean(time_t now);
|
void networkstatus_v2_list_clean(time_t now);
|
||||||
|
int compare_digest_to_routerstatus_entry(const void *_key,
|
||||||
|
const void **_member);
|
||||||
routerstatus_t *networkstatus_v2_find_entry(networkstatus_v2_t *ns,
|
routerstatus_t *networkstatus_v2_find_entry(networkstatus_v2_t *ns,
|
||||||
const char *digest);
|
const char *digest);
|
||||||
routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns,
|
routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns,
|
||||||
@ -4712,6 +4739,7 @@ void sort_version_list(smartlist_t *lst, int remove_duplicates);
|
|||||||
void assert_addr_policy_ok(smartlist_t *t);
|
void assert_addr_policy_ok(smartlist_t *t);
|
||||||
void dump_distinct_digest_count(int severity);
|
void dump_distinct_digest_count(int severity);
|
||||||
|
|
||||||
|
int compare_routerstatus_entries(const void **_a, const void **_b);
|
||||||
networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s);
|
networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s);
|
||||||
networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
|
networkstatus_t *networkstatus_parse_vote_from_string(const char *s,
|
||||||
const char **eos_out,
|
const char **eos_out,
|
||||||
|
@ -1924,6 +1924,16 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
rs->has_bandwidth = 1;
|
rs->has_bandwidth = 1;
|
||||||
|
} else if (!strcmpstart(tok->args[i], "Measured=")) {
|
||||||
|
int ok;
|
||||||
|
rs->measured_bw = tor_parse_ulong(strchr(tok->args[i], '=')+1, 10,
|
||||||
|
0, UINT32_MAX, &ok, NULL);
|
||||||
|
if (!ok) {
|
||||||
|
log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
|
||||||
|
escaped(tok->args[i]));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rs->has_measured_bw = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1966,8 +1976,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Helper to sort a smartlist of pointers to routerstatus_t */
|
/** Helper to sort a smartlist of pointers to routerstatus_t */
|
||||||
static int
|
int
|
||||||
_compare_routerstatus_entries(const void **_a, const void **_b)
|
compare_routerstatus_entries(const void **_a, const void **_b)
|
||||||
{
|
{
|
||||||
const routerstatus_t *a = *_a, *b = *_b;
|
const routerstatus_t *a = *_a, *b = *_b;
|
||||||
return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
|
return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
|
||||||
@ -2114,8 +2124,8 @@ networkstatus_v2_parse_from_string(const char *s)
|
|||||||
NULL, NULL, 0)))
|
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);
|
||||||
smartlist_uniq(ns->entries, _compare_routerstatus_entries,
|
smartlist_uniq(ns->entries, compare_routerstatus_entries,
|
||||||
_free_duplicate_routerstatus_entry);
|
_free_duplicate_routerstatus_entry);
|
||||||
|
|
||||||
if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
|
if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
|
||||||
|
112
src/or/test.c
112
src/or/test.c
@ -3232,6 +3232,72 @@ test_dirutil(void)
|
|||||||
smartlist_free(sl);
|
smartlist_free(sl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_dirutil_measured_bw(void)
|
||||||
|
{
|
||||||
|
measured_bw_line_t mbwl;
|
||||||
|
int i;
|
||||||
|
const char *lines_pass[] = {
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1024\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e\t bw=1024 \n",
|
||||||
|
" node_id=$557365204145532d32353620696e73746561642e bw=1024\n",
|
||||||
|
"\tnoise\tnode_id=$557365204145532d32353620696e73746561642e "
|
||||||
|
"bw=1024 junk=007\n",
|
||||||
|
"misc=junk node_id=$557365204145532d32353620696e73746561642e "
|
||||||
|
"bw=1024 junk=007\n",
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
const char *lines_fail[] = {
|
||||||
|
/* Test possible python stupidity on input */
|
||||||
|
"node_id=None bw=1024\n",
|
||||||
|
"node_id=$None bw=1024\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=None\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1024.0\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=.1024\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1.024\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1024 bw=0\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1024 bw=None\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=-1024\n",
|
||||||
|
/* Test incomplete writes due to race conditions, partial copies, etc */
|
||||||
|
"node_i",
|
||||||
|
"node_i\n",
|
||||||
|
"node_id=",
|
||||||
|
"node_id=\n",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=1024",
|
||||||
|
"node_id=$557365204145532d32353620696e73746561642e bw=\n",
|
||||||
|
"node_id=$557365204145532d32353620696e7374",
|
||||||
|
"node_id=$557365204145532d32353620696e7374\n",
|
||||||
|
"",
|
||||||
|
"\n",
|
||||||
|
" \n ",
|
||||||
|
" \n\n",
|
||||||
|
/* Test assorted noise */
|
||||||
|
" node_id= ",
|
||||||
|
"node_id==$557365204145532d32353620696e73746561642e bw==1024\n",
|
||||||
|
"node_id=$55736520414552d32353620696e73746561642e bw=1024\n",
|
||||||
|
"node_id=557365204145532d32353620696e73746561642e bw=1024\n",
|
||||||
|
"node_id= $557365204145532d32353620696e73746561642e bw=0.23\n",
|
||||||
|
"end"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; strcmp(lines_fail[i], "end"); i++) {
|
||||||
|
//fprintf(stderr, "Testing: %s\n", lines_fail[i]);
|
||||||
|
test_assert(measured_bw_line_parse(&mbwl, lines_fail[i]) == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; strcmp(lines_pass[i], "end"); i++) {
|
||||||
|
//fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n'));
|
||||||
|
test_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
|
||||||
|
test_assert(mbwl.bw == 1024);
|
||||||
|
test_assert(strcmp(mbwl.node_hex,
|
||||||
|
"557365204145532d32353620696e73746561642e") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
extern const char AUTHORITY_CERT_1[];
|
extern const char AUTHORITY_CERT_1[];
|
||||||
extern const char AUTHORITY_SIGNKEY_1[];
|
extern const char AUTHORITY_SIGNKEY_1[];
|
||||||
extern const char AUTHORITY_CERT_2[];
|
extern const char AUTHORITY_CERT_2[];
|
||||||
@ -3512,6 +3578,17 @@ test_v3_networkstatus(void)
|
|||||||
test_eq(rs->dir_port, 0);
|
test_eq(rs->dir_port, 0);
|
||||||
test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
|
test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
|
||||||
|
|
||||||
|
{
|
||||||
|
measured_bw_line_t mbw;
|
||||||
|
memset(mbw.node_id, 33, sizeof(mbw.node_id));
|
||||||
|
mbw.bw = 1024;
|
||||||
|
test_assert(measured_bw_line_apply(&mbw,
|
||||||
|
v1->routerstatus_list) == 1);
|
||||||
|
vrs = smartlist_get(v1->routerstatus_list, 2);
|
||||||
|
test_assert(vrs->status.has_measured_bw &&
|
||||||
|
vrs->status.measured_bw == 1024);
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate second vote. It disagrees on some of the times,
|
/* Generate second vote. It disagrees on some of the times,
|
||||||
* and doesn't list versions, and knows some crazy flags */
|
* and doesn't list versions, and knows some crazy flags */
|
||||||
vote->published = now+1;
|
vote->published = now+1;
|
||||||
@ -4284,6 +4361,39 @@ test_util_datadir(void)
|
|||||||
tor_free(f);
|
tor_free(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_strtok(void)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
char buf2[128];
|
||||||
|
char *cp1, *cp2;
|
||||||
|
strlcpy(buf, "Graved on the dark in gestures of descent", sizeof(buf));
|
||||||
|
strlcpy(buf2, "they.seemed;their!own;most.perfect;monument", sizeof(buf2));
|
||||||
|
/* -- "Year's End", Richard Wilbur */
|
||||||
|
|
||||||
|
test_streq("Graved", tor_strtok_r_impl(buf, " ", &cp1));
|
||||||
|
test_streq("they", tor_strtok_r_impl(buf2, ".!..;!", &cp2));
|
||||||
|
#define S1() tor_strtok_r_impl(NULL, " ", &cp1)
|
||||||
|
#define S2() tor_strtok_r_impl(NULL, ".!..;!", &cp2)
|
||||||
|
test_streq("on", S1());
|
||||||
|
test_streq("the", S1());
|
||||||
|
test_streq("dark", S1());
|
||||||
|
test_streq("seemed", S2());
|
||||||
|
test_streq("their", S2());
|
||||||
|
test_streq("own", S2());
|
||||||
|
test_streq("in", S1());
|
||||||
|
test_streq("gestures", S1());
|
||||||
|
test_streq("of", S1());
|
||||||
|
test_streq("most", S2());
|
||||||
|
test_streq("perfect", S2());
|
||||||
|
test_streq("descent", S1());
|
||||||
|
test_streq("monument", S2());
|
||||||
|
test_assert(NULL == S1());
|
||||||
|
test_assert(NULL == S2());
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/** Test AES-CTR encryption and decryption with IV. */
|
/** Test AES-CTR encryption and decryption with IV. */
|
||||||
static void
|
static void
|
||||||
test_crypto_aes_iv(void)
|
test_crypto_aes_iv(void)
|
||||||
@ -4692,9 +4802,11 @@ static struct {
|
|||||||
SUBENT(util, threads),
|
SUBENT(util, threads),
|
||||||
SUBENT(util, order_functions),
|
SUBENT(util, order_functions),
|
||||||
SUBENT(util, sscanf),
|
SUBENT(util, sscanf),
|
||||||
|
SUBENT(util, strtok),
|
||||||
ENT(onion_handshake),
|
ENT(onion_handshake),
|
||||||
ENT(dir_format),
|
ENT(dir_format),
|
||||||
ENT(dirutil),
|
ENT(dirutil),
|
||||||
|
SUBENT(dirutil, measured_bw),
|
||||||
ENT(v3_networkstatus),
|
ENT(v3_networkstatus),
|
||||||
ENT(policies),
|
ENT(policies),
|
||||||
ENT(rend_fns),
|
ENT(rend_fns),
|
||||||
|
Loading…
Reference in New Issue
Block a user