Merge branch 'maint-0.2.4' into release-0.2.4
This commit is contained in:
commit
2d4aebaf76
|
@ -0,0 +1,8 @@
|
|||
o Critical bugfixes:
|
||||
- Distinguish downloading an authority certificate by identity digest from
|
||||
downloading one by identity digest/signing key digest pair; formerly we
|
||||
always request them only by identity digest and get the newest one even
|
||||
when we wanted one with a different signing key. Then we would complain
|
||||
about being given a certificate we already had, and never get the one we
|
||||
really wanted. Now we use the "fp-sk/" resource as well as the "fp/"
|
||||
resource to request the one we want. Fixes bug 5595.
|
|
@ -0,0 +1,4 @@
|
|||
o Minor bugfixes:
|
||||
- Relays now treat a changed IPv6 ORPort as sufficient reason to
|
||||
publish an updated descriptor. Fix for bug 6026; bugfix for
|
||||
0.2.4.1-alpha.
|
|
@ -0,0 +1,3 @@
|
|||
o Minor bugfixes:
|
||||
- Copy-paste description for PathBias params from man page into or.h
|
||||
comment. Fixes bug 7982.
|
|
@ -0,0 +1,3 @@
|
|||
o Minor features:
|
||||
- Downgrade "unexpected SENDME" warnings to protocol-warn for 0.2.4,
|
||||
for bug 8093.
|
|
@ -0,0 +1,6 @@
|
|||
o Minor bugfixes (log messages)
|
||||
- Fix a scaling issue in the path bias accounting code that resulted in
|
||||
"Bug:" log messages from either pathbias_scale_close_rates() or
|
||||
pathbias_count_build_success(). This represents a bugfix on a previous
|
||||
bugfix: The original fix attempted in 0.2.4.10-alpha was incomplete.
|
||||
Fixes bug 8235; bugfix on 0.2.4.1-alpha.
|
|
@ -0,0 +1,6 @@
|
|||
o Minor features (authority):
|
||||
- Add a "ignoring-advertised-bws" boolean to our flag-thresholds
|
||||
lines to describe whether we have enough measured bandwidths to
|
||||
ignore advertised bandwidth claims. Closes ticket 8711.
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
o Minor bugfixes (memory leak):
|
||||
- Fix a memory leak that would occur whenever a configuration
|
||||
option changed. Fixes bug #8718; bugfix on 0.2.3.3-alpha.
|
|
@ -0,0 +1,6 @@
|
|||
o Major bugfixes (memory leak):
|
||||
- Avoid a memory leak where we would leak a consensus body when we find
|
||||
that a consensus which we couldn't previously verify due to missing
|
||||
certificates is now verifiable. Fixes bug 8719; bugfix on
|
||||
0.2.0.10-alpha.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
o Major bugfixes (directory authority):
|
||||
- Fix a crash bug when building a consensus using an older consensus as
|
||||
its basis. Fixes bug 8833. Bugfix on 0.2.4.12-alpha.
|
|
@ -0,0 +1,6 @@
|
|||
o Major bugfixes:
|
||||
- Prevent the get_freelists() function from running off the end of
|
||||
the list of freelists if it somehow gets an unrecognized
|
||||
allocation. Fixes bug 8844; bugfix on 0.2.0.16-alpha. Reported by
|
||||
eugenis.
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
o Minor bugfixes (test):
|
||||
- Fix an impossible buffer overrun in the AES unit tests. Fixes bug 8845;
|
||||
bugfix on 0.2.0.7-alpha. Found by eugenis.
|
|
@ -0,0 +1,4 @@
|
|||
o Minor bugfixes:
|
||||
- Give a less useless error message when the user asks for an IPv4
|
||||
address on an IPv6-only port, or vice versa. Fixes bug 8846; bugfix
|
||||
on 0.2.4.7-alpha.
|
|
@ -0,0 +1,5 @@
|
|||
o Major bugfixes:
|
||||
- Follow the socks5 protocol when offering username/password
|
||||
authentication. The fix for bug 8117 exposed this bug, and it
|
||||
turns out real-world applications like Pidgin do care. Bugfix on
|
||||
0.2.3.2-alpha; fixes bug 8879.
|
|
@ -0,0 +1,3 @@
|
|||
o Minor features:
|
||||
- Update to the May 9 2013 Maxmind GeoLite Country database.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
o Code simplification and refactoring:
|
||||
- Avoid using character buffers when constructing most directory
|
||||
objects: this approach was unweildy and error-prone. Instead,
|
||||
build smartlists of strings, and concatenate them when done.
|
||||
|
|
@ -1614,6 +1614,29 @@ crypto_digest_assign(crypto_digest_t *into,
|
|||
memcpy(into,from,sizeof(crypto_digest_t));
|
||||
}
|
||||
|
||||
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
|
||||
* at <b>digest_out</b> to the hash of the concatenation of those strings,
|
||||
* plus the optional string <b>append</b>, computed with the algorithm
|
||||
* <b>alg</b>.
|
||||
* <b>out_len</b> must be \<= DIGEST256_LEN. */
|
||||
void
|
||||
crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
const smartlist_t *lst, const char *append,
|
||||
digest_algorithm_t alg)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
if (alg == DIGEST_SHA1)
|
||||
d = crypto_digest_new();
|
||||
else
|
||||
d = crypto_digest256_new(alg);
|
||||
SMARTLIST_FOREACH(lst, const char *, cp,
|
||||
crypto_digest_add_bytes(d, cp, strlen(cp)));
|
||||
if (append)
|
||||
crypto_digest_add_bytes(d, append, strlen(append));
|
||||
crypto_digest_get_digest(d, digest_out, len_out);
|
||||
crypto_digest_free(d);
|
||||
}
|
||||
|
||||
/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
|
||||
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
|
||||
* in <b>hmac_out</b>.
|
||||
|
|
|
@ -205,6 +205,10 @@ int crypto_digest(char *digest, const char *m, size_t len);
|
|||
int crypto_digest256(char *digest, const char *m, size_t len,
|
||||
digest_algorithm_t algorithm);
|
||||
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
|
||||
struct smartlist_t;
|
||||
void crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
const struct smartlist_t *lst, const char *append,
|
||||
digest_algorithm_t alg);
|
||||
const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg);
|
||||
int crypto_digest_algorithm_parse_name(const char *name);
|
||||
crypto_digest_t *crypto_digest_new(void);
|
||||
|
|
20373
src/config/geoip
20373
src/config/geoip
File diff suppressed because it is too large
Load Diff
|
@ -35,6 +35,7 @@ LIBTOR_OBJECTS = \
|
|||
dirvote.obj \
|
||||
dns.obj \
|
||||
dnsserv.obj \
|
||||
fp_pair.obj \
|
||||
entrynodes.obj \
|
||||
geoip.obj \
|
||||
hibernate.obj \
|
||||
|
|
|
@ -148,7 +148,8 @@ static INLINE chunk_freelist_t *
|
|||
get_freelist(size_t alloc)
|
||||
{
|
||||
int i;
|
||||
for (i=0; freelists[i].alloc_size <= alloc; ++i) {
|
||||
for (i=0; (freelists[i].alloc_size <= alloc &&
|
||||
freelists[i].alloc_size); ++i ) {
|
||||
if (freelists[i].alloc_size == alloc) {
|
||||
return &freelists[i];
|
||||
}
|
||||
|
@ -1750,7 +1751,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
|
|||
return 0;
|
||||
}
|
||||
req->replylen = 2; /* 2 bytes of response */
|
||||
req->reply[0] = 5;
|
||||
req->reply[0] = 1; /* authversion == 1 */
|
||||
req->reply[1] = 0; /* authentication successful */
|
||||
log_debug(LD_APP,
|
||||
"socks5: Accepted username/password without checking.");
|
||||
|
|
|
@ -2491,7 +2491,7 @@ pathbias_scale_close_rates(entry_guard_t *guard)
|
|||
/* Verify that the counts are sane before and after scaling */
|
||||
int counts_are_sane = (guard->circ_attempts >= guard->circ_successes);
|
||||
|
||||
guard->circ_attempts -= opened_attempts;
|
||||
guard->circ_attempts -= (opened_attempts+opened_built);
|
||||
guard->circ_successes -= opened_built;
|
||||
|
||||
guard->circ_attempts *= scale_ratio;
|
||||
|
@ -2501,7 +2501,7 @@ pathbias_scale_close_rates(entry_guard_t *guard)
|
|||
guard->collapsed_circuits *= scale_ratio;
|
||||
guard->unusable_circuits *= scale_ratio;
|
||||
|
||||
guard->circ_attempts += opened_attempts;
|
||||
guard->circ_attempts += (opened_attempts+opened_built);
|
||||
guard->circ_successes += opened_built;
|
||||
|
||||
entry_guards_changed();
|
||||
|
|
|
@ -620,12 +620,13 @@ set_options(or_options_t *new_val, char **msg)
|
|||
tor_free(line);
|
||||
}
|
||||
} else {
|
||||
smartlist_add(elements, (char*)options_format.vars[i].name);
|
||||
smartlist_add(elements, tor_strdup(options_format.vars[i].name));
|
||||
smartlist_add(elements, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
control_event_conf_changed(elements);
|
||||
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
|
||||
smartlist_free(elements);
|
||||
}
|
||||
|
||||
|
@ -5576,7 +5577,8 @@ get_first_listener_addrport_string(int listener_type)
|
|||
to iterate all listener connections and find out in which
|
||||
port it ended up listening: */
|
||||
if (cfg->port == CFG_AUTO_PORT) {
|
||||
port = router_get_active_listener_port_by_type(listener_type);
|
||||
port = router_get_active_listener_port_by_type_af(listener_type,
|
||||
tor_addr_family(&cfg->addr));
|
||||
if (!port)
|
||||
return NULL;
|
||||
} else {
|
||||
|
|
|
@ -2073,6 +2073,8 @@ retry_all_listeners(smartlist_t *replaced_conns,
|
|||
const or_options_t *options = get_options();
|
||||
int retval = 0;
|
||||
const uint16_t old_or_port = router_get_advertised_or_port(options);
|
||||
const uint16_t old_or_port_ipv6 =
|
||||
router_get_advertised_or_port_by_af(options,AF_INET6);
|
||||
const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
|
||||
|
@ -2101,8 +2103,9 @@ retry_all_listeners(smartlist_t *replaced_conns,
|
|||
|
||||
smartlist_free(listeners);
|
||||
|
||||
/* XXXprop186 should take all advertised ports into account */
|
||||
if (old_or_port != router_get_advertised_or_port(options) ||
|
||||
old_or_port_ipv6 != router_get_advertised_or_port_by_af(options,
|
||||
AF_INET6) ||
|
||||
old_dir_port != router_get_advertised_dir_port(options, 0)) {
|
||||
/* Our chosen ORPort or DirPort is not what it used to be: the
|
||||
* descriptor we had (if any) should be regenerated. (We won't
|
||||
|
|
|
@ -1769,9 +1769,10 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
|
|||
}
|
||||
|
||||
if (flags == BEGIN_FLAG_IPV4_NOT_OK) {
|
||||
log_warn(LD_BUG, "Hey; I'm about to ask a node for a connection that I "
|
||||
log_warn(LD_EDGE, "I'm about to ask a node for a connection that I "
|
||||
"am telling it to fulfil with neither IPv4 nor IPv6. That's "
|
||||
"probably not going to work.");
|
||||
"not going to work. Did you perhaps ask for an IPv6 address "
|
||||
"on an IPv4Only port, or vice versa?");
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
|
|
@ -4393,7 +4393,7 @@ control_event_guard(const char *nickname, const char *digest,
|
|||
* a smartlist_t containing (key, value, ...) pairs in sequence.
|
||||
* <b>value</b> can be NULL. */
|
||||
int
|
||||
control_event_conf_changed(smartlist_t *elements)
|
||||
control_event_conf_changed(const smartlist_t *elements)
|
||||
{
|
||||
int i;
|
||||
char *result;
|
||||
|
|
|
@ -72,7 +72,7 @@ int control_event_server_status(int severity, const char *format, ...)
|
|||
CHECK_PRINTF(2,3);
|
||||
int control_event_guard(const char *nickname, const char *digest,
|
||||
const char *status);
|
||||
int control_event_conf_changed(smartlist_t *elements);
|
||||
int control_event_conf_changed(const smartlist_t *elements);
|
||||
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
|
||||
buildtimeout_set_event_t type);
|
||||
int control_event_signal(uintptr_t signal);
|
||||
|
|
|
@ -856,19 +856,43 @@ connection_dir_bridge_routerdesc_failed(dir_connection_t *conn)
|
|||
static void
|
||||
connection_dir_download_cert_failed(dir_connection_t *conn, int status)
|
||||
{
|
||||
const char *fp_pfx = "fp/";
|
||||
const char *fpsk_pfx = "fp-sk/";
|
||||
smartlist_t *failed;
|
||||
tor_assert(conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE);
|
||||
|
||||
if (!conn->requested_resource)
|
||||
return;
|
||||
failed = smartlist_new();
|
||||
dir_split_resource_into_fingerprints(conn->requested_resource+3,
|
||||
/*
|
||||
* We have two cases download by fingerprint (resource starts
|
||||
* with "fp/") or download by fingerprint/signing key pair
|
||||
* (resource starts with "fp-sk/").
|
||||
*/
|
||||
if (!strcmpstart(conn->requested_resource, fp_pfx)) {
|
||||
/* Download by fingerprint case */
|
||||
dir_split_resource_into_fingerprints(conn->requested_resource +
|
||||
strlen(fp_pfx),
|
||||
failed, NULL, DSR_HEX);
|
||||
SMARTLIST_FOREACH(failed, char *, cp,
|
||||
{
|
||||
authority_cert_dl_failed(cp, status);
|
||||
SMARTLIST_FOREACH_BEGIN(failed, char *, cp) {
|
||||
/* Null signing key digest indicates download by fp only */
|
||||
authority_cert_dl_failed(cp, NULL, status);
|
||||
tor_free(cp);
|
||||
});
|
||||
} SMARTLIST_FOREACH_END(cp);
|
||||
} else if (!strcmpstart(conn->requested_resource, fpsk_pfx)) {
|
||||
/* Download by (fp,sk) pairs */
|
||||
dir_split_resource_into_fingerprint_pairs(conn->requested_resource +
|
||||
strlen(fpsk_pfx), failed);
|
||||
SMARTLIST_FOREACH_BEGIN(failed, fp_pair_t *, cp) {
|
||||
authority_cert_dl_failed(cp->first, cp->second, status);
|
||||
tor_free(cp);
|
||||
} SMARTLIST_FOREACH_END(cp);
|
||||
} else {
|
||||
log_warn(LD_DIR,
|
||||
"Don't know what to do with failure for cert fetch %s",
|
||||
conn->requested_resource);
|
||||
}
|
||||
|
||||
smartlist_free(failed);
|
||||
|
||||
update_certificate_downloads(time(NULL));
|
||||
|
@ -1634,6 +1658,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|||
conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC);
|
||||
int was_compressed=0;
|
||||
time_t now = time(NULL);
|
||||
int src_code;
|
||||
|
||||
switch (connection_fetch_from_buf_http(TO_CONN(conn),
|
||||
&headers, MAX_HEADERS_SIZE,
|
||||
|
@ -1902,7 +1927,20 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|||
}
|
||||
log_info(LD_DIR,"Received authority certificates (size %d) from server "
|
||||
"'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
|
||||
if (trusted_dirs_load_certs_from_string(body, 0, 1)<0) {
|
||||
|
||||
/*
|
||||
* Tell trusted_dirs_load_certs_from_string() whether it was by fp
|
||||
* or fp-sk pair.
|
||||
*/
|
||||
src_code = -1;
|
||||
if (!strcmpstart(conn->requested_resource, "fp/")) {
|
||||
src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST;
|
||||
} else if (!strcmpstart(conn->requested_resource, "fp-sk/")) {
|
||||
src_code = TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST;
|
||||
}
|
||||
|
||||
if (src_code != -1) {
|
||||
if (trusted_dirs_load_certs_from_string(body, src_code, 1)<0) {
|
||||
log_warn(LD_DIR, "Unable to parse fetched certificates");
|
||||
/* if we fetched more than one and only some failed, the successful
|
||||
* ones got flushed to disk so it's safe to call this on them */
|
||||
|
@ -1911,6 +1949,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
|
|||
directory_info_has_arrived(now, 0);
|
||||
log_info(LD_DIR, "Successfully loaded certificates from fetch.");
|
||||
}
|
||||
} else {
|
||||
log_warn(LD_DIR,
|
||||
"Couldn't figure out what to do with fetched certificates for "
|
||||
"unknown resource %s",
|
||||
conn->requested_resource);
|
||||
connection_dir_download_cert_failed(conn, status_code);
|
||||
}
|
||||
}
|
||||
if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
|
||||
const char *msg;
|
||||
|
|
162
src/or/dirserv.c
162
src/or/dirserv.c
|
@ -1889,7 +1889,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
|
|||
{
|
||||
/* Have measured bw? */
|
||||
int have_mbw =
|
||||
dirserv_has_measured_bw(node->ri->cache_info.identity_digest);
|
||||
dirserv_has_measured_bw(node->identity);
|
||||
uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB;
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
|
@ -1898,7 +1898,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
|
|||
}
|
||||
|
||||
return node->ri && router_is_active(node->ri, node, now) &&
|
||||
!digestmap_get(omit_as_sybil, node->ri->cache_info.identity_digest) &&
|
||||
!digestmap_get(omit_as_sybil, node->identity) &&
|
||||
(dirserv_get_credible_bandwidth_kb(node->ri) >= min_bw_kb) &&
|
||||
(have_mbw || !require_mbw);
|
||||
}
|
||||
|
@ -1959,7 +1959,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
|||
if (router_counts_toward_thresholds(node, now, omit_as_sybil,
|
||||
require_mbw)) {
|
||||
routerinfo_t *ri = node->ri;
|
||||
const char *id = ri->cache_info.identity_digest;
|
||||
const char *id = node->identity;
|
||||
uint32_t bw_kb;
|
||||
node->is_exit = (!router_exit_policy_rejects_all(ri) &&
|
||||
exit_policy_is_general_exit(ri->exit_policy));
|
||||
|
@ -2273,12 +2273,16 @@ char *
|
|||
dirserv_get_flag_thresholds_line(void)
|
||||
{
|
||||
char *result=NULL;
|
||||
const int measured_threshold =
|
||||
get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
|
||||
const int enough_measured_bw = routers_with_measured_bw > measured_threshold;
|
||||
|
||||
tor_asprintf(&result,
|
||||
"stable-uptime=%lu stable-mtbf=%lu "
|
||||
"fast-speed=%lu "
|
||||
"guard-wfu=%.03f%% guard-tk=%lu "
|
||||
"guard-bw-inc-exits=%lu guard-bw-exc-exits=%lu "
|
||||
"enough-mtbf=%d",
|
||||
"enough-mtbf=%d ignoring-advertised-bws=%d",
|
||||
(unsigned long)stable_uptime,
|
||||
(unsigned long)stable_mtbf,
|
||||
(unsigned long)fast_bandwidth_kb*1000,
|
||||
|
@ -2286,7 +2290,8 @@ dirserv_get_flag_thresholds_line(void)
|
|||
(unsigned long)guard_tk,
|
||||
(unsigned long)guard_bandwidth_including_exits_kb*1000,
|
||||
(unsigned long)guard_bandwidth_excluding_exits_kb*1000,
|
||||
enough_mtbf_info ? 1 : 0);
|
||||
enough_mtbf_info ? 1 : 0,
|
||||
enough_measured_bw ? 1 : 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -2311,11 +2316,10 @@ version_from_platform(const char *platform)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>,
|
||||
* 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
|
||||
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
|
||||
* failure.
|
||||
/** Helper: write the router-status information in <b>rs</b> into a newly
|
||||
* allocated character buffer. 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 failure.
|
||||
*
|
||||
* The format argument has one of the following values:
|
||||
* NS_V2 - Output an entry suitable for a V2 NS opinion document
|
||||
|
@ -2326,25 +2330,25 @@ version_from_platform(const char *platform)
|
|||
* it contains additional information for the vote.
|
||||
* NS_CONTROL_PORT - Output a NS document for the control port
|
||||
*/
|
||||
int
|
||||
routerstatus_format_entry(char *buf, size_t buf_len,
|
||||
const routerstatus_t *rs, const char *version,
|
||||
char *
|
||||
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
|
||||
routerstatus_format_type_t format,
|
||||
const vote_routerstatus_t *vrs)
|
||||
{
|
||||
int r;
|
||||
char *cp;
|
||||
char *summary;
|
||||
char *result = NULL;
|
||||
|
||||
char published[ISO_TIME_LEN+1];
|
||||
char identity64[BASE64_DIGEST_LEN+1];
|
||||
char digest64[BASE64_DIGEST_LEN+1];
|
||||
smartlist_t *chunks = NULL;
|
||||
|
||||
format_iso_time(published, rs->published_on);
|
||||
digest_to_base64(identity64, rs->identity_digest);
|
||||
digest_to_base64(digest64, rs->descriptor_digest);
|
||||
|
||||
r = tor_snprintf(buf, buf_len,
|
||||
chunks = smartlist_new();
|
||||
smartlist_add_asprintf(chunks,
|
||||
"r %s %s %s%s%s %s %d %d\n",
|
||||
rs->nickname,
|
||||
identity64,
|
||||
|
@ -2354,11 +2358,6 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||
fmt_addr32(rs->addr),
|
||||
(int)rs->or_port,
|
||||
(int)rs->dir_port);
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||
return -1;
|
||||
}
|
||||
cp = buf + strlen(buf);
|
||||
|
||||
/* 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
|
||||
|
@ -2367,25 +2366,18 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||
|
||||
/* V3 microdesc consensuses don't have "a" lines. */
|
||||
if (format == NS_V3_CONSENSUS_MICRODESC)
|
||||
return 0;
|
||||
goto done;
|
||||
|
||||
/* Possible "a" line. At most one for now. */
|
||||
if (!tor_addr_is_null(&rs->ipv6_addr)) {
|
||||
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||
"a %s\n",
|
||||
smartlist_add_asprintf(chunks, "a %s\n",
|
||||
fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||
return -1;
|
||||
}
|
||||
cp += strlen(cp);
|
||||
}
|
||||
|
||||
if (format == NS_V3_CONSENSUS)
|
||||
return 0;
|
||||
goto done;
|
||||
|
||||
/* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
|
||||
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||
smartlist_add_asprintf(chunks,
|
||||
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
/* These must stay in alphabetical order. */
|
||||
rs->is_authority?" Authority":"",
|
||||
|
@ -2401,20 +2393,11 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||
rs->is_unnamed?" Unnamed":"",
|
||||
rs->is_v2_dir?" V2Dir":"",
|
||||
rs->is_valid?" Valid":"");
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||
return -1;
|
||||
}
|
||||
cp += strlen(cp);
|
||||
|
||||
/* length of "opt v \n" */
|
||||
#define V_LINE_OVERHEAD 7
|
||||
if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
|
||||
if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) {
|
||||
log_warn(LD_BUG, "Unable to print router version.");
|
||||
return -1;
|
||||
}
|
||||
cp += strlen(cp);
|
||||
smartlist_add_asprintf(chunks, "v %s\n", version);
|
||||
}
|
||||
|
||||
if (format != NS_V2) {
|
||||
|
@ -2434,7 +2417,7 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||
log_warn(LD_BUG, "Cannot get any descriptor for %s "
|
||||
"(wanted descriptor %s).",
|
||||
id, dd);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* This assert could fire for the control port, because
|
||||
|
@ -2469,39 +2452,32 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
|||
tor_assert(desc);
|
||||
bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
|
||||
}
|
||||
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||
"w Bandwidth=%d\n", bw_kb);
|
||||
smartlist_add_asprintf(chunks,
|
||||
"w Bandwidth=%d", bw_kb);
|
||||
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer.");
|
||||
return -1;
|
||||
}
|
||||
cp += strlen(cp);
|
||||
if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
|
||||
*--cp = '\0'; /* Kill "\n" */
|
||||
r = tor_snprintf(cp, buf_len - (cp-buf),
|
||||
" Measured=%d\n", vrs->measured_bw_kb);
|
||||
if (r<0) {
|
||||
log_warn(LD_BUG, "Not enough space in buffer for weight line.");
|
||||
return -1;
|
||||
}
|
||||
cp += strlen(cp);
|
||||
smartlist_add_asprintf(chunks,
|
||||
" Measured=%d", vrs->measured_bw_kb);
|
||||
}
|
||||
smartlist_add(chunks, tor_strdup("\n"));
|
||||
|
||||
if (desc) {
|
||||
summary = policy_summarize(desc->exit_policy, AF_INET);
|
||||
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);
|
||||
smartlist_add_asprintf(chunks, "p %s\n", summary);
|
||||
tor_free(summary);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
result = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
|
||||
err:
|
||||
if (chunks) {
|
||||
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
|
||||
smartlist_free(chunks);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Helper for sorting: compares two routerinfos first by address, and then by
|
||||
|
@ -3191,14 +3167,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
|||
/** For v2 authoritative directories only: Replace the contents of
|
||||
* <b>the_v2_networkstatus</b> with a newly generated network status
|
||||
* object. */
|
||||
static cached_dir_t *
|
||||
cached_dir_t *
|
||||
generate_v2_networkstatus_opinion(void)
|
||||
{
|
||||
cached_dir_t *r = NULL;
|
||||
size_t len, identity_pkey_len;
|
||||
size_t identity_pkey_len;
|
||||
char *status = NULL, *client_versions = NULL, *server_versions = NULL,
|
||||
*identity_pkey = NULL, *hostname = NULL;
|
||||
char *outp, *endp;
|
||||
const or_options_t *options = get_options();
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char published[ISO_TIME_LEN+1];
|
||||
|
@ -3217,6 +3192,7 @@ generate_v2_networkstatus_opinion(void)
|
|||
char *version_lines = NULL;
|
||||
smartlist_t *routers = NULL;
|
||||
digestmap_t *omit_as_sybil = NULL;
|
||||
smartlist_t *chunks = NULL;
|
||||
|
||||
private_key = get_server_identity_key();
|
||||
|
||||
|
@ -3255,12 +3231,8 @@ generate_v2_networkstatus_opinion(void)
|
|||
version_lines = tor_strdup("");
|
||||
}
|
||||
|
||||
len = 4096+strlen(client_versions)+strlen(server_versions);
|
||||
len += identity_pkey_len*2;
|
||||
len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
|
||||
|
||||
status = tor_malloc(len);
|
||||
tor_snprintf(status, len,
|
||||
chunks = smartlist_new();
|
||||
smartlist_add_asprintf(chunks,
|
||||
"network-status-version 2\n"
|
||||
"dir-source %s %s %d\n"
|
||||
"fingerprint %s\n"
|
||||
|
@ -3280,8 +3252,6 @@ generate_v2_networkstatus_opinion(void)
|
|||
versioning ? " Versions" : "",
|
||||
version_lines,
|
||||
identity_pkey);
|
||||
outp = status + strlen(status);
|
||||
endp = status + len;
|
||||
|
||||
/* precompute this part, since we need it to decide what "stable"
|
||||
* means. */
|
||||
|
@ -3312,34 +3282,32 @@ generate_v2_networkstatus_opinion(void)
|
|||
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
||||
clear_status_flags_on_sybil(&rs);
|
||||
|
||||
if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2,
|
||||
NULL)) {
|
||||
log_warn(LD_BUG, "Unable to print router status.");
|
||||
tor_free(version);
|
||||
goto done;
|
||||
{
|
||||
char *rsf = routerstatus_format_entry(&rs, version, NS_V2, NULL);
|
||||
if (rsf)
|
||||
smartlist_add(chunks, rsf);
|
||||
}
|
||||
tor_free(version);
|
||||
outp += strlen(outp);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
|
||||
options->Nickname)<0) {
|
||||
log_warn(LD_BUG, "Unable to write signature line.");
|
||||
goto done;
|
||||
}
|
||||
if (router_get_networkstatus_v2_hash(status, digest)<0) {
|
||||
log_warn(LD_BUG, "Unable to hash network status");
|
||||
goto done;
|
||||
}
|
||||
outp += strlen(outp);
|
||||
smartlist_add_asprintf(chunks, "directory-signature %s\n",
|
||||
options->Nickname);
|
||||
|
||||
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
|
||||
|
||||
note_crypto_pk_op(SIGN_DIR);
|
||||
if (router_append_dirobj_signature(outp,endp-outp,digest,DIGEST_LEN,
|
||||
private_key)<0) {
|
||||
{
|
||||
char *sig;
|
||||
if (!(sig = router_get_dirobj_signature(digest,DIGEST_LEN,
|
||||
private_key))) {
|
||||
log_warn(LD_BUG, "Unable to sign router status.");
|
||||
goto done;
|
||||
}
|
||||
smartlist_add(chunks, sig);
|
||||
}
|
||||
|
||||
status = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
|
||||
{
|
||||
networkstatus_v2_t *ns;
|
||||
|
@ -3362,6 +3330,10 @@ generate_v2_networkstatus_opinion(void)
|
|||
}
|
||||
|
||||
done:
|
||||
if (chunks) {
|
||||
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
|
||||
smartlist_free(chunks);
|
||||
}
|
||||
tor_free(client_versions);
|
||||
tor_free(server_versions);
|
||||
tor_free(version_lines);
|
||||
|
|
|
@ -29,28 +29,6 @@
|
|||
|
||||
/** Maximum allowable length of a version line in a networkstatus. */
|
||||
#define MAX_V_LINE_LEN 128
|
||||
/** Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named
|
||||
* Running Stable Unnamed V2Dir Valid\n". */
|
||||
#define MAX_FLAG_LINE_LEN 96
|
||||
/** Length of "w" line for weighting. Currently at most
|
||||
* "w Bandwidth=<uint32t> Measured=<uint32t>\n" */
|
||||
#define MAX_WEIGHT_LINE_LEN (12+10+10+10+1)
|
||||
/** Maximum length of an exit policy summary line. */
|
||||
#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN)
|
||||
/** Amount of space to allocate for each entry: r, s, and v lines. */
|
||||
#define RS_ENTRY_LEN \
|
||||
( /* first line */ \
|
||||
MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
|
||||
5*2 /* ports */ + 10 /* punctuation */ + \
|
||||
/* second line */ \
|
||||
MAX_FLAG_LINE_LEN + \
|
||||
/* weight line */ \
|
||||
MAX_WEIGHT_LINE_LEN + \
|
||||
/* p line. */ \
|
||||
MAX_POLICY_LINE_LEN + \
|
||||
/* v line. */ \
|
||||
MAX_V_LINE_LEN \
|
||||
)
|
||||
|
||||
int connection_dirserv_flushed_some(dir_connection_t *conn);
|
||||
|
||||
|
@ -128,7 +106,7 @@ size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs,
|
|||
int compressed);
|
||||
size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed);
|
||||
|
||||
int routerstatus_format_entry(char *buf, size_t buf_len,
|
||||
char *routerstatus_format_entry(
|
||||
const routerstatus_t *rs, const char *platform,
|
||||
routerstatus_format_type_t format,
|
||||
const vote_routerstatus_t *vrs);
|
||||
|
@ -154,6 +132,7 @@ int dirserv_get_measured_bw_cache_size(void);
|
|||
int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out,
|
||||
time_t *as_of_out);
|
||||
int dirserv_has_measured_bw(const char *node_id);
|
||||
cached_dir_t *generate_v2_networkstatus_opinion(void);
|
||||
#endif
|
||||
|
||||
int dirserv_read_measured_bandwidths(const char *from_file,
|
||||
|
|
192
src/or/dirvote.c
192
src/or/dirvote.c
|
@ -57,9 +57,6 @@ static char *make_consensus_method_list(int low, int high, const char *sep);
|
|||
* Voting
|
||||
* =====*/
|
||||
|
||||
/* Overestimated. */
|
||||
#define MICRODESC_LINE_LEN 80
|
||||
|
||||
/** Return a new string containing the string representation of the vote in
|
||||
* <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
|
||||
* For v3 authorities. */
|
||||
|
@ -67,17 +64,14 @@ char *
|
|||
format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
||||
networkstatus_t *v3_ns)
|
||||
{
|
||||
size_t len;
|
||||
char *status = NULL;
|
||||
smartlist_t *chunks;
|
||||
const char *client_versions = NULL, *server_versions = NULL;
|
||||
char *outp, *endp;
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char digest[DIGEST_LEN];
|
||||
uint32_t addr;
|
||||
routerlist_t *rl = router_get_routerlist();
|
||||
char *version_lines = NULL;
|
||||
int r;
|
||||
char *client_versions_line = NULL, *server_versions_line = NULL;
|
||||
networkstatus_voter_info_t *voter;
|
||||
char *status = NULL;
|
||||
|
||||
tor_assert(private_signing_key);
|
||||
tor_assert(v3_ns->type == NS_TYPE_VOTE || v3_ns->type == NS_TYPE_OPINION);
|
||||
|
@ -91,43 +85,20 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
client_versions = v3_ns->client_versions;
|
||||
server_versions = v3_ns->server_versions;
|
||||
|
||||
if (client_versions || server_versions) {
|
||||
size_t v_len = 64;
|
||||
char *cp;
|
||||
if (client_versions)
|
||||
v_len += strlen(client_versions);
|
||||
if (server_versions)
|
||||
v_len += strlen(server_versions);
|
||||
version_lines = tor_malloc(v_len);
|
||||
cp = version_lines;
|
||||
if (client_versions) {
|
||||
r = tor_snprintf(cp, v_len-(cp-version_lines),
|
||||
"client-versions %s\n", client_versions);
|
||||
if (r < 0) {
|
||||
log_err(LD_BUG, "Insufficient memory for client-versions line");
|
||||
tor_assert(0);
|
||||
}
|
||||
cp += strlen(cp);
|
||||
tor_asprintf(&client_versions_line, "client-versions %s\n",
|
||||
client_versions);
|
||||
} else {
|
||||
client_versions_line = tor_strdup("");
|
||||
}
|
||||
if (server_versions) {
|
||||
r = tor_snprintf(cp, v_len-(cp-version_lines),
|
||||
"server-versions %s\n", server_versions);
|
||||
if (r < 0) {
|
||||
log_err(LD_BUG, "Insufficient memory for server-versions line");
|
||||
tor_assert(0);
|
||||
}
|
||||
}
|
||||
tor_asprintf(&server_versions_line, "server-versions %s\n",
|
||||
server_versions);
|
||||
} else {
|
||||
version_lines = tor_strdup("");
|
||||
server_versions_line = tor_strdup("");
|
||||
}
|
||||
|
||||
len = 8192;
|
||||
len += strlen(version_lines);
|
||||
len += (RS_ENTRY_LEN+MICRODESC_LINE_LEN)*smartlist_len(rl->routers);
|
||||
len += strlen("\ndirectory-footer\n");
|
||||
len += v3_ns->cert->cache_info.signed_descriptor_len;
|
||||
|
||||
status = tor_malloc(len);
|
||||
chunks = smartlist_new();
|
||||
{
|
||||
char published[ISO_TIME_LEN+1];
|
||||
char va[ISO_TIME_LEN+1];
|
||||
|
@ -151,7 +122,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
params = tor_strdup("");
|
||||
|
||||
tor_assert(cert);
|
||||
r = tor_snprintf(status, len,
|
||||
smartlist_add_asprintf(chunks,
|
||||
"network-status-version 3\n"
|
||||
"vote-status %s\n"
|
||||
"consensus-methods %s\n"
|
||||
|
@ -160,7 +131,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
"fresh-until %s\n"
|
||||
"valid-until %s\n"
|
||||
"voting-delay %d %d\n"
|
||||
"%s" /* versions */
|
||||
"%s%s" /* versions */
|
||||
"known-flags %s\n"
|
||||
"flag-thresholds %s\n"
|
||||
"params %s\n"
|
||||
|
@ -170,7 +141,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
methods,
|
||||
published, va, fu, vu,
|
||||
v3_ns->vote_seconds, v3_ns->dist_seconds,
|
||||
version_lines,
|
||||
client_versions_line,
|
||||
server_versions_line,
|
||||
flags,
|
||||
flag_thresholds,
|
||||
params,
|
||||
|
@ -178,92 +150,66 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
fmt_addr32(addr), voter->dir_port, voter->or_port,
|
||||
voter->contact);
|
||||
|
||||
if (r < 0) {
|
||||
log_err(LD_BUG, "Insufficient memory for network status line");
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
tor_free(params);
|
||||
tor_free(flags);
|
||||
tor_free(flag_thresholds);
|
||||
tor_free(methods);
|
||||
outp = status + strlen(status);
|
||||
endp = status + len;
|
||||
|
||||
if (!tor_digest_is_zero(voter->legacy_id_digest)) {
|
||||
char fpbuf[HEX_DIGEST_LEN+1];
|
||||
base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
|
||||
r = tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf);
|
||||
if (r < 0) {
|
||||
log_err(LD_BUG, "Insufficient memory for legacy-dir-key line");
|
||||
tor_assert(0);
|
||||
}
|
||||
outp += strlen(outp);
|
||||
smartlist_add_asprintf(chunks, "legacy-dir-key %s\n", fpbuf);
|
||||
}
|
||||
|
||||
tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
|
||||
memcpy(outp, cert->cache_info.signed_descriptor_body,
|
||||
cert->cache_info.signed_descriptor_len);
|
||||
|
||||
outp += cert->cache_info.signed_descriptor_len;
|
||||
smartlist_add(chunks, tor_strndup(cert->cache_info.signed_descriptor_body,
|
||||
cert->cache_info.signed_descriptor_len));
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(v3_ns->routerstatus_list, vote_routerstatus_t *,
|
||||
vrs) {
|
||||
char *rsf;
|
||||
vote_microdesc_hash_t *h;
|
||||
if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
|
||||
vrs->version, NS_V3_VOTE, vrs) < 0) {
|
||||
log_warn(LD_BUG, "Unable to print router status.");
|
||||
goto err;
|
||||
}
|
||||
outp += strlen(outp);
|
||||
rsf = routerstatus_format_entry(&vrs->status,
|
||||
vrs->version, NS_V3_VOTE, vrs);
|
||||
if (rsf)
|
||||
smartlist_add(chunks, rsf);
|
||||
|
||||
for (h = vrs->microdesc; h; h = h->next) {
|
||||
size_t mlen = strlen(h->microdesc_hash_line);
|
||||
if (outp+mlen >= endp) {
|
||||
log_warn(LD_BUG, "Can't fit microdesc line in vote.");
|
||||
}
|
||||
memcpy(outp, h->microdesc_hash_line, mlen+1);
|
||||
outp += strlen(outp);
|
||||
smartlist_add(chunks, tor_strdup(h->microdesc_hash_line));
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(vrs);
|
||||
|
||||
r = tor_snprintf(outp, endp-outp, "directory-footer\n");
|
||||
if (r < 0) {
|
||||
log_err(LD_BUG, "Insufficient memory for directory-footer line");
|
||||
tor_assert(0);
|
||||
}
|
||||
outp += strlen(outp);
|
||||
smartlist_add(chunks, tor_strdup("directory-footer\n"));
|
||||
|
||||
/* The digest includes everything up through the space after
|
||||
* directory-signature. (Yuck.) */
|
||||
crypto_digest_smartlist(digest, DIGEST_LEN, chunks,
|
||||
"directory-signature ", DIGEST_SHA1);
|
||||
|
||||
{
|
||||
char signing_key_fingerprint[FINGERPRINT_LEN+1];
|
||||
if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
|
||||
log_warn(LD_BUG, "Unable to start signature line.");
|
||||
goto err;
|
||||
}
|
||||
outp += strlen(outp);
|
||||
|
||||
if (crypto_pk_get_fingerprint(private_signing_key,
|
||||
signing_key_fingerprint, 0)<0) {
|
||||
log_warn(LD_BUG, "Unable to get fingerprint for signing key");
|
||||
goto err;
|
||||
}
|
||||
if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
|
||||
signing_key_fingerprint)<0) {
|
||||
log_warn(LD_BUG, "Unable to end signature line.");
|
||||
goto err;
|
||||
}
|
||||
outp += strlen(outp);
|
||||
|
||||
smartlist_add_asprintf(chunks, "directory-signature %s %s\n", fingerprint,
|
||||
signing_key_fingerprint);
|
||||
}
|
||||
|
||||
if (router_get_networkstatus_v3_hash(status, digest, DIGEST_SHA1)<0)
|
||||
goto err;
|
||||
note_crypto_pk_op(SIGN_DIR);
|
||||
if (router_append_dirobj_signature(outp,endp-outp,digest, DIGEST_LEN,
|
||||
private_signing_key)<0) {
|
||||
{
|
||||
char *sig = router_get_dirobj_signature(digest, DIGEST_LEN,
|
||||
private_signing_key);
|
||||
if (!sig) {
|
||||
log_warn(LD_BUG, "Unable to sign networkstatus vote.");
|
||||
goto err;
|
||||
}
|
||||
smartlist_add(chunks, sig);
|
||||
}
|
||||
|
||||
status = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
|
||||
{
|
||||
networkstatus_t *v;
|
||||
|
@ -282,7 +228,12 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
|
|||
err:
|
||||
tor_free(status);
|
||||
done:
|
||||
tor_free(version_lines);
|
||||
tor_free(client_versions_line);
|
||||
tor_free(server_versions_line);
|
||||
if (chunks) {
|
||||
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
|
||||
smartlist_free(chunks);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -526,24 +477,6 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
|
|||
return most;
|
||||
}
|
||||
|
||||
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
|
||||
* at <b>digest_out</b> to the hash of the concatenation of those strings,
|
||||
* computed with the algorithm <b>alg</b>. */
|
||||
static void
|
||||
hash_list_members(char *digest_out, size_t len_out,
|
||||
smartlist_t *lst, digest_algorithm_t alg)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
if (alg == DIGEST_SHA1)
|
||||
d = crypto_digest_new();
|
||||
else
|
||||
d = crypto_digest256_new(alg);
|
||||
SMARTLIST_FOREACH(lst, const char *, cp,
|
||||
crypto_digest_add_bytes(d, cp, strlen(cp)));
|
||||
crypto_digest_get_digest(d, digest_out, len_out);
|
||||
crypto_digest_free(d);
|
||||
}
|
||||
|
||||
/** Sorting helper: compare two strings based on their values as base-ten
|
||||
* positive integers. (Non-integers are treated as prior to all integers, and
|
||||
* compared lexically.) */
|
||||
|
@ -2027,12 +1960,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||
}
|
||||
|
||||
{
|
||||
char buf[4096];
|
||||
char *buf;
|
||||
/* Okay!! Now we can write the descriptor... */
|
||||
/* First line goes into "buf". */
|
||||
routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL,
|
||||
rs_format, NULL);
|
||||
smartlist_add(chunks, tor_strdup(buf));
|
||||
buf = routerstatus_format_entry(&rs_out, NULL, rs_format, NULL);
|
||||
if (buf)
|
||||
smartlist_add(chunks, buf);
|
||||
}
|
||||
/* Now an m line, if applicable. */
|
||||
if (flavor == FLAV_MICRODESC &&
|
||||
|
@ -2144,12 +2077,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||
size_t digest_len =
|
||||
flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN;
|
||||
const char *algname = crypto_digest_algorithm_get_name(digest_alg);
|
||||
char sigbuf[4096];
|
||||
char *signature;
|
||||
|
||||
smartlist_add(chunks, tor_strdup("directory-signature "));
|
||||
|
||||
/* Compute the hash of the chunks. */
|
||||
hash_list_members(digest, digest_len, chunks, digest_alg);
|
||||
crypto_digest_smartlist(digest, digest_len, chunks, "", digest_alg);
|
||||
|
||||
/* Get the fingerprints */
|
||||
crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
|
||||
|
@ -2165,14 +2098,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||
signing_key_fingerprint);
|
||||
}
|
||||
/* And the signature. */
|
||||
sigbuf[0] = '\0';
|
||||
if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf),
|
||||
digest, digest_len,
|
||||
signing_key)) {
|
||||
if (!(signature = router_get_dirobj_signature(digest, digest_len,
|
||||
signing_key))) {
|
||||
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
|
||||
goto done;
|
||||
}
|
||||
smartlist_add(chunks, tor_strdup(sigbuf));
|
||||
smartlist_add(chunks, signature);
|
||||
|
||||
if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) {
|
||||
smartlist_add(chunks, tor_strdup("directory-signature "));
|
||||
|
@ -2188,14 +2119,13 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|||
algname, fingerprint,
|
||||
signing_key_fingerprint);
|
||||
}
|
||||
sigbuf[0] = '\0';
|
||||
if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf),
|
||||
digest, digest_len,
|
||||
legacy_signing_key)) {
|
||||
|
||||
if (!(signature = router_get_dirobj_signature(digest, digest_len,
|
||||
legacy_signing_key))) {
|
||||
log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
|
||||
goto done;
|
||||
}
|
||||
smartlist_add(chunks, tor_strdup(sigbuf));
|
||||
smartlist_add(chunks, signature);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3033,7 +2963,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
|
|||
/* Hey, it's a new cert! */
|
||||
trusted_dirs_load_certs_from_string(
|
||||
vote->cert->cache_info.signed_descriptor_body,
|
||||
0 /* from_store */, 1 /*flush*/);
|
||||
TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/);
|
||||
if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
|
||||
vote->cert->signing_key_digest)) {
|
||||
log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
|
||||
|
|
|
@ -1215,7 +1215,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
|||
int severity = LOG_INFO;
|
||||
/* If this state file was written by a Tor that would have
|
||||
* already fixed it, then the overcounting bug is still there.. */
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) {
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) {
|
||||
severity = LOG_NOTICE;
|
||||
}
|
||||
log_fn(severity, LD_BUG,
|
||||
|
@ -1280,7 +1280,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
|||
int severity = LOG_INFO;
|
||||
/* If this state file was written by a Tor that would have
|
||||
* already fixed it, then the overcounting bug is still there.. */
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) {
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.13-alpha")) {
|
||||
severity = LOG_NOTICE;
|
||||
}
|
||||
log_fn(severity, LD_BUG,
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "or.h"
|
||||
#include "fp_pair.h"
|
||||
|
||||
/* Define fp_pair_map_t structures */
|
||||
|
||||
struct fp_pair_map_entry_s {
|
||||
HT_ENTRY(fp_pair_map_entry_s) node;
|
||||
void *val;
|
||||
fp_pair_t key;
|
||||
};
|
||||
|
||||
struct fp_pair_map_s {
|
||||
HT_HEAD(fp_pair_map_impl, fp_pair_map_entry_s) head;
|
||||
};
|
||||
|
||||
/*
|
||||
* Hash function and equality checker for fp_pair_map_t
|
||||
*/
|
||||
|
||||
/** Compare fp_pair_entry_t objects by key value. */
|
||||
static INLINE int
|
||||
fp_pair_map_entries_eq(const fp_pair_map_entry_t *a,
|
||||
const fp_pair_map_entry_t *b)
|
||||
{
|
||||
return tor_memeq(&(a->key), &(b->key), sizeof(fp_pair_t));
|
||||
}
|
||||
|
||||
/** Return a hash value for an fp_pair_entry_t. */
|
||||
static INLINE unsigned int
|
||||
fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
|
||||
{
|
||||
const uint32_t *p;
|
||||
unsigned int hash;
|
||||
|
||||
p = (const uint32_t *)(a->key.first);
|
||||
/* Hashes are 20 bytes long, so 5 times uint32_t */
|
||||
hash = p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
|
||||
/* Now XOR in the second fingerprint */
|
||||
p = (const uint32_t *)(a->key.second);
|
||||
hash ^= p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4];
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash table functions for fp_pair_map_t
|
||||
*/
|
||||
|
||||
HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node,
|
||||
fp_pair_map_entry_hash, fp_pair_map_entries_eq)
|
||||
HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node,
|
||||
fp_pair_map_entry_hash, fp_pair_map_entries_eq,
|
||||
0.6, tor_malloc, tor_realloc, tor_free)
|
||||
|
||||
/** Constructor to create a new empty map from fp_pair_t to void *
|
||||
*/
|
||||
|
||||
fp_pair_map_t *
|
||||
fp_pair_map_new(void)
|
||||
{
|
||||
fp_pair_map_t *result;
|
||||
|
||||
result = tor_malloc(sizeof(fp_pair_map_t));
|
||||
HT_INIT(fp_pair_map_impl, &result->head);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Set the current value for key to val; returns the previous
|
||||
* value for key if one was set, or NULL if one was not.
|
||||
*/
|
||||
|
||||
void *
|
||||
fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val)
|
||||
{
|
||||
fp_pair_map_entry_t *resolve;
|
||||
fp_pair_map_entry_t search;
|
||||
void *oldval;
|
||||
|
||||
tor_assert(map);
|
||||
tor_assert(key);
|
||||
tor_assert(val);
|
||||
|
||||
memcpy(&(search.key), key, sizeof(*key));
|
||||
resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
|
||||
if (resolve) {
|
||||
oldval = resolve->val;
|
||||
resolve->val = val;
|
||||
} else {
|
||||
resolve = tor_malloc_zero(sizeof(fp_pair_map_entry_t));
|
||||
memcpy(&(resolve->key), key, sizeof(*key));
|
||||
resolve->val = val;
|
||||
HT_INSERT(fp_pair_map_impl, &(map->head), resolve);
|
||||
oldval = NULL;
|
||||
}
|
||||
|
||||
return oldval;
|
||||
}
|
||||
|
||||
/** Set the current value for the key (first, second) to val; returns
|
||||
* the previous value for key if one was set, or NULL if one was not.
|
||||
*/
|
||||
|
||||
void *
|
||||
fp_pair_map_set_by_digests(fp_pair_map_t *map,
|
||||
const char *first, const char *second,
|
||||
void *val)
|
||||
{
|
||||
fp_pair_t k;
|
||||
|
||||
tor_assert(first);
|
||||
tor_assert(second);
|
||||
|
||||
memcpy(k.first, first, DIGEST_LEN);
|
||||
memcpy(k.second, second, DIGEST_LEN);
|
||||
|
||||
return fp_pair_map_set(map, &k, val);
|
||||
}
|
||||
|
||||
/** Return the current value associated with key, or NULL if no value is set.
|
||||
*/
|
||||
|
||||
void *
|
||||
fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key)
|
||||
{
|
||||
fp_pair_map_entry_t *resolve;
|
||||
fp_pair_map_entry_t search;
|
||||
void *val = NULL;
|
||||
|
||||
tor_assert(map);
|
||||
tor_assert(key);
|
||||
|
||||
memcpy(&(search.key), key, sizeof(*key));
|
||||
resolve = HT_FIND(fp_pair_map_impl, &(map->head), &search);
|
||||
if (resolve) val = resolve->val;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Return the current value associated the key (first, second), or
|
||||
* NULL if no value is set.
|
||||
*/
|
||||
|
||||
void *
|
||||
fp_pair_map_get_by_digests(const fp_pair_map_t *map,
|
||||
const char *first, const char *second)
|
||||
{
|
||||
fp_pair_t k;
|
||||
|
||||
tor_assert(first);
|
||||
tor_assert(second);
|
||||
|
||||
memcpy(k.first, first, DIGEST_LEN);
|
||||
memcpy(k.second, second, DIGEST_LEN);
|
||||
|
||||
return fp_pair_map_get(map, &k);
|
||||
}
|
||||
|
||||
/** Remove the value currently associated with key from the map.
|
||||
* Return the value if one was set, or NULL if there was no entry for
|
||||
* key. The caller must free any storage associated with the
|
||||
* returned value.
|
||||
*/
|
||||
|
||||
void *
|
||||
fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key)
|
||||
{
|
||||
fp_pair_map_entry_t *resolve;
|
||||
fp_pair_map_entry_t search;
|
||||
void *val = NULL;
|
||||
|
||||
tor_assert(map);
|
||||
tor_assert(key);
|
||||
|
||||
memcpy(&(search.key), key, sizeof(*key));
|
||||
resolve = HT_REMOVE(fp_pair_map_impl, &(map->head), &search);
|
||||
if (resolve) {
|
||||
val = resolve->val;
|
||||
tor_free(resolve);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Remove all entries from map, and deallocate storage for those entries.
|
||||
* If free_val is provided, it is invoked on every value in map.
|
||||
*/
|
||||
|
||||
void
|
||||
fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*))
|
||||
{
|
||||
fp_pair_map_entry_t **ent, **next, *this;
|
||||
|
||||
if (map) {
|
||||
for (ent = HT_START(fp_pair_map_impl, &(map->head));
|
||||
ent != NULL; ent = next) {
|
||||
this = *ent;
|
||||
next = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), ent);
|
||||
if (free_val) free_val(this->val);
|
||||
tor_free(this);
|
||||
}
|
||||
tor_assert(HT_EMPTY(&(map->head)));
|
||||
HT_CLEAR(fp_pair_map_impl, &(map->head));
|
||||
tor_free(map);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff map has no entries.
|
||||
*/
|
||||
|
||||
int
|
||||
fp_pair_map_isempty(const fp_pair_map_t *map)
|
||||
{
|
||||
tor_assert(map);
|
||||
|
||||
return HT_EMPTY(&(map->head));
|
||||
}
|
||||
|
||||
/** Return the number of items in map.
|
||||
*/
|
||||
|
||||
int
|
||||
fp_pair_map_size(const fp_pair_map_t *map)
|
||||
{
|
||||
tor_assert(map);
|
||||
|
||||
return HT_SIZE(&(map->head));
|
||||
}
|
||||
|
||||
/** return an iterator pointing to the start of map.
|
||||
*/
|
||||
|
||||
fp_pair_map_iter_t *
|
||||
fp_pair_map_iter_init(fp_pair_map_t *map)
|
||||
{
|
||||
tor_assert(map);
|
||||
|
||||
return HT_START(fp_pair_map_impl, &(map->head));
|
||||
}
|
||||
|
||||
/** Advance iter a single step to the next entry of map, and return
|
||||
* its new value.
|
||||
*/
|
||||
|
||||
fp_pair_map_iter_t *
|
||||
fp_pair_map_iter_next(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
|
||||
{
|
||||
tor_assert(map);
|
||||
tor_assert(iter);
|
||||
|
||||
return HT_NEXT(fp_pair_map_impl, &(map->head), iter);
|
||||
}
|
||||
|
||||
/** Advance iter a single step to the next entry of map, removing the current
|
||||
* entry, and return its new value.
|
||||
*/
|
||||
|
||||
fp_pair_map_iter_t *
|
||||
fp_pair_map_iter_next_rmv(fp_pair_map_t *map, fp_pair_map_iter_t *iter)
|
||||
{
|
||||
fp_pair_map_entry_t *rmv;
|
||||
|
||||
tor_assert(map);
|
||||
tor_assert(iter);
|
||||
tor_assert(*iter);
|
||||
|
||||
rmv = *iter;
|
||||
iter = HT_NEXT_RMV(fp_pair_map_impl, &(map->head), iter);
|
||||
tor_free(rmv);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
/** Set *key_out and *val_out to the current entry pointed to by iter.
|
||||
*/
|
||||
|
||||
void
|
||||
fp_pair_map_iter_get(fp_pair_map_iter_t *iter,
|
||||
fp_pair_t *key_out, void **val_out)
|
||||
{
|
||||
tor_assert(iter);
|
||||
tor_assert(*iter);
|
||||
|
||||
if (key_out) memcpy(key_out, &((*iter)->key), sizeof(fp_pair_t));
|
||||
if (val_out) *val_out = (*iter)->val;
|
||||
}
|
||||
|
||||
/** Return true iff iter has advanced past the last entry of its map.
|
||||
*/
|
||||
|
||||
int
|
||||
fp_pair_map_iter_done(fp_pair_map_iter_t *iter)
|
||||
{
|
||||
return (iter == NULL);
|
||||
}
|
||||
|
||||
/** Assert if anything has gone wrong with the internal
|
||||
* representation of map.
|
||||
*/
|
||||
|
||||
void
|
||||
fp_pair_map_assert_ok(const fp_pair_map_t *map)
|
||||
{
|
||||
tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head)));
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file fp_pair.h
|
||||
* \brief Header file for fp_pair.c.
|
||||
**/
|
||||
|
||||
#ifndef _TOR_FP_PAIR_H
|
||||
#define _TOR_FP_PAIR_H
|
||||
|
||||
/*
|
||||
* Declare fp_pair_map_t functions and structs
|
||||
*/
|
||||
|
||||
typedef struct fp_pair_map_entry_s fp_pair_map_entry_t;
|
||||
typedef struct fp_pair_map_s fp_pair_map_t;
|
||||
typedef fp_pair_map_entry_t *fp_pair_map_iter_t;
|
||||
|
||||
fp_pair_map_t * fp_pair_map_new(void);
|
||||
void * fp_pair_map_set(fp_pair_map_t *map, const fp_pair_t *key, void *val);
|
||||
void * fp_pair_map_set_by_digests(fp_pair_map_t *map,
|
||||
const char *first, const char *second,
|
||||
void *val);
|
||||
void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key);
|
||||
void * fp_pair_map_get_by_digests(const fp_pair_map_t *map,
|
||||
const char *first, const char *second);
|
||||
void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key);
|
||||
void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*));
|
||||
int fp_pair_map_isempty(const fp_pair_map_t *map);
|
||||
int fp_pair_map_size(const fp_pair_map_t *map);
|
||||
fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map);
|
||||
fp_pair_map_iter_t * fp_pair_map_iter_next(fp_pair_map_t *map,
|
||||
fp_pair_map_iter_t *iter);
|
||||
fp_pair_map_iter_t * fp_pair_map_iter_next_rmv(fp_pair_map_t *map,
|
||||
fp_pair_map_iter_t *iter);
|
||||
void fp_pair_map_iter_get(fp_pair_map_iter_t *iter,
|
||||
fp_pair_t *key_out, void **val_out);
|
||||
int fp_pair_map_iter_done(fp_pair_map_iter_t *iter);
|
||||
void fp_pair_map_assert_ok(const fp_pair_map_t *map);
|
||||
|
||||
#undef DECLARE_MAP_FNS
|
||||
|
||||
#endif
|
||||
|
|
@ -45,6 +45,7 @@ src_or_libtor_a_SOURCES = \
|
|||
src/or/dirvote.c \
|
||||
src/or/dns.c \
|
||||
src/or/dnsserv.c \
|
||||
src/or/fp_pair.c \
|
||||
src/or/geoip.c \
|
||||
src/or/entrynodes.c \
|
||||
src/or/hibernate.c \
|
||||
|
@ -126,6 +127,7 @@ ORHEADERS = \
|
|||
src/or/dns.h \
|
||||
src/or/dnsserv.h \
|
||||
src/or/eventdns_tor.h \
|
||||
src/or/fp_pair.h \
|
||||
src/or/geoip.h \
|
||||
src/or/entrynodes.h \
|
||||
src/or/hibernate.h \
|
||||
|
|
|
@ -1878,11 +1878,12 @@ networkstatus_note_certs_arrived(void)
|
|||
if (!waiting->consensus)
|
||||
continue;
|
||||
if (networkstatus_check_consensus_signature(waiting->consensus, 0)>=0) {
|
||||
char *waiting_body = waiting->body;
|
||||
if (!networkstatus_set_current_consensus(
|
||||
waiting->body,
|
||||
waiting_body,
|
||||
networkstatus_get_flavor_name(i),
|
||||
NSSET_WAS_WAITING_FOR_CERTS)) {
|
||||
tor_free(waiting->body);
|
||||
tor_free(waiting_body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2115,9 +2116,7 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs)
|
|||
char *
|
||||
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
|
||||
{
|
||||
char buf[RS_ENTRY_LEN+1];
|
||||
routerstatus_format_entry(buf, sizeof(buf), rs, NULL, NS_CONTROL_PORT, NULL);
|
||||
return tor_strdup(buf);
|
||||
return routerstatus_format_entry(rs, NULL, NS_CONTROL_PORT, NULL);
|
||||
}
|
||||
|
||||
/** Alloc and return a string describing routerstatuses for the most
|
||||
|
|
38
src/or/or.h
38
src/or/or.h
|
@ -2329,7 +2329,8 @@ typedef struct networkstatus_v2_t {
|
|||
typedef struct vote_microdesc_hash_t {
|
||||
/** Next element in the list, or NULL. */
|
||||
struct vote_microdesc_hash_t *next;
|
||||
/** The raw contents of the microdesc hash line, excluding the "m". */
|
||||
/** The raw contents of the microdesc hash line, from the "m" through the
|
||||
* newline. */
|
||||
char *microdesc_hash_line;
|
||||
} vote_microdesc_hash_t;
|
||||
|
||||
|
@ -4001,6 +4002,27 @@ typedef struct {
|
|||
/**
|
||||
* Parameters for path-bias detection.
|
||||
* @{
|
||||
* These options override the default behavior of Tor's (**currently
|
||||
* experimental**) path bias detection algorithm. To try to find broken or
|
||||
* misbehaving guard nodes, Tor looks for nodes where more than a certain
|
||||
* fraction of circuits through that guard fail to get built.
|
||||
*
|
||||
* The PathBiasCircThreshold option controls how many circuits we need to
|
||||
* build through a guard before we make these checks. The
|
||||
* PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options
|
||||
* control what fraction of circuits must succeed through a guard so we
|
||||
* won't write log messages. If less than PathBiasExtremeRate circuits
|
||||
* succeed *and* PathBiasDropGuards is set to 1, we disable use of that
|
||||
* guard.
|
||||
*
|
||||
* When we have seen more than PathBiasScaleThreshold circuits through a
|
||||
* guard, we scale our observations by 0.5 (governed by the consensus) so
|
||||
* that new observations don't get swamped by old ones.
|
||||
*
|
||||
* By default, or if a negative value is provided for one of these options,
|
||||
* Tor uses reasonable defaults from the networkstatus consensus document.
|
||||
* If no defaults are available there, these options default to 150, .70,
|
||||
* .50, .30, 0, and 300 respectively.
|
||||
*/
|
||||
int PathBiasCircThreshold;
|
||||
double PathBiasNoticeRate;
|
||||
|
@ -4013,6 +4035,20 @@ typedef struct {
|
|||
/**
|
||||
* Parameters for path-bias use detection
|
||||
* @{
|
||||
* Similar to the above options, these options override the default behavior
|
||||
* of Tor's (**currently experimental**) path use bias detection algorithm.
|
||||
*
|
||||
* Where as the path bias parameters govern thresholds for successfully
|
||||
* building circuits, these four path use bias parameters govern thresholds
|
||||
* only for circuit usage. Circuits which receive no stream usage are not
|
||||
* counted by this detection algorithm. A used circuit is considered
|
||||
* successful if it is capable of carrying streams or otherwise receiving
|
||||
* well-formed responses to RELAY cells.
|
||||
*
|
||||
* By default, or if a negative value is provided for one of these options,
|
||||
* Tor uses reasonable defaults from the networkstatus consensus document.
|
||||
* If no defaults are available there, these options default to 20, .80,
|
||||
* .60, and 100, respectively.
|
||||
*/
|
||||
int PathBiasUseThreshold;
|
||||
double PathBiasNoticeUseRate;
|
||||
|
|
|
@ -1494,9 +1494,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
|||
if (layer_hint) {
|
||||
if (layer_hint->package_window + CIRCWINDOW_INCREMENT >
|
||||
CIRCWINDOW_START_MAX) {
|
||||
/*XXXX024: Downgrade this back to LOG_PROTOCOL_WARN after a while*/
|
||||
log_fn(LOG_WARN, LD_PROTOCOL,
|
||||
"Bug/attack: unexpected sendme cell from exit relay. "
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Unexpected sendme cell from exit relay. "
|
||||
"Closing circ.");
|
||||
return -END_CIRC_REASON_TORPROTOCOL;
|
||||
}
|
||||
|
@ -1507,9 +1506,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
|||
} else {
|
||||
if (circ->package_window + CIRCWINDOW_INCREMENT >
|
||||
CIRCWINDOW_START_MAX) {
|
||||
/*XXXX024: Downgrade this back to LOG_PROTOCOL_WARN after a while*/
|
||||
log_fn(LOG_WARN, LD_PROTOCOL,
|
||||
"Bug/attack: unexpected sendme cell from client. "
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Unexpected sendme cell from client. "
|
||||
"Closing circ (window %d).",
|
||||
circ->package_window);
|
||||
return -END_CIRC_REASON_TORPROTOCOL;
|
||||
|
|
180
src/or/router.c
180
src/or/router.c
|
@ -969,7 +969,8 @@ init_keys(void)
|
|||
if (cert) { /* add my own cert to the list of known certs */
|
||||
log_info(LD_DIR, "adding my own v3 cert");
|
||||
if (trusted_dirs_load_certs_from_string(
|
||||
cert->cache_info.signed_descriptor_body, 0, 0)<0) {
|
||||
cert->cache_info.signed_descriptor_body,
|
||||
TRUSTED_DIRS_CERTS_SRC_SELF, 0)<0) {
|
||||
log_warn(LD_DIR, "Unable to parse my own v3 cert! Failing.");
|
||||
return -1;
|
||||
}
|
||||
|
@ -1459,13 +1460,18 @@ consider_publishable_server(int force)
|
|||
/** XXX not a very good interface. it's not reliable when there are
|
||||
multiple listeners. */
|
||||
uint16_t
|
||||
router_get_active_listener_port_by_type(int listener_type)
|
||||
router_get_active_listener_port_by_type_af(int listener_type,
|
||||
sa_family_t family)
|
||||
{
|
||||
/* Iterate all connections, find one of the right kind and return
|
||||
the port. Not very sophisticated or fast, but effective. */
|
||||
const connection_t *c = connection_get_by_type(listener_type);
|
||||
if (c)
|
||||
return c->port;
|
||||
smartlist_t *conns = get_connection_array();
|
||||
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
||||
if (conn->type == listener_type && !conn->marked_for_close &&
|
||||
conn->socket_family == family) {
|
||||
return conn->port;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1477,13 +1483,24 @@ router_get_active_listener_port_by_type(int listener_type)
|
|||
uint16_t
|
||||
router_get_advertised_or_port(const or_options_t *options)
|
||||
{
|
||||
int port = get_primary_or_port();
|
||||
return router_get_advertised_or_port_by_af(options, AF_INET);
|
||||
}
|
||||
|
||||
/** As router_get_advertised_or_port(), but allows an address family argument.
|
||||
*/
|
||||
uint16_t
|
||||
router_get_advertised_or_port_by_af(const or_options_t *options,
|
||||
sa_family_t family)
|
||||
{
|
||||
int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
|
||||
family);
|
||||
(void)options;
|
||||
|
||||
/* If the port is in 'auto' mode, we have to use
|
||||
router_get_listener_port_by_type(). */
|
||||
if (port == CFG_AUTO_PORT)
|
||||
return router_get_active_listener_port_by_type(CONN_TYPE_OR_LISTENER);
|
||||
return router_get_active_listener_port_by_type_af(CONN_TYPE_OR_LISTENER,
|
||||
family);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
@ -1503,7 +1520,8 @@ router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport)
|
|||
return dirport;
|
||||
|
||||
if (dirport_configured == CFG_AUTO_PORT)
|
||||
return router_get_active_listener_port_by_type(CONN_TYPE_DIR_LISTENER);
|
||||
return router_get_active_listener_port_by_type_af(CONN_TYPE_DIR_LISTENER,
|
||||
AF_INET);
|
||||
|
||||
return dirport_configured;
|
||||
}
|
||||
|
@ -1944,9 +1962,8 @@ router_rebuild_descriptor(int force)
|
|||
/* ri was allocated with tor_malloc_zero, so there is no need to
|
||||
* zero ri->cache_info.extra_info_digest here. */
|
||||
}
|
||||
ri->cache_info.signed_descriptor_body = tor_malloc(8192);
|
||||
if (router_dump_router_to_string(ri->cache_info.signed_descriptor_body, 8192,
|
||||
ri, get_server_identity_key()) < 0) {
|
||||
if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(
|
||||
ri, get_server_identity_key()))) {
|
||||
log_warn(LD_BUG, "Couldn't generate router descriptor.");
|
||||
routerinfo_free(ri);
|
||||
extrainfo_free(ei);
|
||||
|
@ -2246,54 +2263,54 @@ get_platform_str(char *platform, size_t len)
|
|||
#define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
|
||||
|
||||
/** OR only: Given a routerinfo for this router, and an identity key to sign
|
||||
* with, encode the routerinfo as a signed server descriptor and write the
|
||||
* result into <b>s</b>, using at most <b>maxlen</b> bytes. Return -1 on
|
||||
* failure, and the number of bytes used on success.
|
||||
* with, encode the routerinfo as a signed server descriptor and return a new
|
||||
* string encoding the result, or NULL on failure.
|
||||
*/
|
||||
int
|
||||
router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
||||
char *
|
||||
router_dump_router_to_string(routerinfo_t *router,
|
||||
crypto_pk_t *ident_key)
|
||||
{
|
||||
char *onion_pkey; /* Onion key, PEM-encoded. */
|
||||
char *identity_pkey; /* Identity key, PEM-encoded. */
|
||||
/* XXXX025 Make this look entirely at its arguments, and not at globals.
|
||||
*/
|
||||
char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
|
||||
char *identity_pkey = NULL; /* Identity key, PEM-encoded. */
|
||||
char digest[DIGEST_LEN];
|
||||
char published[ISO_TIME_LEN+1];
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
int has_extra_info_digest;
|
||||
char extra_info_digest[HEX_DIGEST_LEN+1];
|
||||
size_t onion_pkeylen, identity_pkeylen;
|
||||
size_t written;
|
||||
int result=0;
|
||||
char *family_line;
|
||||
char *family_line = NULL;
|
||||
char *extra_or_address = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
smartlist_t *chunks = NULL;
|
||||
char *output = NULL;
|
||||
|
||||
/* Make sure the identity key matches the one in the routerinfo. */
|
||||
if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) {
|
||||
log_warn(LD_BUG,"Tried to sign a router with a private key that didn't "
|
||||
"match router's public key!");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* record our fingerprint, so we can include it in the descriptor */
|
||||
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
|
||||
log_err(LD_BUG,"Error computing fingerprint");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* PEM-encode the onion key */
|
||||
if (crypto_pk_write_public_key_to_string(router->onion_pkey,
|
||||
&onion_pkey,&onion_pkeylen)<0) {
|
||||
log_warn(LD_BUG,"write onion_pkey to string failed!");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* PEM-encode the identity key */
|
||||
if (crypto_pk_write_public_key_to_string(router->identity_pkey,
|
||||
&identity_pkey,&identity_pkeylen)<0) {
|
||||
log_warn(LD_BUG,"write identity_pkey to string failed!");
|
||||
tor_free(onion_pkey);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Encode the publication time. */
|
||||
|
@ -2328,8 +2345,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
|||
}
|
||||
}
|
||||
|
||||
chunks = smartlist_new();
|
||||
/* Generate the easy portion of the router descriptor. */
|
||||
result = tor_snprintf(s, maxlen,
|
||||
smartlist_add_asprintf(chunks,
|
||||
"router %s %s %d 0 %d\n"
|
||||
"%s"
|
||||
"platform %s\n"
|
||||
|
@ -2364,28 +2382,11 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
|||
options->HidServDirectoryV2 ? "hidden-service-dir\n" : "",
|
||||
options->AllowSingleHopExits ? "allow-single-hop-exits\n" : "");
|
||||
|
||||
tor_free(family_line);
|
||||
tor_free(onion_pkey);
|
||||
tor_free(identity_pkey);
|
||||
tor_free(extra_or_address);
|
||||
|
||||
if (result < 0) {
|
||||
log_warn(LD_BUG,"descriptor snprintf #1 ran out of room!");
|
||||
return -1;
|
||||
}
|
||||
/* From now on, we use 'written' to remember the current length of 's'. */
|
||||
written = result;
|
||||
|
||||
if (options->ContactInfo && strlen(options->ContactInfo)) {
|
||||
const char *ci = options->ContactInfo;
|
||||
if (strchr(ci, '\n') || strchr(ci, '\r'))
|
||||
ci = escaped(ci);
|
||||
result = tor_snprintf(s+written,maxlen-written, "contact %s\n", ci);
|
||||
if (result<0) {
|
||||
log_warn(LD_BUG,"descriptor snprintf #2 ran out of room!");
|
||||
return -1;
|
||||
}
|
||||
written += result;
|
||||
smartlist_add_asprintf(chunks, "contact %s\n", ci);
|
||||
}
|
||||
|
||||
#ifdef CURVE25519_ENABLED
|
||||
|
@ -2394,105 +2395,92 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
|||
base64_encode(kbuf, sizeof(kbuf),
|
||||
(const char *)router->onion_curve25519_pkey->public_key,
|
||||
CURVE25519_PUBKEY_LEN);
|
||||
result = tor_snprintf(s+written,maxlen-written, "ntor-onion-key %s",
|
||||
kbuf);
|
||||
if (result<0) {
|
||||
log_warn(LD_BUG,"descriptor snprintf ran out of room!");
|
||||
return -1;
|
||||
}
|
||||
written += result;
|
||||
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write the exit policy to the end of 's'. */
|
||||
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
|
||||
strlcat(s+written, "reject *:*\n", maxlen-written);
|
||||
written += strlen("reject *:*\n");
|
||||
smartlist_add(chunks, tor_strdup("reject *:*\n"));
|
||||
} else if (router->exit_policy) {
|
||||
int i;
|
||||
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
|
||||
char pbuf[POLICY_BUF_LEN];
|
||||
addr_policy_t *tmpe = smartlist_get(router->exit_policy, i);
|
||||
int result;
|
||||
if (tor_addr_family(&tmpe->addr) == AF_INET6)
|
||||
continue; /* Don't include IPv6 parts of address policy */
|
||||
result = policy_write_item(s+written, maxlen-written, tmpe, 1);
|
||||
result = policy_write_item(pbuf, POLICY_BUF_LEN, tmpe, 1);
|
||||
if (result < 0) {
|
||||
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
tor_assert(result == (int)strlen(s+written));
|
||||
written += result;
|
||||
if (written+2 > maxlen) {
|
||||
log_warn(LD_BUG,"descriptor policy_write_item ran out of room (2)!");
|
||||
return -1;
|
||||
}
|
||||
s[written++] = '\n';
|
||||
smartlist_add_asprintf(chunks, "%s\n", pbuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (router->ipv6_exit_policy) {
|
||||
char *p6 = write_short_policy(router->ipv6_exit_policy);
|
||||
if (p6 && strcmp(p6, "reject 1-65535")) {
|
||||
result = tor_snprintf(s+written, maxlen-written,
|
||||
smartlist_add_asprintf(chunks,
|
||||
"ipv6-policy %s\n", p6);
|
||||
if (result<0) {
|
||||
log_warn(LD_BUG,"Descriptor printf of policy ran out of room");
|
||||
tor_free(p6);
|
||||
return -1;
|
||||
}
|
||||
written += result;
|
||||
}
|
||||
tor_free(p6);
|
||||
}
|
||||
|
||||
if (written + DIROBJ_MAX_SIG_LEN > maxlen) {
|
||||
/* Not enough room for signature. */
|
||||
log_warn(LD_BUG,"not enough room left in descriptor for signature!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sign the descriptor */
|
||||
strlcpy(s+written, "router-signature\n", maxlen-written);
|
||||
written += strlen(s+written);
|
||||
s[written] = '\0';
|
||||
if (router_get_router_hash(s, strlen(s), digest) < 0) {
|
||||
return -1;
|
||||
}
|
||||
smartlist_add(chunks, tor_strdup("router-signature\n"));
|
||||
|
||||
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
|
||||
|
||||
note_crypto_pk_op(SIGN_RTR);
|
||||
if (router_append_dirobj_signature(s+written,maxlen-written,
|
||||
digest,DIGEST_LEN,ident_key)<0) {
|
||||
{
|
||||
char *sig;
|
||||
if (!(sig = router_get_dirobj_signature(digest, DIGEST_LEN, ident_key))) {
|
||||
log_warn(LD_BUG, "Couldn't sign router descriptor");
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
smartlist_add(chunks, sig);
|
||||
}
|
||||
written += strlen(s+written);
|
||||
|
||||
if (written+2 > maxlen) {
|
||||
log_warn(LD_BUG,"Not enough room to finish descriptor.");
|
||||
return -1;
|
||||
}
|
||||
/* include a last '\n' */
|
||||
s[written] = '\n';
|
||||
s[written+1] = 0;
|
||||
smartlist_add(chunks, tor_strdup("\n"));
|
||||
|
||||
output = smartlist_join_strings(chunks, "", 0, NULL);
|
||||
|
||||
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
|
||||
{
|
||||
char *s_dup;
|
||||
const char *cp;
|
||||
routerinfo_t *ri_tmp;
|
||||
cp = s_dup = tor_strdup(s);
|
||||
cp = s_dup = tor_strdup(output);
|
||||
ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL);
|
||||
if (!ri_tmp) {
|
||||
log_err(LD_BUG,
|
||||
"We just generated a router descriptor we can't parse.");
|
||||
log_err(LD_BUG, "Descriptor was: <<%s>>", s);
|
||||
return -1;
|
||||
log_err(LD_BUG, "Descriptor was: <<%s>>", output);
|
||||
goto err;
|
||||
}
|
||||
tor_free(s_dup);
|
||||
routerinfo_free(ri_tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (int)written+1;
|
||||
goto done;
|
||||
|
||||
err:
|
||||
tor_free(output); /* sets output to NULL */
|
||||
done:
|
||||
if (chunks) {
|
||||
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
|
||||
smartlist_free(chunks);
|
||||
}
|
||||
tor_free(family_line);
|
||||
tor_free(onion_pkey);
|
||||
tor_free(identity_pkey);
|
||||
tor_free(extra_or_address);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
|
||||
|
|
|
@ -58,8 +58,11 @@ int authdir_mode_publishes_statuses(const or_options_t *options);
|
|||
int authdir_mode_tests_reachability(const or_options_t *options);
|
||||
int authdir_mode_bridge(const or_options_t *options);
|
||||
|
||||
uint16_t router_get_active_listener_port_by_type(int listener_type);
|
||||
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
|
||||
sa_family_t family);
|
||||
uint16_t router_get_advertised_or_port(const or_options_t *options);
|
||||
uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
|
||||
sa_family_t family);
|
||||
uint16_t router_get_advertised_dir_port(const or_options_t *options,
|
||||
uint16_t dirport);
|
||||
|
||||
|
@ -90,7 +93,7 @@ int router_is_me(const routerinfo_t *router);
|
|||
int router_fingerprint_is_me(const char *fp);
|
||||
int router_pick_published_address(const or_options_t *options, uint32_t *addr);
|
||||
int router_rebuild_descriptor(int force);
|
||||
int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
|
||||
char *router_dump_router_to_string(routerinfo_t *router,
|
||||
crypto_pk_t *ident_key);
|
||||
void router_get_prim_orport(const routerinfo_t *router,
|
||||
tor_addr_port_t *addr_port_out);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
#include "entrynodes.h"
|
||||
#include "fp_pair.h"
|
||||
#include "geoip.h"
|
||||
#include "hibernate.h"
|
||||
#include "main.h"
|
||||
|
@ -41,6 +42,24 @@
|
|||
|
||||
/****************************************************************************/
|
||||
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
|
||||
#define SDMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
|
||||
valvar)
|
||||
#define RIMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
|
||||
#define EIMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
|
||||
#define DSMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
|
||||
valvar)
|
||||
|
||||
/* Forward declaration for cert_list_t */
|
||||
typedef struct cert_list_t cert_list_t;
|
||||
|
||||
/* static function prototypes */
|
||||
static int compute_weighted_bandwidths(const smartlist_t *sl,
|
||||
bandwidth_weight_rule_t rule,
|
||||
|
@ -61,19 +80,14 @@ static const char *signed_descriptor_get_body_impl(
|
|||
int with_annotations);
|
||||
static void list_pending_downloads(digestmap_t *result,
|
||||
int purpose, const char *prefix);
|
||||
static void list_pending_fpsk_downloads(fp_pair_map_t *result);
|
||||
static void launch_dummy_descriptor_download_as_needed(time_t now,
|
||||
const or_options_t *options);
|
||||
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
|
||||
DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
|
||||
#define SDMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
|
||||
valvar)
|
||||
#define RIMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(rimap_to_digestmap(map), keyvar, routerinfo_t *, valvar)
|
||||
#define EIMAP_FOREACH(map, keyvar, valvar) \
|
||||
DIGESTMAP_FOREACH(eimap_to_digestmap(map), keyvar, extrainfo_t *, valvar)
|
||||
static void download_status_reset_by_sk_in_cl(cert_list_t *cl,
|
||||
const char *digest);
|
||||
static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
|
||||
const char *digest,
|
||||
time_t now, int max_failures);
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
@ -86,10 +100,17 @@ static smartlist_t *fallback_dir_servers = NULL;
|
|||
|
||||
/** List of for a given authority, and download status for latest certificate.
|
||||
*/
|
||||
typedef struct cert_list_t {
|
||||
download_status_t dl_status;
|
||||
struct cert_list_t {
|
||||
/*
|
||||
* The keys of download status map are cert->signing_key_digest for pending
|
||||
* downloads by (identity digest/signing key digest) pair; functions such
|
||||
* as authority_cert_get_by_digest() already assume these are unique.
|
||||
*/
|
||||
struct digest_ds_map_t *dl_status_map;
|
||||
/* There is also a dlstatus for the download by identity key only */
|
||||
download_status_t dl_status_by_id;
|
||||
smartlist_t *certs;
|
||||
} cert_list_t;
|
||||
};
|
||||
/** Map from v3 identity key digest to cert_list_t. */
|
||||
static digestmap_t *trusted_dir_certs = NULL;
|
||||
/** True iff any key certificate in at least one member of
|
||||
|
@ -133,6 +154,72 @@ get_n_authorities(dirinfo_type_t type)
|
|||
return n;
|
||||
}
|
||||
|
||||
/** Reset the download status of a specified element in a dsmap */
|
||||
static void
|
||||
download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest)
|
||||
{
|
||||
download_status_t *dlstatus = NULL;
|
||||
|
||||
tor_assert(cl);
|
||||
tor_assert(digest);
|
||||
|
||||
/* Make sure we have a dsmap */
|
||||
if (!(cl->dl_status_map)) {
|
||||
cl->dl_status_map = dsmap_new();
|
||||
}
|
||||
/* Look for a download_status_t in the map with this digest */
|
||||
dlstatus = dsmap_get(cl->dl_status_map, digest);
|
||||
/* Got one? */
|
||||
if (!dlstatus) {
|
||||
/* Insert before we reset */
|
||||
dlstatus = tor_malloc_zero(sizeof(*dlstatus));
|
||||
dsmap_set(cl->dl_status_map, digest, dlstatus);
|
||||
}
|
||||
tor_assert(dlstatus);
|
||||
/* Go ahead and reset it */
|
||||
download_status_reset(dlstatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the download for this signing key digest in cl is ready
|
||||
* to be re-attempted.
|
||||
*/
|
||||
static int
|
||||
download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
|
||||
const char *digest,
|
||||
time_t now, int max_failures)
|
||||
{
|
||||
int rv = 0;
|
||||
download_status_t *dlstatus = NULL;
|
||||
|
||||
tor_assert(cl);
|
||||
tor_assert(digest);
|
||||
|
||||
/* Make sure we have a dsmap */
|
||||
if (!(cl->dl_status_map)) {
|
||||
cl->dl_status_map = dsmap_new();
|
||||
}
|
||||
/* Look for a download_status_t in the map with this digest */
|
||||
dlstatus = dsmap_get(cl->dl_status_map, digest);
|
||||
/* Got one? */
|
||||
if (dlstatus) {
|
||||
/* Use download_status_is_ready() */
|
||||
rv = download_status_is_ready(dlstatus, now, max_failures);
|
||||
} else {
|
||||
/*
|
||||
* If we don't know anything about it, return 1, since we haven't
|
||||
* tried this one before. We need to create a new entry here,
|
||||
* too.
|
||||
*/
|
||||
dlstatus = tor_malloc_zero(sizeof(*dlstatus));
|
||||
download_status_reset(dlstatus);
|
||||
dsmap_set(cl->dl_status_map, digest, dlstatus);
|
||||
rv = 1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define get_n_v2_authorities() get_n_authorities(V2_DIRINFO)
|
||||
|
||||
/** Helper: Return the cert_list_t for an authority whose authority ID is
|
||||
|
@ -146,8 +233,9 @@ get_cert_list(const char *id_digest)
|
|||
cl = digestmap_get(trusted_dir_certs, id_digest);
|
||||
if (!cl) {
|
||||
cl = tor_malloc_zero(sizeof(cert_list_t));
|
||||
cl->dl_status.schedule = DL_SCHED_CONSENSUS;
|
||||
cl->dl_status_by_id.schedule = DL_SCHED_CONSENSUS;
|
||||
cl->certs = smartlist_new();
|
||||
cl->dl_status_map = dsmap_new();
|
||||
digestmap_set(trusted_dir_certs, id_digest, cl);
|
||||
}
|
||||
return cl;
|
||||
|
@ -167,7 +255,9 @@ trusted_dirs_reload_certs(void)
|
|||
tor_free(filename);
|
||||
if (!contents)
|
||||
return 0;
|
||||
r = trusted_dirs_load_certs_from_string(contents, 1, 1);
|
||||
r = trusted_dirs_load_certs_from_string(
|
||||
contents,
|
||||
TRUSTED_DIRS_CERTS_SRC_FROM_STORE, 1);
|
||||
tor_free(contents);
|
||||
return r;
|
||||
}
|
||||
|
@ -190,17 +280,23 @@ already_have_cert(authority_cert_t *cert)
|
|||
}
|
||||
|
||||
/** Load a bunch of new key certificates from the string <b>contents</b>. If
|
||||
* <b>from_store</b> is true, the certificates are from the cache, and we
|
||||
* don't need to flush them to disk. If <b>flush</b> is true, we need
|
||||
* to flush any changed certificates to disk now. Return 0 on success, -1
|
||||
* if any certs fail to parse. */
|
||||
* <b>source</b> is TRUSTED_DIRS_CERTS_SRC_FROM_STORE, the certificates are
|
||||
* from the cache, and we don't need to flush them to disk. If we are a
|
||||
* dirauth loading our own cert, source is TRUSTED_DIRS_CERTS_SRC_SELF.
|
||||
* Otherwise, source is download type: TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST
|
||||
* or TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST. If <b>flush</b> is true, we
|
||||
* need to flush any changed certificates to disk now. Return 0 on success,
|
||||
* -1 if any certs fail to parse.
|
||||
*/
|
||||
|
||||
int
|
||||
trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
||||
trusted_dirs_load_certs_from_string(const char *contents, int source,
|
||||
int flush)
|
||||
{
|
||||
dir_server_t *ds;
|
||||
const char *s, *eos;
|
||||
int failure_code = 0;
|
||||
int from_store = (source == TRUSTED_DIRS_CERTS_SRC_FROM_STORE);
|
||||
|
||||
for (s = contents; *s; s = eos) {
|
||||
authority_cert_t *cert = authority_cert_parse_from_string(s, &eos);
|
||||
|
@ -221,9 +317,13 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
|||
from_store ? "cached" : "downloaded",
|
||||
ds ? ds->nickname : "an old or new authority");
|
||||
|
||||
/* a duplicate on a download should be treated as a failure, since it
|
||||
* probably means we wanted a different secret key or we are trying to
|
||||
* replace an expired cert that has not in fact been updated. */
|
||||
/*
|
||||
* A duplicate on download should be treated as a failure, so we call
|
||||
* authority_cert_dl_failed() to reset the download status to make sure
|
||||
* we can't try again. Since we've implemented the fp-sk mechanism
|
||||
* to download certs by signing key, this should be much rarer than it
|
||||
* was and is perhaps cause for concern.
|
||||
*/
|
||||
if (!from_store) {
|
||||
if (authdir_mode(get_options())) {
|
||||
log_warn(LD_DIR,
|
||||
|
@ -237,7 +337,18 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
|||
ds ? ds->nickname : "an old or new authority");
|
||||
}
|
||||
|
||||
authority_cert_dl_failed(cert->cache_info.identity_digest, 404);
|
||||
/*
|
||||
* This is where we care about the source; authority_cert_dl_failed()
|
||||
* needs to know whether the download was by fp or (fp,sk) pair to
|
||||
* twiddle the right bit in the download map.
|
||||
*/
|
||||
if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST) {
|
||||
authority_cert_dl_failed(cert->cache_info.identity_digest,
|
||||
NULL, 404);
|
||||
} else if (source == TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST) {
|
||||
authority_cert_dl_failed(cert->cache_info.identity_digest,
|
||||
cert->signing_key_digest, 404);
|
||||
}
|
||||
}
|
||||
|
||||
authority_cert_free(cert);
|
||||
|
@ -452,17 +563,53 @@ authority_cert_get_all(smartlist_t *certs_out)
|
|||
}
|
||||
|
||||
/** Called when an attempt to download a certificate with the authority with
|
||||
* ID <b>id_digest</b> fails with HTTP response code <b>status</b>: remember
|
||||
* the failure, so we don't try again immediately. */
|
||||
* ID <b>id_digest</b> and, if not NULL, signed with key signing_key_digest
|
||||
* fails with HTTP response code <b>status</b>: remember the failure, so we
|
||||
* don't try again immediately. */
|
||||
void
|
||||
authority_cert_dl_failed(const char *id_digest, int status)
|
||||
authority_cert_dl_failed(const char *id_digest,
|
||||
const char *signing_key_digest, int status)
|
||||
{
|
||||
cert_list_t *cl;
|
||||
download_status_t *dlstatus = NULL;
|
||||
char id_digest_str[2*DIGEST_LEN+1];
|
||||
char sk_digest_str[2*DIGEST_LEN+1];
|
||||
|
||||
if (!trusted_dir_certs ||
|
||||
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
|
||||
return;
|
||||
|
||||
download_status_failed(&cl->dl_status, status);
|
||||
/*
|
||||
* Are we noting a failed download of the latest cert for the id digest,
|
||||
* or of a download by (id, signing key) digest pair?
|
||||
*/
|
||||
if (!signing_key_digest) {
|
||||
/* Just by id digest */
|
||||
download_status_failed(&cl->dl_status_by_id, status);
|
||||
} else {
|
||||
/* Reset by (id, signing key) digest pair
|
||||
*
|
||||
* Look for a download_status_t in the map with this digest
|
||||
*/
|
||||
dlstatus = dsmap_get(cl->dl_status_map, signing_key_digest);
|
||||
/* Got one? */
|
||||
if (dlstatus) {
|
||||
download_status_failed(dlstatus, status);
|
||||
} else {
|
||||
/*
|
||||
* Do this rather than hex_str(), since hex_str clobbers
|
||||
* old results and we call twice in the param list.
|
||||
*/
|
||||
base16_encode(id_digest_str, sizeof(id_digest_str),
|
||||
id_digest, DIGEST_LEN);
|
||||
base16_encode(sk_digest_str, sizeof(sk_digest_str),
|
||||
signing_key_digest, DIGEST_LEN);
|
||||
log_warn(LD_BUG,
|
||||
"Got failure for cert fetch with (fp,sk) = (%s,%s), with "
|
||||
"status %d, but knew nothing about the download.",
|
||||
id_digest_str, sk_digest_str, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff when we've been getting enough failures when trying to
|
||||
|
@ -478,7 +625,7 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
|
|||
!(cl = digestmap_get(trusted_dir_certs, id_digest)))
|
||||
return 0;
|
||||
|
||||
n_failures = download_status_get_n_failures(&cl->dl_status);
|
||||
n_failures = download_status_get_n_failures(&cl->dl_status_by_id);
|
||||
return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER;
|
||||
}
|
||||
|
||||
|
@ -494,20 +641,88 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
|
|||
void
|
||||
authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
||||
{
|
||||
digestmap_t *pending;
|
||||
/*
|
||||
* The pending_id digestmap tracks pending certificate downloads by
|
||||
* identity digest; the pending_cert digestmap tracks pending downloads
|
||||
* by (identity digest, signing key digest) pairs.
|
||||
*/
|
||||
digestmap_t *pending_id;
|
||||
fp_pair_map_t *pending_cert;
|
||||
authority_cert_t *cert;
|
||||
smartlist_t *missing_digests;
|
||||
/*
|
||||
* The missing_id_digests smartlist will hold a list of id digests
|
||||
* we want to fetch the newest cert for; the missing_cert_digests
|
||||
* smartlist will hold a list of fp_pair_t with an identity and
|
||||
* signing key digest.
|
||||
*/
|
||||
smartlist_t *missing_cert_digests, *missing_id_digests;
|
||||
char *resource = NULL;
|
||||
cert_list_t *cl;
|
||||
const int cache = directory_caches_unknown_auth_certs(get_options());
|
||||
fp_pair_t *fp_tmp = NULL;
|
||||
char id_digest_str[2*DIGEST_LEN+1];
|
||||
char sk_digest_str[2*DIGEST_LEN+1];
|
||||
|
||||
if (should_delay_dir_fetches(get_options()))
|
||||
return;
|
||||
|
||||
pending = digestmap_new();
|
||||
missing_digests = smartlist_new();
|
||||
pending_cert = fp_pair_map_new();
|
||||
pending_id = digestmap_new();
|
||||
missing_cert_digests = smartlist_new();
|
||||
missing_id_digests = smartlist_new();
|
||||
|
||||
list_pending_downloads(pending, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
|
||||
/*
|
||||
* First, we get the lists of already pending downloads so we don't
|
||||
* duplicate effort.
|
||||
*/
|
||||
list_pending_downloads(pending_id, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
|
||||
list_pending_fpsk_downloads(pending_cert);
|
||||
|
||||
/*
|
||||
* Now, we download any trusted authority certs we don't have by
|
||||
* identity digest only. This gets the latest cert for that authority.
|
||||
*/
|
||||
SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds) {
|
||||
int found = 0;
|
||||
if (!(ds->type & V3_DIRINFO))
|
||||
continue;
|
||||
if (smartlist_contains_digest(missing_id_digests,
|
||||
ds->v3_identity_digest))
|
||||
continue;
|
||||
cl = get_cert_list(ds->v3_identity_digest);
|
||||
SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) {
|
||||
if (now < cert->expires) {
|
||||
/* It's not expired, and we weren't looking for something to
|
||||
* verify a consensus with. Call it done. */
|
||||
download_status_reset(&(cl->dl_status_by_id));
|
||||
/* No sense trying to download it specifically by signing key hash */
|
||||
download_status_reset_by_sk_in_cl(cl, cert->signing_key_digest);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(cert);
|
||||
if (!found &&
|
||||
download_status_is_ready(&(cl->dl_status_by_id), now,
|
||||
MAX_CERT_DL_FAILURES) &&
|
||||
!digestmap_get(pending_id, ds->v3_identity_digest)) {
|
||||
log_info(LD_DIR,
|
||||
"No current certificate known for authority %s "
|
||||
"(ID digest %s); launching request.",
|
||||
ds->nickname, hex_str(ds->v3_identity_digest, DIGEST_LEN));
|
||||
smartlist_add(missing_id_digests, ds->v3_identity_digest);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
|
||||
/*
|
||||
* Next, if we have a consensus, scan through it and look for anything
|
||||
* signed with a key from a cert we don't have. Those get downloaded
|
||||
* by (fp,sk) pair, but if we don't know any certs at all for the fp
|
||||
* (identity digest), and it's one of the trusted dir server certs
|
||||
* we started off above or a pending download in pending_id, don't
|
||||
* try to get it yet. Most likely, the one we'll get for that will
|
||||
* have the right signing key too, and we'd just be downloading
|
||||
* redundantly.
|
||||
*/
|
||||
if (status) {
|
||||
SMARTLIST_FOREACH_BEGIN(status->voters, networkstatus_voter_info_t *,
|
||||
voter) {
|
||||
|
@ -517,84 +732,164 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
|||
if (!cache &&
|
||||
!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
|
||||
continue; /* We are not a cache, and we don't know this authority.*/
|
||||
|
||||
/*
|
||||
* If we don't know *any* cert for this authority, and a download by ID
|
||||
* is pending or we added it to missing_id_digests above, skip this
|
||||
* one for now to avoid duplicate downloads.
|
||||
*/
|
||||
cl = get_cert_list(voter->identity_digest);
|
||||
if (smartlist_len(cl->certs) == 0) {
|
||||
/* We have no certs at all for this one */
|
||||
|
||||
/* Do we have a download of one pending? */
|
||||
if (digestmap_get(pending_id, voter->identity_digest))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Are we about to launch a download of one due to the trusted
|
||||
* dir server check above?
|
||||
*/
|
||||
if (smartlist_contains_digest(missing_id_digests,
|
||||
voter->identity_digest))
|
||||
continue;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(voter->sigs, document_signature_t *, sig) {
|
||||
cert = authority_cert_get_by_digests(voter->identity_digest,
|
||||
sig->signing_key_digest);
|
||||
if (cert) {
|
||||
if (now < cert->expires)
|
||||
download_status_reset(&cl->dl_status);
|
||||
download_status_reset_by_sk_in_cl(cl, sig->signing_key_digest);
|
||||
continue;
|
||||
}
|
||||
if (download_status_is_ready(&cl->dl_status, now,
|
||||
MAX_CERT_DL_FAILURES) &&
|
||||
!digestmap_get(pending, voter->identity_digest)) {
|
||||
log_info(LD_DIR, "We're missing a certificate from authority "
|
||||
"with signing key %s: launching request.",
|
||||
hex_str(sig->signing_key_digest, DIGEST_LEN));
|
||||
smartlist_add(missing_digests, sig->identity_digest);
|
||||
if (download_status_is_ready_by_sk_in_cl(
|
||||
cl, sig->signing_key_digest,
|
||||
now, MAX_CERT_DL_FAILURES) &&
|
||||
!fp_pair_map_get_by_digests(pending_cert,
|
||||
voter->identity_digest,
|
||||
sig->signing_key_digest)) {
|
||||
/*
|
||||
* Do this rather than hex_str(), since hex_str clobbers
|
||||
* old results and we call twice in the param list.
|
||||
*/
|
||||
base16_encode(id_digest_str, sizeof(id_digest_str),
|
||||
voter->identity_digest, DIGEST_LEN);
|
||||
base16_encode(sk_digest_str, sizeof(sk_digest_str),
|
||||
sig->signing_key_digest, DIGEST_LEN);
|
||||
|
||||
if (voter->nickname) {
|
||||
log_info(LD_DIR,
|
||||
"We're missing a certificate from authority %s "
|
||||
"(ID digest %s) with signing key %s: "
|
||||
"launching request.",
|
||||
voter->nickname, id_digest_str, sk_digest_str);
|
||||
} else {
|
||||
log_info(LD_DIR,
|
||||
"We're missing a certificate from authority ID digest "
|
||||
"%s with signing key %s: launching request.",
|
||||
id_digest_str, sk_digest_str);
|
||||
}
|
||||
|
||||
/* Allocate a new fp_pair_t to append */
|
||||
fp_tmp = tor_malloc(sizeof(*fp_tmp));
|
||||
memcpy(fp_tmp->first, voter->identity_digest, sizeof(fp_tmp->first));
|
||||
memcpy(fp_tmp->second, sig->signing_key_digest,
|
||||
sizeof(fp_tmp->second));
|
||||
smartlist_add(missing_cert_digests, fp_tmp);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(sig);
|
||||
} SMARTLIST_FOREACH_END(voter);
|
||||
}
|
||||
SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ds) {
|
||||
int found = 0;
|
||||
if (!(ds->type & V3_DIRINFO))
|
||||
continue;
|
||||
if (smartlist_contains_digest(missing_digests, ds->v3_identity_digest))
|
||||
continue;
|
||||
cl = get_cert_list(ds->v3_identity_digest);
|
||||
SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, {
|
||||
if (now < cert->expires) {
|
||||
/* It's not expired, and we weren't looking for something to
|
||||
* verify a consensus with. Call it done. */
|
||||
download_status_reset(&cl->dl_status);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (!found &&
|
||||
download_status_is_ready(&cl->dl_status, now,MAX_CERT_DL_FAILURES) &&
|
||||
!digestmap_get(pending, ds->v3_identity_digest)) {
|
||||
log_info(LD_DIR, "No current certificate known for authority %s; "
|
||||
"launching request.", ds->nickname);
|
||||
smartlist_add(missing_digests, ds->v3_identity_digest);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
|
||||
if (!smartlist_len(missing_digests)) {
|
||||
goto done;
|
||||
} else {
|
||||
/* Do downloads by identity digest */
|
||||
if (smartlist_len(missing_id_digests) > 0) {
|
||||
int need_plus = 0;
|
||||
smartlist_t *fps = smartlist_new();
|
||||
|
||||
smartlist_add(fps, tor_strdup("fp/"));
|
||||
SMARTLIST_FOREACH(missing_digests, const char *, d, {
|
||||
char *fp;
|
||||
if (digestmap_get(pending, d))
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(missing_id_digests, const char *, d) {
|
||||
char *fp = NULL;
|
||||
|
||||
if (digestmap_get(pending_id, d))
|
||||
continue;
|
||||
fp = tor_malloc(HEX_DIGEST_LEN+2);
|
||||
base16_encode(fp, HEX_DIGEST_LEN+1, d, DIGEST_LEN);
|
||||
fp[HEX_DIGEST_LEN] = '+';
|
||||
fp[HEX_DIGEST_LEN+1] = '\0';
|
||||
|
||||
base16_encode(id_digest_str, sizeof(id_digest_str),
|
||||
d, DIGEST_LEN);
|
||||
|
||||
if (need_plus) {
|
||||
tor_asprintf(&fp, "+%s", id_digest_str);
|
||||
} else {
|
||||
/* No need for tor_asprintf() in this case; first one gets no '+' */
|
||||
fp = tor_strdup(id_digest_str);
|
||||
need_plus = 1;
|
||||
}
|
||||
|
||||
smartlist_add(fps, fp);
|
||||
});
|
||||
if (smartlist_len(fps) == 1) {
|
||||
/* we didn't add any: they were all pending */
|
||||
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
||||
smartlist_free(fps);
|
||||
goto done;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(d);
|
||||
|
||||
if (smartlist_len(fps) > 1) {
|
||||
resource = smartlist_join_strings(fps, "", 0, NULL);
|
||||
resource[strlen(resource)-1] = '\0';
|
||||
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
||||
smartlist_free(fps);
|
||||
}
|
||||
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
|
||||
resource, PDS_RETRY_IF_NO_SERVERS);
|
||||
|
||||
done:
|
||||
tor_free(resource);
|
||||
smartlist_free(missing_digests);
|
||||
digestmap_free(pending, NULL);
|
||||
}
|
||||
/* else we didn't add any: they were all pending */
|
||||
|
||||
SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp));
|
||||
smartlist_free(fps);
|
||||
}
|
||||
|
||||
/* Do downloads by identity digest/signing key pair */
|
||||
if (smartlist_len(missing_cert_digests) > 0) {
|
||||
int need_plus = 0;
|
||||
smartlist_t *fp_pairs = smartlist_new();
|
||||
|
||||
smartlist_add(fp_pairs, tor_strdup("fp-sk/"));
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(missing_cert_digests, const fp_pair_t *, d) {
|
||||
char *fp_pair = NULL;
|
||||
|
||||
if (fp_pair_map_get(pending_cert, d))
|
||||
continue;
|
||||
|
||||
/* Construct string encodings of the digests */
|
||||
base16_encode(id_digest_str, sizeof(id_digest_str),
|
||||
d->first, DIGEST_LEN);
|
||||
base16_encode(sk_digest_str, sizeof(sk_digest_str),
|
||||
d->second, DIGEST_LEN);
|
||||
|
||||
/* Now tor_asprintf() */
|
||||
if (need_plus) {
|
||||
tor_asprintf(&fp_pair, "+%s-%s", id_digest_str, sk_digest_str);
|
||||
} else {
|
||||
/* First one in the list doesn't get a '+' */
|
||||
tor_asprintf(&fp_pair, "%s-%s", id_digest_str, sk_digest_str);
|
||||
need_plus = 1;
|
||||
}
|
||||
|
||||
/* Add it to the list of pairs to request */
|
||||
smartlist_add(fp_pairs, fp_pair);
|
||||
} SMARTLIST_FOREACH_END(d);
|
||||
|
||||
if (smartlist_len(fp_pairs) > 1) {
|
||||
resource = smartlist_join_strings(fp_pairs, "", 0, NULL);
|
||||
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
|
||||
resource, PDS_RETRY_IF_NO_SERVERS);
|
||||
tor_free(resource);
|
||||
}
|
||||
/* else they were all pending */
|
||||
|
||||
SMARTLIST_FOREACH(fp_pairs, char *, p, tor_free(p));
|
||||
smartlist_free(fp_pairs);
|
||||
}
|
||||
|
||||
smartlist_free(missing_id_digests);
|
||||
SMARTLIST_FOREACH(missing_cert_digests, fp_pair_t *, p, tor_free(p));
|
||||
smartlist_free(missing_cert_digests);
|
||||
digestmap_free(pending_id, NULL);
|
||||
fp_pair_map_free(pending_cert, NULL);
|
||||
}
|
||||
|
||||
/* Router descriptor storage.
|
||||
|
@ -4078,6 +4373,41 @@ list_pending_microdesc_downloads(digestmap_t *result)
|
|||
list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
|
||||
}
|
||||
|
||||
/** For every certificate we are currently downloading by (identity digest,
|
||||
* signing key digest) pair, set result[fp_pair] to (void *1).
|
||||
*/
|
||||
static void
|
||||
list_pending_fpsk_downloads(fp_pair_map_t *result)
|
||||
{
|
||||
const char *pfx = "fp-sk/";
|
||||
smartlist_t *tmp;
|
||||
smartlist_t *conns;
|
||||
const char *resource;
|
||||
|
||||
tor_assert(result);
|
||||
|
||||
tmp = smartlist_new();
|
||||
conns = get_connection_array();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
|
||||
if (conn->type == CONN_TYPE_DIR &&
|
||||
conn->purpose == DIR_PURPOSE_FETCH_CERTIFICATE &&
|
||||
!conn->marked_for_close) {
|
||||
resource = TO_DIR_CONN(conn)->requested_resource;
|
||||
if (!strcmpstart(resource, pfx))
|
||||
dir_split_resource_into_fingerprint_pairs(resource + strlen(pfx),
|
||||
tmp);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(conn);
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(tmp, fp_pair_t *, fp) {
|
||||
fp_pair_map_set(result, fp, (void*)1);
|
||||
tor_free(fp);
|
||||
} SMARTLIST_FOREACH_END(fp);
|
||||
|
||||
smartlist_free(tmp);
|
||||
}
|
||||
|
||||
/** Launch downloads for all the descriptors whose digests or digests256
|
||||
* are listed as digests[i] for lo <= i < hi. (Lo and hi may be out of
|
||||
* range.) If <b>source</b> is given, download from <b>source</b>;
|
||||
|
|
|
@ -13,7 +13,20 @@
|
|||
|
||||
int get_n_authorities(dirinfo_type_t type);
|
||||
int trusted_dirs_reload_certs(void);
|
||||
int trusted_dirs_load_certs_from_string(const char *contents, int from_store,
|
||||
|
||||
/*
|
||||
* Pass one of these as source to trusted_dirs_load_certs_from_string()
|
||||
* to indicate whence string originates; this controls error handling
|
||||
* behavior such as marking downloads as failed.
|
||||
*/
|
||||
|
||||
#define TRUSTED_DIRS_CERTS_SRC_SELF 0
|
||||
#define TRUSTED_DIRS_CERTS_SRC_FROM_STORE 1
|
||||
#define TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST 2
|
||||
#define TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_SK_DIGEST 3
|
||||
#define TRUSTED_DIRS_CERTS_SRC_FROM_VOTE 4
|
||||
|
||||
int trusted_dirs_load_certs_from_string(const char *contents, int source,
|
||||
int flush);
|
||||
void trusted_dirs_flush_certs_to_disk(void);
|
||||
authority_cert_t *authority_cert_get_newest_by_id(const char *id_digest);
|
||||
|
@ -21,7 +34,8 @@ authority_cert_t *authority_cert_get_by_sk_digest(const char *sk_digest);
|
|||
authority_cert_t *authority_cert_get_by_digests(const char *id_digest,
|
||||
const char *sk_digest);
|
||||
void authority_cert_get_all(smartlist_t *certs_out);
|
||||
void authority_cert_dl_failed(const char *id_digest, int status);
|
||||
void authority_cert_dl_failed(const char *id_digest,
|
||||
const char *signing_key_digest, int status);
|
||||
void authority_certs_fetch_missing(networkstatus_t *status, time_t now);
|
||||
int router_reload_router_list(void);
|
||||
int authority_cert_dl_looks_uncertain(const char *id_digest);
|
||||
|
|
|
@ -662,18 +662,6 @@ router_get_networkstatus_v3_hashes(const char *s, digests_t *digests)
|
|||
' ');
|
||||
}
|
||||
|
||||
/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
|
||||
* string in <b>s</b>. Return 0 on success, -1 on failure. */
|
||||
int
|
||||
router_get_networkstatus_v3_hash(const char *s, char *digest,
|
||||
digest_algorithm_t alg)
|
||||
{
|
||||
return router_get_hash_impl(s, strlen(s), digest,
|
||||
"network-status-version",
|
||||
"\ndirectory-signature",
|
||||
' ', alg);
|
||||
}
|
||||
|
||||
/** Set <b>digest</b> to the SHA-1 digest of the hash of the <b>s_len</b>-byte
|
||||
* extrainfo string at <b>s</b>. Return 0 on success, -1 on failure. */
|
||||
int
|
||||
|
@ -683,6 +671,61 @@ router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
|
|||
"\nrouter-signature",'\n', DIGEST_SHA1);
|
||||
}
|
||||
|
||||
/** Helper: used to generate signatures for routers, directories and
|
||||
* network-status objects. Given a <b>digest_len</b>-byte digest in
|
||||
* <b>digest</b> and a secret <b>private_key</b>, generate an PKCS1-padded
|
||||
* signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs,
|
||||
* and return the new signature on success or NULL on failure.
|
||||
*/
|
||||
char *
|
||||
router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key)
|
||||
{
|
||||
char *signature;
|
||||
size_t i, keysize;
|
||||
int siglen;
|
||||
char *buf = NULL;
|
||||
size_t buf_len;
|
||||
/* overestimate of BEGIN/END lines total len. */
|
||||
#define BEGIN_END_OVERHEAD_LEN 64
|
||||
|
||||
keysize = crypto_pk_keysize(private_key);
|
||||
signature = tor_malloc(keysize);
|
||||
siglen = crypto_pk_private_sign(private_key, signature, keysize,
|
||||
digest, digest_len);
|
||||
if (siglen < 0) {
|
||||
log_warn(LD_BUG,"Couldn't sign digest.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* The *2 here is a ridiculous overestimate of base-64 overhead. */
|
||||
buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN;
|
||||
buf = tor_malloc(buf_len);
|
||||
|
||||
if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
i = strlen(buf);
|
||||
if (base64_encode(buf+i, buf_len-i, signature, siglen) < 0) {
|
||||
log_warn(LD_BUG,"couldn't base64-encode signature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
tor_free(signature);
|
||||
return buf;
|
||||
|
||||
truncated:
|
||||
log_warn(LD_BUG,"tried to exceed string length.");
|
||||
err:
|
||||
tor_free(signature);
|
||||
tor_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Helper: used to generate signatures for routers, directories and
|
||||
* network-status objects. Given a digest in <b>digest</b> and a secret
|
||||
* <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
|
||||
|
@ -694,38 +737,21 @@ int
|
|||
router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
|
||||
size_t digest_len, crypto_pk_t *private_key)
|
||||
{
|
||||
char *signature;
|
||||
size_t i, keysize;
|
||||
int siglen;
|
||||
|
||||
keysize = crypto_pk_keysize(private_key);
|
||||
signature = tor_malloc(keysize);
|
||||
siglen = crypto_pk_private_sign(private_key, signature, keysize,
|
||||
digest, digest_len);
|
||||
if (siglen < 0) {
|
||||
log_warn(LD_BUG,"Couldn't sign digest.");
|
||||
goto err;
|
||||
}
|
||||
if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
i = strlen(buf);
|
||||
if (base64_encode(buf+i, buf_len-i, signature, siglen) < 0) {
|
||||
log_warn(LD_BUG,"couldn't base64-encode signature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
|
||||
goto truncated;
|
||||
|
||||
tor_free(signature);
|
||||
return 0;
|
||||
|
||||
truncated:
|
||||
log_warn(LD_BUG,"tried to exceed string length.");
|
||||
err:
|
||||
tor_free(signature);
|
||||
size_t sig_len, s_len;
|
||||
char *sig = router_get_dirobj_signature(digest, digest_len, private_key);
|
||||
if (!sig) {
|
||||
log_warn(LD_BUG, "No signature generated");
|
||||
return -1;
|
||||
}
|
||||
sig_len = strlen(sig);
|
||||
s_len = strlen(buf);
|
||||
if (sig_len + s_len + 1 > buf_len) {
|
||||
log_warn(LD_BUG, "Not enough room for signature");
|
||||
tor_free(sig);
|
||||
return -1;
|
||||
}
|
||||
memcpy(buf+s_len, sig, sig_len+1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
|
||||
|
@ -1494,7 +1520,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
|
|||
extrainfo = tor_malloc_zero(sizeof(extrainfo_t));
|
||||
extrainfo->cache_info.is_extrainfo = 1;
|
||||
if (cache_copy)
|
||||
extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s, end-s);
|
||||
extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s,end-s);
|
||||
extrainfo->cache_info.signed_descriptor_len = end-s;
|
||||
memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
|
||||
|
||||
|
|
|
@ -16,11 +16,12 @@ int router_get_router_hash(const char *s, size_t s_len, char *digest);
|
|||
int router_get_dir_hash(const char *s, char *digest);
|
||||
int router_get_runningrouters_hash(const char *s, char *digest);
|
||||
int router_get_networkstatus_v2_hash(const char *s, char *digest);
|
||||
int router_get_networkstatus_v3_hash(const char *s, char *digest,
|
||||
digest_algorithm_t algorithm);
|
||||
int router_get_networkstatus_v3_hashes(const char *s, digests_t *digests);
|
||||
int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest);
|
||||
#define DIROBJ_MAX_SIG_LEN 256
|
||||
char *router_get_dirobj_signature(const char *digest,
|
||||
size_t digest_len,
|
||||
crypto_pk_t *private_key);
|
||||
int router_append_dirobj_signature(char *buf, size_t buf_len,
|
||||
const char *digest,
|
||||
size_t digest_len,
|
||||
|
|
|
@ -108,7 +108,8 @@ setup_directory(void)
|
|||
r = mkdir(temp_dir);
|
||||
}
|
||||
#else
|
||||
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s", (int) getpid(), rnd32);
|
||||
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
|
||||
(int) getpid(), rnd32);
|
||||
r = mkdir(temp_dir, 0700);
|
||||
#endif
|
||||
if (r) {
|
||||
|
@ -467,7 +468,7 @@ test_socks_5_no_authenticate(void *ptr)
|
|||
get_options()->SafeSocks));
|
||||
test_eq(5, socks->socks_version);
|
||||
test_eq(2, socks->replylen);
|
||||
test_eq(5, socks->reply[0]);
|
||||
test_eq(1, socks->reply[0]);
|
||||
test_eq(0, socks->reply[1]);
|
||||
|
||||
test_eq(2, socks->usernamelen);
|
||||
|
@ -506,7 +507,7 @@ test_socks_5_authenticate(void *ptr)
|
|||
get_options()->SafeSocks));
|
||||
test_eq(5, socks->socks_version);
|
||||
test_eq(2, socks->replylen);
|
||||
test_eq(5, socks->reply[0]);
|
||||
test_eq(1, socks->reply[0]);
|
||||
test_eq(0, socks->reply[1]);
|
||||
|
||||
test_eq(2, socks->usernamelen);
|
||||
|
@ -546,7 +547,7 @@ test_socks_5_authenticate_with_data(void *ptr)
|
|||
get_options()->SafeSocks) == 1);
|
||||
test_eq(5, socks->socks_version);
|
||||
test_eq(2, socks->replylen);
|
||||
test_eq(5, socks->reply[0]);
|
||||
test_eq(1, socks->reply[0]);
|
||||
test_eq(0, socks->reply[1]);
|
||||
|
||||
test_streq("2.2.2.2", socks->address);
|
||||
|
@ -812,6 +813,18 @@ test_buffers(void)
|
|||
buf_free(buf);
|
||||
buf = NULL;
|
||||
|
||||
/* Try adding a string too long for any freelist. */
|
||||
{
|
||||
char *cp = tor_malloc_zero(65536);
|
||||
buf = buf_new();
|
||||
write_to_buf(cp, 65536, buf);
|
||||
tor_free(cp);
|
||||
|
||||
tt_int_op(buf_datalen(buf), ==, 65536);
|
||||
buf_free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
done:
|
||||
if (buf)
|
||||
buf_free(buf);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "orconfig.h"
|
||||
#include "or.h"
|
||||
#include "fp_pair.h"
|
||||
#include "test.h"
|
||||
|
||||
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
|
||||
|
@ -826,6 +827,88 @@ test_di_map(void *arg)
|
|||
dimap_free(map, NULL);
|
||||
}
|
||||
|
||||
/** Run unit tests for fp_pair-to-void* map functions */
|
||||
static void
|
||||
test_container_fp_pair_map(void)
|
||||
{
|
||||
fp_pair_map_t *map;
|
||||
fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6;
|
||||
void *v;
|
||||
fp_pair_map_iter_t *iter;
|
||||
fp_pair_t k;
|
||||
|
||||
map = fp_pair_map_new();
|
||||
test_assert(map);
|
||||
test_eq(fp_pair_map_size(map), 0);
|
||||
test_assert(fp_pair_map_isempty(map));
|
||||
|
||||
memset(fp1.first, 0x11, DIGEST_LEN);
|
||||
memset(fp1.second, 0x12, DIGEST_LEN);
|
||||
memset(fp2.first, 0x21, DIGEST_LEN);
|
||||
memset(fp2.second, 0x22, DIGEST_LEN);
|
||||
memset(fp3.first, 0x31, DIGEST_LEN);
|
||||
memset(fp3.second, 0x32, DIGEST_LEN);
|
||||
memset(fp4.first, 0x41, DIGEST_LEN);
|
||||
memset(fp4.second, 0x42, DIGEST_LEN);
|
||||
memset(fp5.first, 0x51, DIGEST_LEN);
|
||||
memset(fp5.second, 0x52, DIGEST_LEN);
|
||||
memset(fp6.first, 0x61, DIGEST_LEN);
|
||||
memset(fp6.second, 0x62, DIGEST_LEN);
|
||||
|
||||
v = fp_pair_map_set(map, &fp1, (void*)99);
|
||||
test_eq(v, NULL);
|
||||
test_assert(!fp_pair_map_isempty(map));
|
||||
v = fp_pair_map_set(map, &fp2, (void*)101);
|
||||
test_eq(v, NULL);
|
||||
v = fp_pair_map_set(map, &fp1, (void*)100);
|
||||
test_eq(v, (void*)99);
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100);
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101);
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp3), NULL);
|
||||
fp_pair_map_assert_ok(map);
|
||||
|
||||
v = fp_pair_map_remove(map, &fp2);
|
||||
fp_pair_map_assert_ok(map);
|
||||
test_eq_ptr(v, (void*)101);
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
|
||||
test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL);
|
||||
|
||||
fp_pair_map_set(map, &fp2, (void*)101);
|
||||
fp_pair_map_set(map, &fp3, (void*)102);
|
||||
fp_pair_map_set(map, &fp4, (void*)103);
|
||||
test_eq(fp_pair_map_size(map), 4);
|
||||
fp_pair_map_assert_ok(map);
|
||||
fp_pair_map_set(map, &fp5, (void*)104);
|
||||
fp_pair_map_set(map, &fp6, (void*)105);
|
||||
fp_pair_map_assert_ok(map);
|
||||
|
||||
/* Test iterator. */
|
||||
iter = fp_pair_map_iter_init(map);
|
||||
while (!fp_pair_map_iter_done(iter)) {
|
||||
fp_pair_map_iter_get(iter, &k, &v);
|
||||
test_eq_ptr(v, fp_pair_map_get(map, &k));
|
||||
|
||||
if (tor_memeq(&fp2, &k, sizeof(fp2))) {
|
||||
iter = fp_pair_map_iter_next_rmv(map, iter);
|
||||
} else {
|
||||
iter = fp_pair_map_iter_next(map, iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure we removed fp2, but not the others. */
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
|
||||
test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104);
|
||||
|
||||
fp_pair_map_assert_ok(map);
|
||||
/* Clean up after ourselves. */
|
||||
fp_pair_map_free(map, NULL);
|
||||
map = NULL;
|
||||
|
||||
done:
|
||||
if (map)
|
||||
fp_pair_map_free(map, NULL);
|
||||
}
|
||||
|
||||
#define CONTAINER_LEGACY(name) \
|
||||
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
|
||||
|
||||
|
@ -841,6 +924,7 @@ struct testcase_t container_tests[] = {
|
|||
CONTAINER_LEGACY(pqueue),
|
||||
CONTAINER_LEGACY(order_functions),
|
||||
{ "di_map", test_di_map, 0, NULL, NULL },
|
||||
CONTAINER_LEGACY(fp_pair_map),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
|
|
@ -730,7 +730,7 @@ test_crypto_aes_iv(void *arg)
|
|||
/* Decrypt with the wrong key. */
|
||||
decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
|
||||
encrypted1, encrypted_size);
|
||||
test_memneq(plain, decrypted2, encrypted_size);
|
||||
test_memneq(plain, decrypted2, decrypted_size);
|
||||
/* Alter the initialization vector. */
|
||||
encrypted1[0] += 42;
|
||||
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define ROUTERLIST_PRIVATE
|
||||
#define HIBERNATE_PRIVATE
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
|
@ -73,22 +74,24 @@ test_dir_nicknames(void)
|
|||
static void
|
||||
test_dir_formats(void)
|
||||
{
|
||||
char buf[8192], buf2[8192];
|
||||
char *buf = NULL;
|
||||
char buf2[8192];
|
||||
char platform[256];
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
|
||||
size_t pk1_str_len, pk2_str_len, pk3_str_len;
|
||||
char *pk1_str = NULL, *pk2_str = NULL, *cp;
|
||||
size_t pk1_str_len, pk2_str_len;
|
||||
routerinfo_t *r1=NULL, *r2=NULL;
|
||||
crypto_pk_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
|
||||
routerinfo_t *rp1 = NULL;
|
||||
crypto_pk_t *pk1 = NULL, *pk2 = NULL;
|
||||
routerinfo_t *rp1 = NULL, *rp2 = NULL;
|
||||
addr_policy_t *ex1, *ex2;
|
||||
routerlist_t *dir1 = NULL, *dir2 = NULL;
|
||||
or_options_t *options = get_options_mutable();
|
||||
const addr_policy_t *p;
|
||||
|
||||
pk1 = pk_generate(0);
|
||||
pk2 = pk_generate(1);
|
||||
pk3 = pk_generate(2);
|
||||
|
||||
test_assert(pk1 && pk2 && pk3);
|
||||
test_assert(pk1 && pk2);
|
||||
|
||||
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
|
||||
|
||||
|
@ -128,22 +131,27 @@ test_dir_formats(void)
|
|||
r2->or_port = 9005;
|
||||
r2->dir_port = 0;
|
||||
r2->onion_pkey = crypto_pk_dup_key(pk2);
|
||||
r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t));
|
||||
curve25519_public_from_base64(r2->onion_curve25519_pkey,
|
||||
"skyinAnvardNostarsNomoonNowindormistsorsnow");
|
||||
r2->identity_pkey = crypto_pk_dup_key(pk1);
|
||||
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
|
||||
r2->exit_policy = smartlist_new();
|
||||
smartlist_add(r2->exit_policy, ex2);
|
||||
smartlist_add(r2->exit_policy, ex1);
|
||||
smartlist_add(r2->exit_policy, ex2);
|
||||
r2->nickname = tor_strdup("Fred");
|
||||
|
||||
test_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
|
||||
&pk1_str_len));
|
||||
test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
|
||||
&pk2_str_len));
|
||||
test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str,
|
||||
&pk3_str_len));
|
||||
|
||||
memset(buf, 0, 2048);
|
||||
test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
|
||||
/* XXXX025 router_dump_to_string should really take this from ri.*/
|
||||
options->ContactInfo = tor_strdup("Magri White "
|
||||
"<magri@elsewhere.example.com>");
|
||||
buf = router_dump_router_to_string(r1, pk2);
|
||||
tor_free(options->ContactInfo);
|
||||
test_assert(buf);
|
||||
|
||||
strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n"
|
||||
"or-address [1:2:3:4::]:9999\n"
|
||||
|
@ -165,13 +173,17 @@ test_dir_formats(void)
|
|||
strlcat(buf2, "signing-key\n", sizeof(buf2));
|
||||
strlcat(buf2, pk2_str, sizeof(buf2));
|
||||
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
||||
strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
|
||||
sizeof(buf2));
|
||||
strlcat(buf2, "reject *:*\nrouter-signature\n", sizeof(buf2));
|
||||
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
|
||||
* twice */
|
||||
|
||||
test_streq(buf, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
|
||||
buf = router_dump_router_to_string(r1, pk2);
|
||||
test_assert(buf);
|
||||
cp = buf;
|
||||
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
|
||||
test_assert(rp1);
|
||||
|
@ -185,35 +197,67 @@ test_dir_formats(void)
|
|||
test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
|
||||
//test_assert(rp1->exit_policy == NULL);
|
||||
|
||||
#if 0
|
||||
/* XXX Once we have exit policies, test this again. XXX */
|
||||
strlcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n", sizeof(buf2));
|
||||
strlcpy(buf2,
|
||||
"router Fred 1.1.1.1 9005 0 0\n"
|
||||
"platform Tor "VERSION" on ", sizeof(buf2));
|
||||
strlcat(buf2, get_uname(), sizeof(buf2));
|
||||
strlcat(buf2, "\n"
|
||||
"protocols Link 1 2 Circuit 1\n"
|
||||
"published 1970-01-01 00:00:05\n"
|
||||
"fingerprint ", sizeof(buf2));
|
||||
test_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
|
||||
strlcat(buf2, fingerprint, sizeof(buf2));
|
||||
strlcat(buf2, "\nuptime 0\n"
|
||||
"bandwidth 3000 3000 3000\n", sizeof(buf2));
|
||||
strlcat(buf2, "onion-key\n", sizeof(buf2));
|
||||
strlcat(buf2, pk2_str, sizeof(buf2));
|
||||
strlcat(buf2, "signing-key\n", sizeof(buf2));
|
||||
strlcat(buf2, pk1_str, sizeof(buf2));
|
||||
strlcat(buf2, "accept *:80\nreject 18.*:24\n\n", sizeof(buf2));
|
||||
test_assert(router_dump_router_to_string(buf, 2048, &r2, pk2)>0);
|
||||
test_streq(buf, buf2);
|
||||
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
|
||||
strlcat(buf2, "ntor-onion-key "
|
||||
"skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
|
||||
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
|
||||
strlcat(buf2, "router-signature\n", sizeof(buf2));
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1);
|
||||
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
|
||||
* twice */
|
||||
test_streq(buf, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1);
|
||||
cp = buf;
|
||||
rp2 = router_parse_entry_from_string(&cp,1);
|
||||
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
|
||||
test_assert(rp2);
|
||||
test_streq(rp2->address, r2.address);
|
||||
test_eq(rp2->or_port, r2.or_port);
|
||||
test_eq(rp2->dir_port, r2.dir_port);
|
||||
test_eq(rp2->bandwidth, r2.bandwidth);
|
||||
test_streq(rp2->address, r2->address);
|
||||
test_eq(rp2->or_port, r2->or_port);
|
||||
test_eq(rp2->dir_port, r2->dir_port);
|
||||
test_eq(rp2->bandwidthrate, r2->bandwidthrate);
|
||||
test_eq(rp2->bandwidthburst, r2->bandwidthburst);
|
||||
test_eq(rp2->bandwidthcapacity, r2->bandwidthcapacity);
|
||||
test_memeq(rp2->onion_curve25519_pkey->public_key,
|
||||
r2->onion_curve25519_pkey->public_key,
|
||||
CURVE25519_PUBKEY_LEN);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
|
||||
test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
|
||||
test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
|
||||
test_streq(rp2->exit_policy->string, "accept *:80");
|
||||
test_streq(rp2->exit_policy->address, "*");
|
||||
test_streq(rp2->exit_policy->port, "80");
|
||||
test_eq(rp2->exit_policy->next->policy_type, EXIT_POLICY_REJECT);
|
||||
test_streq(rp2->exit_policy->next->string, "reject 18.*:24");
|
||||
test_streq(rp2->exit_policy->next->address, "18.*");
|
||||
test_streq(rp2->exit_policy->next->port, "24");
|
||||
test_assert(rp2->exit_policy->next->next == NULL);
|
||||
|
||||
test_eq(smartlist_len(rp2->exit_policy), 2);
|
||||
|
||||
p = smartlist_get(rp2->exit_policy, 0);
|
||||
test_eq(p->policy_type, ADDR_POLICY_ACCEPT);
|
||||
test_assert(tor_addr_is_null(&p->addr));
|
||||
test_eq(p->maskbits, 0);
|
||||
test_eq(p->prt_min, 80);
|
||||
test_eq(p->prt_max, 80);
|
||||
|
||||
p = smartlist_get(rp2->exit_policy, 1);
|
||||
test_eq(p->policy_type, ADDR_POLICY_REJECT);
|
||||
test_assert(tor_addr_eq(&p->addr, &ex2->addr));
|
||||
test_eq(p->maskbits, 8);
|
||||
test_eq(p->prt_min, 24);
|
||||
test_eq(p->prt_max, 24);
|
||||
|
||||
#if 0
|
||||
/* Okay, now for the directories. */
|
||||
{
|
||||
fingerprint_list = smartlist_new();
|
||||
|
@ -232,12 +276,11 @@ test_dir_formats(void)
|
|||
if (r2)
|
||||
routerinfo_free(r2);
|
||||
|
||||
tor_free(buf);
|
||||
tor_free(pk1_str);
|
||||
tor_free(pk2_str);
|
||||
tor_free(pk3_str);
|
||||
if (pk1) crypto_pk_free(pk1);
|
||||
if (pk2) crypto_pk_free(pk2);
|
||||
if (pk3) crypto_pk_free(pk3);
|
||||
if (rp1) routerinfo_free(rp1);
|
||||
tor_free(dir1); /* XXXX And more !*/
|
||||
tor_free(dir2); /* And more !*/
|
||||
|
@ -611,7 +654,7 @@ test_dir_measured_bw_kb_cache(void)
|
|||
test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL));
|
||||
test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL));
|
||||
test_eq(bw, 20);
|
||||
test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, &as_of));
|
||||
test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of));
|
||||
test_eq(as_of, MBWC_INIT_TIME);
|
||||
/* Now expire it */
|
||||
curr += MAX_MEASUREMENT_AGE + 1;
|
||||
|
@ -619,7 +662,7 @@ test_dir_measured_bw_kb_cache(void)
|
|||
/* Check that the cache is empty */
|
||||
test_eq(dirserv_get_measured_bw_cache_size(), 0);
|
||||
/* Check that we can't retrieve it */
|
||||
test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL, NULL));
|
||||
test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL));
|
||||
/* Try caching a few things now */
|
||||
dirserv_cache_measured_bw(&(mbwl[0]), curr);
|
||||
test_eq(dirserv_get_measured_bw_cache_size(), 1);
|
||||
|
@ -934,6 +977,13 @@ gen_routerstatus_for_v3ns(int idx, time_t now)
|
|||
/* Shouldn't happen */
|
||||
test_assert(0);
|
||||
}
|
||||
if (vrs) {
|
||||
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
|
||||
tor_asprintf(&vrs->microdesc->microdesc_hash_line,
|
||||
"m 9,10,11,12,13,14,15,16,17 "
|
||||
"sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
|
||||
idx);
|
||||
}
|
||||
|
||||
done:
|
||||
return vrs;
|
||||
|
@ -1903,6 +1953,13 @@ gen_routerstatus_for_umbw(int idx, time_t now)
|
|||
/* Shouldn't happen */
|
||||
test_assert(0);
|
||||
}
|
||||
if (vrs) {
|
||||
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
|
||||
tor_asprintf(&vrs->microdesc->microdesc_hash_line,
|
||||
"m 9,10,11,12,13,14,15,16,17 "
|
||||
"sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
|
||||
idx);
|
||||
}
|
||||
|
||||
done:
|
||||
return vrs;
|
||||
|
@ -2050,7 +2107,7 @@ test_consensus_for_umbw(networkstatus_t *con, time_t now)
|
|||
|
||||
test_assert(con);
|
||||
test_assert(!con->cert);
|
||||
/* test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB); */
|
||||
// test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
|
||||
test_assert(con->consensus_method >= 16);
|
||||
test_eq(4, smartlist_len(con->routerstatus_list));
|
||||
/* There should be four listed routers; all voters saw the same in this */
|
||||
|
@ -2176,8 +2233,8 @@ test_dir_clip_unmeasured_bw_kb(void)
|
|||
}
|
||||
|
||||
/**
|
||||
* This version of test_dir_clip_unmeasured_bw_kb() uses a non-default choice of
|
||||
* clip bandwidth.
|
||||
* This version of test_dir_clip_unmeasured_bw_kb() uses a non-default choice
|
||||
* of clip bandwidth.
|
||||
*/
|
||||
|
||||
static void
|
||||
|
@ -2197,26 +2254,138 @@ test_dir_clip_unmeasured_bw_kb_alt(void)
|
|||
test_routerstatus_for_umbw);
|
||||
}
|
||||
|
||||
extern time_t time_of_process_start; /* from main.c */
|
||||
|
||||
static void
|
||||
test_dir_v2_dir(void *arg)
|
||||
{
|
||||
/* Runs in a forked process: acts like a v2 directory just enough to make and
|
||||
* sign a v2 networkstatus opinion */
|
||||
|
||||
cached_dir_t *v2 = NULL;
|
||||
or_options_t *options = get_options_mutable();
|
||||
crypto_pk_t *id_key = pk_generate(4);
|
||||
(void) arg;
|
||||
|
||||
options->ORPort_set = 1; /* So we believe we're a server. */
|
||||
options->DirPort_set = 1;
|
||||
options->Address = tor_strdup("99.99.99.99");
|
||||
options->Nickname = tor_strdup("TestV2Auth");
|
||||
options->ContactInfo = tor_strdup("TestV2Auth <testv2auth@example.com>");
|
||||
{
|
||||
/* Give it a DirPort */
|
||||
smartlist_t *ports = (smartlist_t *)get_configured_ports();
|
||||
port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
port->type = CONN_TYPE_DIR_LISTENER;
|
||||
port->port = 9999;
|
||||
smartlist_add(ports, port);
|
||||
}
|
||||
set_server_identity_key(id_key);
|
||||
set_client_identity_key(id_key);
|
||||
|
||||
/* Add a router. */
|
||||
{
|
||||
was_router_added_t wra;
|
||||
const char *msg = NULL;
|
||||
routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
r1->address = tor_strdup("18.244.0.1");
|
||||
r1->addr = 0xc0a80001u; /* 192.168.0.1 */
|
||||
r1->cache_info.published_on = time(NULL)-60;
|
||||
r1->or_port = 9000;
|
||||
r1->dir_port = 9003;
|
||||
tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
|
||||
r1->ipv6_orport = 9999;
|
||||
r1->onion_pkey = pk_generate(1);
|
||||
r1->identity_pkey = pk_generate(2);
|
||||
r1->bandwidthrate = 1000;
|
||||
r1->bandwidthburst = 5000;
|
||||
r1->bandwidthcapacity = 10000;
|
||||
r1->exit_policy = NULL;
|
||||
r1->nickname = tor_strdup("Magri");
|
||||
r1->platform = tor_strdup("Tor 0.2.7.7-gamma");
|
||||
r1->cache_info.routerlist_index = -1;
|
||||
r1->cache_info.signed_descriptor_body =
|
||||
router_dump_router_to_string(r1, r1->identity_pkey);
|
||||
r1->cache_info.signed_descriptor_len =
|
||||
strlen(r1->cache_info.signed_descriptor_body);
|
||||
wra = router_add_to_routerlist(r1, &msg, 0, 0);
|
||||
tt_int_op(wra, ==, ROUTER_ADDED_SUCCESSFULLY);
|
||||
}
|
||||
|
||||
/* Prevent call of rep_hist_note_router_unreachable(). */
|
||||
time_of_process_start = time(NULL);
|
||||
|
||||
/* Make a directory so there's somewhere to store the thing */
|
||||
#ifdef _WIN32
|
||||
mkdir(get_fname("cached-status"));
|
||||
#else
|
||||
mkdir(get_fname("cached-status"), 0700);
|
||||
#endif
|
||||
|
||||
v2 = generate_v2_networkstatus_opinion();
|
||||
tt_assert(v2);
|
||||
|
||||
done:
|
||||
crypto_pk_free(id_key);
|
||||
cached_dir_decref(v2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dir_fmt_control_ns(void *arg)
|
||||
{
|
||||
char *s = NULL;
|
||||
routerstatus_t rs;
|
||||
(void)arg;
|
||||
|
||||
memset(&rs, 0, sizeof(rs));
|
||||
rs.published_on = 1364925198;
|
||||
strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname));
|
||||
memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN);
|
||||
memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN);
|
||||
rs.addr = 0x20304050;
|
||||
rs.or_port = 9001;
|
||||
rs.dir_port = 9002;
|
||||
rs.is_exit = 1;
|
||||
rs.is_fast = 1;
|
||||
rs.is_flagged_running = 1;
|
||||
rs.has_bandwidth = 1;
|
||||
rs.bandwidth_kb = 1000;
|
||||
|
||||
s = networkstatus_getinfo_helper_single(&rs);
|
||||
tt_assert(s);
|
||||
tt_str_op(s, ==,
|
||||
"r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA "
|
||||
"TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 "
|
||||
"32.48.64.80 9001 9002\n"
|
||||
"s Exit Fast Running\n"
|
||||
"w Bandwidth=1000\n");
|
||||
|
||||
done:
|
||||
tor_free(s);
|
||||
}
|
||||
|
||||
#define DIR_LEGACY(name) \
|
||||
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
|
||||
|
||||
#define DIR(name) \
|
||||
{ #name, test_dir_##name, 0, NULL, NULL }
|
||||
#define DIR(name,flags) \
|
||||
{ #name, test_dir_##name, (flags), NULL, NULL }
|
||||
|
||||
struct testcase_t dir_tests[] = {
|
||||
DIR_LEGACY(nicknames),
|
||||
DIR_LEGACY(formats),
|
||||
DIR_LEGACY(versions),
|
||||
DIR_LEGACY(fp_pairs),
|
||||
DIR(split_fps),
|
||||
DIR(split_fps, 0),
|
||||
DIR_LEGACY(measured_bw_kb),
|
||||
DIR_LEGACY(measured_bw_kb_cache),
|
||||
DIR_LEGACY(param_voting),
|
||||
DIR_LEGACY(v3_networkstatus),
|
||||
DIR(random_weighted),
|
||||
DIR(scale_bw),
|
||||
DIR(random_weighted, 0),
|
||||
DIR(scale_bw, 0),
|
||||
DIR_LEGACY(clip_unmeasured_bw_kb),
|
||||
DIR_LEGACY(clip_unmeasured_bw_kb_alt),
|
||||
DIR_LEGACY(measured_bw_kb_cache),
|
||||
DIR(v2_dir, TT_FORK),
|
||||
DIR(fmt_control_ns, 0),
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue