aboutsummaryrefslogtreecommitdiff
path: root/src/feature/dirclient/dirclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/dirclient/dirclient.c')
-rw-r--r--src/feature/dirclient/dirclient.c171
1 files changed, 85 insertions, 86 deletions
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index 6725fc3369..ae1e018df2 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -1,8 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file dirclient.c
+ * @brief Download directory information
+ **/
+
#define DIRCLIENT_PRIVATE
#include "core/or/or.h"
@@ -14,12 +19,14 @@
#include "core/or/policies.h"
#include "feature/client/bridges.h"
#include "feature/client/entrynodes.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirclient/dirclient.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/consdiff.h"
#include "feature/dircommon/directory.h"
@@ -37,6 +44,7 @@
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "feature/rend/rendcache.h"
@@ -45,6 +53,7 @@
#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
+#include "lib/cc/ctassert.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -448,7 +457,7 @@ directory_get_from_dirserver,(
{
const routerstatus_t *rs = NULL;
const or_options_t *options = get_options();
- int prefer_authority = (directory_fetches_from_authorities(options)
+ int prefer_authority = (dirclient_fetches_from_authorities(options)
|| want_authority == DL_WANT_AUTHORITY);
int require_authority = 0;
int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose,
@@ -667,7 +676,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
if (indirection == DIRIND_DIRECT_CONN ||
indirection == DIRIND_ANON_DIRPORT ||
(indirection == DIRIND_ONEHOP
- && !directory_must_use_begindir(options))) {
+ && !dirclient_must_use_begindir(options))) {
fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0,
use_dir_ap);
have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0);
@@ -866,16 +875,6 @@ connection_dir_download_cert_failed(dir_connection_t *conn, int status)
update_certificate_downloads(time(NULL));
}
-/* Should this tor instance only use begindir for all its directory requests?
- */
-int
-directory_must_use_begindir(const or_options_t *options)
-{
- /* Clients, onion services, and bridges must use begindir,
- * relays and authorities do not have to */
- return !public_server_mode(options);
-}
-
/** Evaluate the situation and decide if we should use an encrypted
* "begindir-style" connection for this directory request.
* 0) If there is no DirPort, yes.
@@ -927,7 +926,7 @@ directory_command_should_use_begindir(const or_options_t *options,
}
/* Reasons why we want to avoid using begindir */
if (indirection == DIRIND_ONEHOP) {
- if (!directory_must_use_begindir(options)) {
+ if (!dirclient_must_use_begindir(options)) {
*reason = "in relay mode";
return 0;
}
@@ -1289,7 +1288,7 @@ directory_initiate_request,(directory_request_t *request))
/* use encrypted begindir connections for everything except relays
* this provides better protection for directory fetches */
- if (!use_begindir && directory_must_use_begindir(options)) {
+ if (!use_begindir && dirclient_must_use_begindir(options)) {
log_warn(LD_BUG, "Client could not use begindir connection: %s",
begindir_reason ? begindir_reason : "(NULL)");
return;
@@ -1447,9 +1446,7 @@ compare_strs_(const void **a, const void **b)
}
#define CONDITIONAL_CONSENSUS_FPR_LEN 3
-#if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
-#error "conditional consensus fingerprint length is larger than digest length"
-#endif
+CTASSERT(CONDITIONAL_CONSENSUS_FPR_LEN <= DIGEST_LEN);
/** Return the URL we should use for a consensus download.
*
@@ -1968,6 +1965,44 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
return rv;
}
+/**
+ * Total number of bytes downloaded of each directory purpose, when
+ * bootstrapped, and when not bootstrapped.
+ *
+ * (For example, the number of bytes downloaded of purpose p while
+ * not fully bootstrapped is total_dl[p][false].)
+ **/
+static uint64_t total_dl[DIR_PURPOSE_MAX_][2];
+
+/**
+ * Heartbeat: dump a summary of how many bytes of which purpose we've
+ * downloaded, when bootstrapping and when not bootstrapping.
+ **/
+void
+dirclient_dump_total_dls(void)
+{
+ const or_options_t *options = get_options();
+ for (int bootstrapped = 0; bootstrapped < 2; ++bootstrapped) {
+ bool first_time = true;
+ for (int i=0; i < DIR_PURPOSE_MAX_; ++i) {
+ uint64_t n = total_dl[i][bootstrapped];
+ if (n == 0)
+ continue;
+ if (options->SafeLogging_ != SAFELOG_SCRUB_NONE &&
+ purpose_needs_anonymity(i, ROUTER_PURPOSE_GENERAL, NULL))
+ continue;
+ if (first_time) {
+ log_notice(LD_NET,
+ "While %sbootstrapping, fetched this many bytes: ",
+ bootstrapped?"not ":"");
+ first_time = false;
+ }
+ log_notice(LD_NET, " %"PRIu64" (%s)",
+ n, dir_conn_purpose_to_string(i));
+ }
+ }
+}
+
/** We are a client, and we've finished reading the server's
* response. Parse it and act appropriately.
*
@@ -2001,6 +2036,16 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
received_bytes = connection_get_inbuf_len(TO_CONN(conn));
+ log_debug(LD_DIR, "Downloaded %"TOR_PRIuSZ" bytes on connection of purpose "
+ "%s; bootstrap %d%%",
+ received_bytes,
+ dir_conn_purpose_to_string(conn->base_.purpose),
+ control_get_bootstrap_percent());
+ {
+ bool bootstrapped = control_get_bootstrap_percent() == 100;
+ total_dl[conn->base_.purpose][bootstrapped] += received_bytes;
+ }
+
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
&body, &body_len, MAX_DIR_DL_SIZE,
@@ -2205,24 +2250,31 @@ handle_response_fetch_consensus(dir_connection_t *conn,
if (looks_like_a_consensus_diff(body, body_len)) {
/* First find our previous consensus. Maybe it's in ram, maybe not. */
cached_dir_t *cd = dirserv_get_consensus(flavname);
- const char *consensus_body;
- char *owned_consensus = NULL;
+ const char *consensus_body = NULL;
+ size_t consensus_body_len;
+ tor_mmap_t *mapped_consensus = NULL;
if (cd) {
consensus_body = cd->dir;
+ consensus_body_len = cd->dir_len;
} else {
- owned_consensus = networkstatus_read_cached_consensus(flavname);
- consensus_body = owned_consensus;
+ mapped_consensus = networkstatus_map_cached_consensus(flavname);
+ if (mapped_consensus) {
+ consensus_body = mapped_consensus->data;
+ consensus_body_len = mapped_consensus->size;
+ }
}
if (!consensus_body) {
log_warn(LD_DIR, "Received a consensus diff, but we can't find "
"any %s-flavored consensus in our current cache.",flavname);
+ tor_munmap_file(mapped_consensus);
networkstatus_consensus_download_failed(0, flavname);
// XXXX if this happens too much, see below
return -1;
}
- new_consensus = consensus_diff_apply(consensus_body, body);
- tor_free(owned_consensus);
+ new_consensus = consensus_diff_apply(consensus_body, consensus_body_len,
+ body, body_len);
+ tor_munmap_file(mapped_consensus);
if (new_consensus == NULL) {
log_warn(LD_DIR, "Could not apply consensus diff received from server "
"'%s:%d'", conn->base_.address, conn->base_.port);
@@ -2244,7 +2296,9 @@ handle_response_fetch_consensus(dir_connection_t *conn,
sourcename = "downloaded";
}
- if ((r=networkstatus_set_current_consensus(consensus, flavname, 0,
+ if ((r=networkstatus_set_current_consensus(consensus,
+ strlen(consensus),
+ flavname, 0,
conn->identity_digest))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory %s from "
@@ -2359,7 +2413,7 @@ handle_response_fetch_status_vote(dir_connection_t *conn,
conn->base_.port, conn->requested_resource);
return -1;
}
- dirvote_add_vote(body, &msg, &st);
+ dirvote_add_vote(body, 0, &msg, &st);
if (st > 299) {
log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
} else {
@@ -2522,7 +2576,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
conn->base_.port);
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
- tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN));
+ tor_assert_nonfatal(!fast_mem_is_zero(conn->identity_digest, DIGEST_LEN));
which = smartlist_new();
dir_split_resource_into_fingerprints(conn->requested_resource+2,
which, NULL,
@@ -2719,62 +2773,7 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
log_info(LD_REND,"Received v3 hsdesc (body size %d, status %d (%s))",
(int)body_len, status_code, escaped(reason));
- switch (status_code) {
- case 200:
- /* We got something: Try storing it in the cache. */
- if (hs_cache_store_as_client(body, &conn->hs_ident->identity_pk) < 0) {
- log_info(LD_REND, "Failed to store hidden service descriptor");
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "BAD_DESC");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- } else {
- log_info(LD_REND, "Stored hidden service descriptor successfully.");
- TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC;
- hs_client_desc_has_arrived(conn->hs_ident);
- /* Fire control port RECEIVED event. */
- hs_control_desc_event_received(conn->hs_ident, conn->identity_digest);
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- body);
- }
- break;
- case 404:
- /* Not there. We'll retry when connection_about_to_close_connection()
- * tries to clean this conn up. */
- log_info(LD_REND, "Fetching hidden service v3 descriptor not found: "
- "Retrying at another directory.");
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "NOT_FOUND");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- case 400:
- log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
- "http status 400 (%s). Dirserver didn't like our "
- "query? Retrying at another directory.",
- escaped(reason));
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "QUERY_REJECTED");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- default:
- log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
- "http status %d (%s) response unexpected from HSDir server "
- "'%s:%d'. Retrying at another directory.",
- status_code, escaped(reason), TO_CONN(conn)->address,
- TO_CONN(conn)->port);
- /* Fire control port FAILED event. */
- hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
- "UNEXPECTED");
- hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
- NULL);
- break;
- }
-
+ hs_client_dir_fetch_done(conn, reason, body, status_code);
return 0;
}
@@ -3134,7 +3133,7 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
{
char digest[DIGEST_LEN];
time_t now = time(NULL);
- int server = directory_fetches_from_authorities(get_options());
+ int server = dirclient_fetches_from_authorities(get_options());
if (!was_descriptor_digests) {
if (router_purpose == ROUTER_PURPOSE_BRIDGE) {
tor_assert(!was_extrainfo);
@@ -3179,7 +3178,7 @@ dir_microdesc_download_failed(smartlist_t *failed,
routerstatus_t *rs;
download_status_t *dls;
time_t now = time(NULL);
- int server = directory_fetches_from_authorities(get_options());
+ int server = dirclient_fetches_from_authorities(get_options());
if (! consensus)
return;