aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/compat.c5
-rw-r--r--src/common/util.c12
-rw-r--r--src/config/torrc.minimal.in-staging2
-rw-r--r--src/config/torrc.sample.in2
-rw-r--r--src/or/circuituse.c18
-rw-r--r--src/or/config.c4
-rw-r--r--src/or/confparse.c2
-rw-r--r--src/or/directory.c35
-rw-r--r--src/or/hs_common.c13
-rw-r--r--src/or/hs_descriptor.c13
-rw-r--r--src/or/hs_descriptor.h3
-rw-r--r--src/or/or.h4
-rw-r--r--src/or/parsecommon.h1
-rw-r--r--src/or/policies.c37
-rw-r--r--src/or/policies.h3
-rw-r--r--src/or/protover.c2
-rw-r--r--src/or/rendservice.c76
-rw-r--r--src/or/router.c4
-rw-r--r--src/or/routerparse.c4
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_dir.c24
-rw-r--r--src/test/test_hs.c55
-rw-r--r--src/test/test_hs_descriptor.c1
-rw-r--r--src/test/test_policy.c18
-rw-r--r--src/test/testing_common.c34
25 files changed, 253 insertions, 120 deletions
diff --git a/src/common/compat.c b/src/common/compat.c
index 4f2f9778f2..8d6a491c42 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -532,7 +532,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
/* On Windows, _vsnprintf won't tell us the length of the string if it
* overflows, so we need to use _vcsprintf to tell how much to allocate */
int len, r;
- len = _vscprintf(fmt, args);
+ va_list tmp_args;
+ va_copy(tmp_args, args);
+ len = _vscprintf(fmt, tmp_args);
+ va_end(tmp_args);
if (len < 0) {
*strp = NULL;
return -1;
diff --git a/src/common/util.c b/src/common/util.c
index b1159e5334..cb5f12821e 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -2191,11 +2191,13 @@ file_status(const char *fname)
}
}
-/** Check whether <b>dirname</b> exists and is private. If yes return 0. If
- * it does not exist, and <b>check</b>&CPD_CREATE is set, try to create it
- * and return 0 on success. If it does not exist, and
- * <b>check</b>&CPD_CHECK, and we think we can create it, return 0. Else
- * return -1. If CPD_GROUP_OK is set, then it's okay if the directory
+/** Check whether <b>dirname</b> exists and is private. If yes return 0.
+ * If <b>dirname</b> does not exist:
+ * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success.
+ * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0.
+ * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0.
+ * - otherwise, return -1.
+ * If CPD_GROUP_OK is set, then it's okay if the directory
* is group-readable, but in all cases we create the directory mode 0700.
* If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and
* if the directory is created it will use mode 0750 with group read
diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging
index 5fa37c18f0..c537c51f9b 100644
--- a/src/config/torrc.minimal.in-staging
+++ b/src/config/torrc.minimal.in-staging
@@ -105,7 +105,7 @@
## Define these to limit how much relayed traffic you will allow. Your
## own traffic is still unthrottled. Note that RelayBandwidthRate must
-## be at least 20 kilobytes per second.
+## be at least 75 kilobytes per second.
## Note that units for these config options are bytes (per second), not
## bits (per second), and that prefixes are binary prefixes, i.e. 2^10,
## 2^20, etc.
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index d4dfd5f6bb..5328206da9 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -104,7 +104,7 @@
## Define these to limit how much relayed traffic you will allow. Your
## own traffic is still unthrottled. Note that RelayBandwidthRate must
-## be at least 20 kilobytes per second.
+## be at least 75 kilobytes per second.
## Note that units for these config options are bytes (per second), not
## bits (per second), and that prefixes are binary prefixes, i.e. 2^10,
## 2^20, etc.
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 71615bc17a..ba7b75ff25 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -807,6 +807,8 @@ static time_t last_expired_clientside_circuits = 0;
* As a diagnostic for bug 8387, log information about how many one-hop
* circuits we have around that have been there for at least <b>age</b>
* seconds. Log a few of them.
+ * Ignores Single Onion Service intro and Tor2web redezvous circuits, they are
+ * expected to be long-term one-hop circuits.
*/
void
circuit_log_ancient_one_hop_circuits(int age)
@@ -816,6 +818,7 @@ circuit_log_ancient_one_hop_circuits(int age)
time_t cutoff = now - age;
int n_found = 0;
smartlist_t *log_these = smartlist_new();
+ const or_options_t *options = get_options();
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
const origin_circuit_t *ocirc;
@@ -823,6 +826,19 @@ circuit_log_ancient_one_hop_circuits(int age)
continue;
if (circ->timestamp_created.tv_sec >= cutoff)
continue;
+ /* Single Onion Services deliberately make long term one-hop intro
+ * connections. We only ignore active intro point connections, if we take
+ * a long time establishing, that's worth logging. */
+ if (rend_service_allow_non_anonymous_connection(options) &&
+ circ->purpose == CIRCUIT_PURPOSE_S_INTRO)
+ continue;
+ /* Tor2web deliberately makes long term one-hop rend connections,
+ * particularly when Tor2webRendezvousPoints is used. We only ignore
+ * active rend point connections, if we take a long time to rendezvous,
+ * that's worth logging. */
+ if (rend_client_allow_non_anonymous_connection(options) &&
+ circ->purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
+ continue;
ocirc = CONST_TO_ORIGIN_CIRCUIT(circ);
if (ocirc->build_state && ocirc->build_state->onehop_tunnel) {
@@ -858,7 +874,7 @@ circuit_log_ancient_one_hop_circuits(int age)
tor_asprintf(&dirty, "Dirty since %s (%ld seconds vs %ld-second cutoff)",
dirty_since, (long)(now - circ->timestamp_dirty),
- (long) get_options()->MaxCircuitDirtiness);
+ (long) options->MaxCircuitDirtiness);
} else {
dirty = tor_strdup("Not marked dirty");
}
diff --git a/src/or/config.c b/src/or/config.c
index fef12083e0..9553822ba3 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -550,7 +550,7 @@ static config_var_t option_vars_[] = {
* When clients have authorities and fallbacks available, they use these
* schedules: (we stagger the times to avoid thundering herds) */
V(ClientBootstrapConsensusAuthorityDownloadSchedule, CSV_INTERVAL,
- "10, 11, 3600, 10800, 25200, 54000, 111600, 262800" /* 3 days + 1 hour */),
+ "6, 11, 3600, 10800, 25200, 54000, 111600, 262800" /* 3 days + 1 hour */),
V(ClientBootstrapConsensusFallbackDownloadSchedule, CSV_INTERVAL,
"0, 1, 4, 11, 3600, 10800, 25200, 54000, 111600, 262800"),
/* When clients only have authorities available, they use this schedule: */
@@ -561,7 +561,7 @@ static config_var_t option_vars_[] = {
* blackholed. Clients will try 3 directories simultaneously.
* (Relays never use simultaneous connections.) */
V(ClientBootstrapConsensusMaxInProgressTries, UINT, "3"),
- V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "1200, 900, 900, 3600"),
V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"),
V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"),
V(TestingConsensusMaxDownloadTries, UINT, "8"),
diff --git a/src/or/confparse.c b/src/or/confparse.c
index ca54284dba..1706fa85e2 100644
--- a/src/or/confparse.c
+++ b/src/or/confparse.c
@@ -1224,6 +1224,8 @@ static struct unit_table_t memory_units[] = {
{ "gbits", 1<<27 },
{ "gbit", 1<<27 },
{ "tb", U64_LITERAL(1)<<40 },
+ { "tbyte", U64_LITERAL(1)<<40 },
+ { "tbytes", U64_LITERAL(1)<<40 },
{ "terabyte", U64_LITERAL(1)<<40 },
{ "terabytes", U64_LITERAL(1)<<40 },
{ "terabits", U64_LITERAL(1)<<37 },
diff --git a/src/or/directory.c b/src/or/directory.c
index 8c7953020d..65ddd7d583 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -3997,14 +3997,26 @@ next_random_exponential_delay(int delay, int max_delay)
/* How much are we willing to add to the delay? */
int max_increment;
+ int multiplier = 3; /* no more than quadruple the previous delay */
+ if (get_options()->TestingTorNetwork) {
+ /* Decrease the multiplier in testing networks. This reduces the variance,
+ * so that bootstrap is more reliable. */
+ multiplier = 2; /* no more than triple the previous delay */
+ }
- if (delay)
- max_increment = delay; /* no more than double. */
- else
- max_increment = 1; /* we're always willing to slow down a little. */
+ if (delay && delay < (INT_MAX-1) / multiplier) {
+ max_increment = delay * multiplier;
+ } else if (delay) {
+ max_increment = INT_MAX-1;
+ } else {
+ max_increment = 1;
+ }
+
+ if (BUG(max_increment < 1))
+ max_increment = 1;
- /* the + 1 here is so that we include the end of the interval */
- int increment = crypto_rand_int(max_increment+1);
+ /* the + 1 here is so that we always wait longer than last time. */
+ int increment = crypto_rand_int(max_increment)+1;
if (increment < max_delay - delay)
return delay + increment;
@@ -4048,7 +4060,7 @@ download_status_schedule_get_delay(download_status_t *dls,
delay = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1);
} else if (dls->backoff == DL_SCHED_RANDOM_EXPONENTIAL) {
/* Check if we missed a reset somehow */
- if (dls->last_backoff_position > dls_schedule_position) {
+ IF_BUG_ONCE(dls->last_backoff_position > dls_schedule_position) {
dls->last_backoff_position = 0;
dls->last_delay_used = 0;
}
@@ -4134,15 +4146,16 @@ time_t
download_status_increment_failure(download_status_t *dls, int status_code,
const char *item, int server, time_t now)
{
+ (void) status_code; // XXXX no longer used.
+ (void) server; // XXXX no longer used.
int increment = -1;
int min_delay = 0, max_delay = INT_MAX;
tor_assert(dls);
- /* only count the failure if it's permanent, or we're a server */
- if (status_code != 503 || server) {
- if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1)
- ++dls->n_download_failures;
+ /* count the failure */
+ if (dls->n_download_failures < IMPOSSIBLE_TO_DOWNLOAD-1) {
+ ++dls->n_download_failures;
}
if (dls->increment_on == DL_SCHED_INCREMENT_FAILURE) {
diff --git a/src/or/hs_common.c b/src/or/hs_common.c
index b7ee888842..7dd97e7c7c 100644
--- a/src/or/hs_common.c
+++ b/src/or/hs_common.c
@@ -135,7 +135,9 @@ compute_desc_id(rend_data_t *rend_data)
/* Allocate and initialize a rend_data_t object for a service using the
* provided arguments. All arguments are optional (can be NULL), except from
- * <b>onion_address</b> which MUST be set.
+ * <b>onion_address</b> which MUST be set. The <b>pk_digest</b> is the hash of
+ * the service private key. The <b>cookie</b> is the rendezvous cookie and
+ * <b>auth_type</b> is which authentiation this service is configured with.
*
* Return a valid rend_data_t pointer. This only returns a version 2 object of
* rend_data_t. */
@@ -163,10 +165,11 @@ rend_data_service_create(const char *onion_address, const char *pk_digest,
return rend_data;
}
-/* Allocate and initialize a rend_data_t object for a client request using
- * the given arguments. Either an onion address or a descriptor ID is
- * needed. Both can be given but only the onion address will be used to make
- * the descriptor fetch.
+/* Allocate and initialize a rend_data_t object for a client request using the
+ * given arguments. Either an onion address or a descriptor ID is needed. Both
+ * can be given but in this case only the onion address will be used to make
+ * the descriptor fetch. The <b>cookie</b> is the rendezvous cookie and
+ * <b>auth_type</b> is which authentiation the service is configured with.
*
* Return a valid rend_data_t pointer or NULL on error meaning the
* descriptor IDs couldn't be computed from the given data. */
diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c
index 96db936735..1517ccb12e 100644
--- a/src/or/hs_descriptor.c
+++ b/src/or/hs_descriptor.c
@@ -26,6 +26,7 @@
/* Constant string value for the encrypted part of the descriptor. */
#define str_create2_formats "create2-formats"
#define str_auth_required "authentication-required"
+#define str_single_onion "single-onion-service"
#define str_intro_point "introduction-point"
#define str_ip_auth_key "auth-key"
#define str_ip_enc_key "enc-key"
@@ -63,6 +64,7 @@ static token_rule_t hs_desc_v3_token_table[] = {
static token_rule_t hs_desc_encrypted_v3_token_table[] = {
T1_START(str_create2_formats, R3_CREATE2_FORMATS, CONCAT_ARGS, NO_OBJ),
T01(str_auth_required, R3_AUTHENTICATION_REQUIRED, ARGS, NO_OBJ),
+ T01(str_single_onion, R3_SINGLE_ONION_SERVICE, ARGS, NO_OBJ),
END_OF_TABLE
};
@@ -692,6 +694,10 @@ encode_encrypted_data(const hs_descriptor_t *desc,
smartlist_add_asprintf(lines, "%s %s\n", str_auth_required, buf);
tor_free(buf);
}
+
+ if (desc->encrypted_data.single_onion_service) {
+ smartlist_add_asprintf(lines, "%s\n", str_single_onion);
+ }
}
/* Build the introduction point(s) section. */
@@ -1613,6 +1619,13 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
goto err;
}
}
+
+ /* Is this service a single onion service? */
+ tok = find_opt_by_keyword(tokens, R3_SINGLE_ONION_SERVICE);
+ if (tok) {
+ desc_encrypted_out->single_onion_service = 1;
+ }
+
/* Initialize the descriptor's introduction point list before we start
* decoding. Having 0 intro point is valid. Then decode them all. */
desc_encrypted_out->intro_points = smartlist_new();
diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h
index 8bc725674e..895bed2485 100644
--- a/src/or/hs_descriptor.h
+++ b/src/or/hs_descriptor.h
@@ -128,6 +128,9 @@ typedef struct hs_desc_encrypted_data_t {
* in order to contact the service. Contains NULL terminated strings. */
smartlist_t *auth_types;
+ /* Is this descriptor a single onion service? */
+ unsigned int single_onion_service : 1;
+
/* A list of intro points. Contains hs_desc_intro_point_t objects. */
smartlist_t *intro_points;
} hs_desc_encrypted_data_t;
diff --git a/src/or/or.h b/src/or/or.h
index a43e2a33cd..eb94f63d5e 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2265,6 +2265,10 @@ typedef struct routerstatus_t {
* accept EXTEND2 cells */
unsigned int supports_extend2_cells:1;
+ /** True iff this router has a protocol list that allows it to negotiate
+ * ed25519 identity keys on a link handshake. */
+ unsigned int supports_ed25519_link_handshake:1;
+
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with
diff --git a/src/or/parsecommon.h b/src/or/parsecommon.h
index 3a86c52f3c..3019df63eb 100644
--- a/src/or/parsecommon.h
+++ b/src/or/parsecommon.h
@@ -158,6 +158,7 @@ typedef enum {
R3_SIGNATURE,
R3_CREATE2_FORMATS,
R3_AUTHENTICATION_REQUIRED,
+ R3_SINGLE_ONION_SERVICE,
R3_INTRODUCTION_POINT,
R3_INTRO_AUTH_KEY,
R3_INTRO_ENC_KEY,
diff --git a/src/or/policies.c b/src/or/policies.c
index 9e4e73dfea..f4c0cddbcc 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -281,28 +281,22 @@ parse_reachable_addresses(void)
/* We ignore ReachableAddresses for relays */
if (!server_mode(options)) {
- if ((reachable_or_addr_policy
- && policy_is_reject_star(reachable_or_addr_policy, AF_UNSPEC))
- || (reachable_dir_addr_policy
- && policy_is_reject_star(reachable_dir_addr_policy, AF_UNSPEC))) {
+ if (policy_is_reject_star(reachable_or_addr_policy, AF_UNSPEC, 0)
+ || policy_is_reject_star(reachable_dir_addr_policy, AF_UNSPEC,0)) {
log_warn(LD_CONFIG, "Tor cannot connect to the Internet if "
"ReachableAddresses, ReachableORAddresses, or "
"ReachableDirAddresses reject all addresses. Please accept "
"some addresses in these options.");
} else if (options->ClientUseIPv4 == 1
- && ((reachable_or_addr_policy
- && policy_is_reject_star(reachable_or_addr_policy, AF_INET))
- || (reachable_dir_addr_policy
- && policy_is_reject_star(reachable_dir_addr_policy, AF_INET)))) {
+ && (policy_is_reject_star(reachable_or_addr_policy, AF_INET, 0)
+ || policy_is_reject_star(reachable_dir_addr_policy, AF_INET, 0))) {
log_warn(LD_CONFIG, "You have set ClientUseIPv4 1, but "
"ReachableAddresses, ReachableORAddresses, or "
"ReachableDirAddresses reject all IPv4 addresses. "
"Tor will not connect using IPv4.");
} else if (fascist_firewall_use_ipv6(options)
- && ((reachable_or_addr_policy
- && policy_is_reject_star(reachable_or_addr_policy, AF_INET6))
- || (reachable_dir_addr_policy
- && policy_is_reject_star(reachable_dir_addr_policy, AF_INET6)))) {
+ && (policy_is_reject_star(reachable_or_addr_policy, AF_INET6, 0)
+ || policy_is_reject_star(reachable_dir_addr_policy, AF_INET6, 0))) {
log_warn(LD_CONFIG, "You have configured tor to use IPv6 "
"(ClientUseIPv6 1 or UseBridges 1), but "
"ReachableAddresses, ReachableORAddresses, or "
@@ -1091,8 +1085,8 @@ validate_addr_policies(const or_options_t *options, char **msg)
const int exitrelay_setting_is_auto = options->ExitRelay == -1;
const int policy_accepts_something =
- ! (policy_is_reject_star(addr_policy, AF_INET) &&
- policy_is_reject_star(addr_policy, AF_INET6));
+ ! (policy_is_reject_star(addr_policy, AF_INET, 1) &&
+ policy_is_reject_star(addr_policy, AF_INET6, 1));
if (server_mode(options) &&
! warned_about_exitrelay &&
@@ -2163,13 +2157,16 @@ exit_policy_is_general_exit(smartlist_t *policy)
}
/** Return false if <b>policy</b> might permit access to some addr:port;
- * otherwise if we are certain it rejects everything, return true. */
+ * otherwise if we are certain it rejects everything, return true. If no
+ * part of <b>policy</b> matches, return <b>default_reject</b>.
+ * NULL policies are allowed, and treated as empty. */
int
-policy_is_reject_star(const smartlist_t *policy, sa_family_t family)
+policy_is_reject_star(const smartlist_t *policy, sa_family_t family,
+ int default_reject)
{
- if (!policy) /*XXXX disallow NULL policies? */
- return 1;
- SMARTLIST_FOREACH_BEGIN(policy, addr_policy_t *, p) {
+ if (!policy)
+ return default_reject;
+ SMARTLIST_FOREACH_BEGIN(policy, const addr_policy_t *, p) {
if (p->policy_type == ADDR_POLICY_ACCEPT &&
(tor_addr_family(&p->addr) == family ||
tor_addr_family(&p->addr) == AF_UNSPEC)) {
@@ -2182,7 +2179,7 @@ policy_is_reject_star(const smartlist_t *policy, sa_family_t family)
return 1;
}
} SMARTLIST_FOREACH_END(p);
- return 1;
+ return default_reject;
}
/** Write a single address policy to the buf_len byte buffer at buf. Return
diff --git a/src/or/policies.h b/src/or/policies.h
index e134e686d2..20f58f2beb 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -100,7 +100,8 @@ void addr_policy_append_reject_addr_list(smartlist_t **dest,
const smartlist_t *addrs);
void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter);
int exit_policy_is_general_exit(smartlist_t *policy);
-int policy_is_reject_star(const smartlist_t *policy, sa_family_t family);
+int policy_is_reject_star(const smartlist_t *policy, sa_family_t family,
+ int reject_by_default);
char * policy_dump_to_string(const smartlist_t *policy_list,
int include_ipv4,
int include_ipv6);
diff --git a/src/or/protover.c b/src/or/protover.c
index 6c2da165f7..5972e61be7 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -293,7 +293,7 @@ protover_get_supported_protocols(void)
"HSIntro=3 "
"HSRend=1-2 "
"Link=1-4 "
- "LinkAuth=1 "
+ "LinkAuth=1,3 "
"Microdesc=1-2 "
"Relay=1-2";
}
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index b6bf63d829..0819d8a713 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -73,6 +73,10 @@ static ssize_t rend_service_parse_intro_for_v3(
size_t plaintext_len,
char **err_msg_out);
+static int rend_service_check_private_dir(const or_options_t *options,
+ const rend_service_t *s,
+ int create);
+
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
*/
@@ -472,6 +476,11 @@ rend_config_services(const or_options_t *options, int validate_only)
for (line = options->RendConfigLines; line; line = line->next) {
if (!strcasecmp(line->key, "HiddenServiceDir")) {
if (service) { /* register the one we just finished parsing */
+ if (rend_service_check_private_dir(options, service, 0) < 0) {
+ rend_service_free(service);
+ return -1;
+ }
+
if (validate_only)
rend_service_free(service);
else
@@ -687,12 +696,7 @@ rend_config_services(const or_options_t *options, int validate_only)
}
}
if (service) {
- cpd_check_t check_opts = CPD_CHECK_MODE_ONLY|CPD_CHECK;
- if (service->dir_group_readable) {
- check_opts |= CPD_GROUP_READ;
- }
-
- if (check_private_dir(service->directory, check_opts, options->User) < 0) {
+ if (rend_service_check_private_dir(options, service, 0) < 0) {
rend_service_free(service);
return -1;
}
@@ -1016,7 +1020,9 @@ service_is_single_onion_poisoned(const rend_service_t *service)
fstatus = file_status(poison_fname);
tor_free(poison_fname);
- /* If this fname is occupied, the hidden service has been poisoned. */
+ /* If this fname is occupied, the hidden service has been poisoned.
+ * fstatus can be FN_ERROR if the service directory does not exist, in that
+ * case, there is obviously no private key. */
if (fstatus == FN_FILE || fstatus == FN_EMPTY) {
return 1;
}
@@ -1032,7 +1038,9 @@ rend_service_private_key_exists(const rend_service_t *service)
char *private_key_path = rend_service_path(service, private_key_fname);
const file_status_t private_key_status = file_status(private_key_path);
tor_free(private_key_path);
- /* Only non-empty regular private key files could have been used before. */
+ /* Only non-empty regular private key files could have been used before.
+ * fstatus can be FN_ERROR if the service directory does not exist, in that
+ * case, there is obviously no private key. */
return private_key_status == FN_FILE;
}
@@ -1105,6 +1113,10 @@ poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
return -1;
}
+ /* Make sure the directory exists */
+ if (rend_service_check_private_dir(get_options(), service, 1) < 0)
+ return -1;
+
poison_fname = rend_service_sos_poison_path(service);
switch (file_status(poison_fname)) {
@@ -1260,6 +1272,37 @@ rend_service_derive_key_digests(struct rend_service_t *s)
return 0;
}
+/** Make sure that the directory for <b>s</b> is private, using the config in
+ * <b>options</b>.
+ * If <b>create</b> is true:
+ * - if the directory exists, change permissions if needed,
+ * - if the directory does not exist, create it with the correct permissions.
+ * If <b>create</b> is false:
+ * - if the directory exists, check permissions,
+ * - if the directory does not exist, check if we think we can create it.
+ * Return 0 on success, -1 on failure. */
+static int
+rend_service_check_private_dir(const or_options_t *options,
+ const rend_service_t *s,
+ int create)
+{
+ cpd_check_t check_opts = CPD_NONE;
+ if (create) {
+ check_opts |= CPD_CREATE;
+ } else {
+ check_opts |= CPD_CHECK_MODE_ONLY;
+ check_opts |= CPD_CHECK;
+ }
+ if (s->dir_group_readable) {
+ check_opts |= CPD_GROUP_READ;
+ }
+ /* Check/create directory */
+ if (check_private_dir(s->directory, check_opts, options->User) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
/** Load and/or generate private keys for the hidden service <b>s</b>,
* possibly including keys for client authorization. Return 0 on success, -1
* on failure. */
@@ -1268,24 +1311,9 @@ rend_service_load_keys(rend_service_t *s)
{
char *fname = NULL;
char buf[128];
- cpd_check_t check_opts = CPD_CREATE;
- if (s->dir_group_readable) {
- check_opts |= CPD_GROUP_READ;
- }
- /* Check/create directory */
- if (check_private_dir(s->directory, check_opts, get_options()->User) < 0) {
+ if (rend_service_check_private_dir(get_options(), s, 1) < 0)
goto err;
- }
-#ifndef _WIN32
- if (s->dir_group_readable) {
- /* Only new dirs created get new opts, also enforce group read. */
- if (chmod(s->directory, 0750)) {
- log_warn(LD_FS,"Unable to make %s group-readable.",
- rend_service_escaped_dir(s));
- }
- }
-#endif
/* Load key */
fname = rend_service_path(s, private_key_fname);
diff --git a/src/or/router.c b/src/or/router.c
index e45f233634..79caf42a2a 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2158,8 +2158,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
&ri->exit_policy);
}
ri->policy_is_reject_star =
- policy_is_reject_star(ri->exit_policy, AF_INET) &&
- policy_is_reject_star(ri->exit_policy, AF_INET6);
+ policy_is_reject_star(ri->exit_policy, AF_INET, 1) &&
+ policy_is_reject_star(ri->exit_policy, AF_INET6, 1);
if (options->IPv6Exit) {
char *p_tmp = policy_summarize(ri->exit_policy, AF_INET6);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 5bc2d39579..2cfd3fc58a 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -1924,7 +1924,7 @@ router_parse_entry_from_string(const char *s, const char *end,
}
}
- if (policy_is_reject_star(router->exit_policy, AF_INET) &&
+ if (policy_is_reject_star(router->exit_policy, AF_INET, 1) &&
(!router->ipv6_exit_policy ||
short_policy_is_reject_star(router->ipv6_exit_policy)))
router->policy_is_reject_star = 1;
@@ -2682,6 +2682,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->protocols_known = 1;
rs->supports_extend2_cells =
protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2);
+ rs->supports_ed25519_link_handshake =
+ protocol_list_supports_protocol(tok->args[0], PRT_LINKAUTH, 3);
}
if ((tok = find_opt_by_keyword(tokens, K_V))) {
tor_assert(tok->n_args == 1);
diff --git a/src/test/test.h b/src/test/test.h
index 15ccf5c379..49b4499594 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -73,6 +73,7 @@
{print_ = (I64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION)
const char *get_fname(const char *name);
+const char *get_fname_rnd(const char *name);
struct crypto_pk_t *pk_generate(int idx);
void init_pregenerated_keys(void);
void free_pregenerated_keys(void);
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 4281109812..6f83ceff00 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -3935,8 +3935,8 @@ test_dir_download_status_random_backoff(void *arg)
tt_int_op(increment, OP_GE, min_delay);
tt_int_op(increment, OP_LE, max_delay);
tt_int_op(increment, OP_GE, old_increment);
- /* We at most double, and maybe add one */
- tt_int_op(increment, OP_LE, 2 * old_increment + 1);
+ /* We at most quadruple, and maybe add one */
+ tt_int_op(increment, OP_LE, 4 * old_increment + 1);
/* Advance */
current_time += increment;
@@ -4041,14 +4041,14 @@ test_dir_download_status_increment(void *arg)
current_time + delay1 + 10,
0) == 0);
- /* Check that failure increments don't happen on 503 for clients, but that
- * attempt increments do. */
+ /* Check that failure increments do happen on 503 for clients, and
+ * attempt increments do too. */
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_failure, 503, "test", 0,
current_time);
- tt_assert(next_at == current_time + delay1);
- tt_assert(download_status_get_n_failures(&dls_failure) == 1);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 2);
+ tt_i64_op(next_at, ==, current_time + delay2);
+ tt_int_op(download_status_get_n_failures(&dls_failure), ==, 2);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), ==, 2);
tt_assert(mock_get_options_calls >= 1);
/* Check that failure increments do happen on 503 for servers */
@@ -4056,7 +4056,7 @@ test_dir_download_status_increment(void *arg)
next_at = download_status_increment_failure(&dls_failure, 503, "test", 1,
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_failure) == 2);
+ tt_assert(download_status_get_n_failures(&dls_failure) == 3);
tt_assert(download_status_get_n_attempts(&dls_failure) == 3);
tt_assert(mock_get_options_calls >= 1);
@@ -4065,7 +4065,7 @@ test_dir_download_status_increment(void *arg)
next_at = download_status_increment_failure(&dls_failure, 404, "test", 0,
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_failure) == 3);
+ tt_assert(download_status_get_n_failures(&dls_failure) == 4);
tt_assert(download_status_get_n_attempts(&dls_failure) == 4);
tt_assert(mock_get_options_calls >= 1);
@@ -4227,8 +4227,13 @@ test_dir_download_status_increment(void *arg)
/* Check that attempt increments don't happen on failure-based schedules,
* and that the attempt is set at the end of time */
mock_get_options_calls = 0;
+ setup_full_capture_of_logs(LOG_WARN);
next_at = download_status_increment_attempt(&dls_failure, "test",
current_time);
+ expect_single_log_msg_containing(
+ "Tried to launch an attempt-based connection on a failure-based "
+ "schedule.");
+ teardown_capture_of_logs();
tt_assert(next_at == TIME_MAX);
tt_assert(download_status_get_n_failures(&dls_failure) == 0);
tt_assert(download_status_get_n_attempts(&dls_failure) == 0);
@@ -4240,6 +4245,7 @@ test_dir_download_status_increment(void *arg)
UNMOCK(get_options);
mock_options = NULL;
mock_get_options_calls = 0;
+ teardown_capture_of_logs();
}
static void
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index 67ce1cfaed..318c549762 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -527,6 +527,11 @@ mock_get_options(void)
return mock_options;
}
+/* arg can't be 0 (the test fails) or 2 (the test is skipped) */
+#define CREATE_HS_DIR_NONE ((intptr_t)0x04)
+#define CREATE_HS_DIR1 ((intptr_t)0x08)
+#define CREATE_HS_DIR2 ((intptr_t)0x10)
+
/* Test that single onion poisoning works. */
static void
test_single_onion_poisoning(void *arg)
@@ -537,15 +542,15 @@ test_single_onion_poisoning(void *arg)
MOCK(get_options, mock_get_options);
int ret = -1;
- mock_options->DataDirectory = tor_strdup(get_fname("test_data_dir"));
+ intptr_t create_dir_mask = (intptr_t)arg;
+ /* Get directories with a random suffix so we can repeat the tests */
+ mock_options->DataDirectory = tor_strdup(get_fname_rnd("test_data_dir"));
rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t));
- char *dir1 = tor_strdup(get_fname("test_hs_dir1"));
+ char *dir1 = tor_strdup(get_fname_rnd("test_hs_dir1"));
rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t));
- char *dir2 = tor_strdup(get_fname("test_hs_dir2"));
+ char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2"));
smartlist_t *services = smartlist_new();
- (void) arg;
-
/* No services, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
@@ -558,22 +563,20 @@ test_single_onion_poisoning(void *arg)
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
tt_assert(ret == 0);
- /* Create directories for both services */
-
-#ifdef _WIN32
- ret = mkdir(mock_options->DataDirectory);
- tt_assert(ret == 0);
- ret = mkdir(dir1);
- tt_assert(ret == 0);
- ret = mkdir(dir2);
-#else
- ret = mkdir(mock_options->DataDirectory, 0700);
- tt_assert(ret == 0);
- ret = mkdir(dir1, 0700);
- tt_assert(ret == 0);
- ret = mkdir(dir2, 0700);
-#endif
+ /* Create the data directory, and, if the correct bit in arg is set,
+ * create a directory for that service.
+ * The data directory is required for the lockfile, which is used when
+ * loading keys. */
+ ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL);
tt_assert(ret == 0);
+ if (create_dir_mask & CREATE_HS_DIR1) {
+ ret = check_private_dir(dir1, CPD_CREATE, NULL);
+ tt_assert(ret == 0);
+ }
+ if (create_dir_mask & CREATE_HS_DIR2) {
+ ret = check_private_dir(dir2, CPD_CREATE, NULL);
+ tt_assert(ret == 0);
+ }
service_1->directory = dir1;
service_2->directory = dir2;
@@ -703,7 +706,7 @@ test_single_onion_poisoning(void *arg)
tt_assert(ret < 0);
done:
- /* TODO: should we delete the directories here? */
+ /* The test harness deletes the directories at exit */
rend_service_free(service_1);
rend_service_free(service_2);
smartlist_free(services);
@@ -725,8 +728,14 @@ struct testcase_t hs_tests[] = {
NULL, NULL },
{ "hs_auth_cookies", test_hs_auth_cookies, TT_FORK,
NULL, NULL },
- { "single_onion_poisoning", test_single_onion_poisoning, TT_FORK,
- NULL, NULL },
+ { "single_onion_poisoning_create_dir_none", test_single_onion_poisoning,
+ TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR_NONE) },
+ { "single_onion_poisoning_create_dir1", test_single_onion_poisoning,
+ TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1) },
+ { "single_onion_poisoning_create_dir2", test_single_onion_poisoning,
+ TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) },
+ { "single_onion_poisoning_create_dir_both", test_single_onion_poisoning,
+ TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index ea8740bfc8..8af5cabca3 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -102,6 +102,7 @@ helper_build_hs_desc(unsigned int no_ip)
/* Setup encrypted data section. */
desc->encrypted_data.create2_ntor = 1;
desc->encrypted_data.auth_types = smartlist_new();
+ desc->encrypted_data.single_onion_service = 1;
smartlist_add(desc->encrypted_data.auth_types, tor_strdup("ed25519"));
desc->encrypted_data.intro_points = smartlist_new();
if (!no_ip) {
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index b89de01b7b..4df40f618e 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -258,14 +258,16 @@ test_policies_general(void *arg)
tt_assert(!cmp_addr_policies(policy2, policy2));
tt_assert(!cmp_addr_policies(NULL, NULL));
- tt_assert(!policy_is_reject_star(policy2, AF_INET));
- tt_assert(policy_is_reject_star(policy, AF_INET));
- tt_assert(policy_is_reject_star(policy10, AF_INET));
- tt_assert(!policy_is_reject_star(policy10, AF_INET6));
- tt_assert(policy_is_reject_star(policy11, AF_INET));
- tt_assert(policy_is_reject_star(policy11, AF_INET6));
- tt_assert(policy_is_reject_star(NULL, AF_INET));
- tt_assert(policy_is_reject_star(NULL, AF_INET6));
+ tt_assert(!policy_is_reject_star(policy2, AF_INET, 1));
+ tt_assert(policy_is_reject_star(policy, AF_INET, 1));
+ tt_assert(policy_is_reject_star(policy10, AF_INET, 1));
+ tt_assert(!policy_is_reject_star(policy10, AF_INET6, 1));
+ tt_assert(policy_is_reject_star(policy11, AF_INET, 1));
+ tt_assert(policy_is_reject_star(policy11, AF_INET6, 1));
+ tt_assert(policy_is_reject_star(NULL, AF_INET, 1));
+ tt_assert(policy_is_reject_star(NULL, AF_INET6, 1));
+ tt_assert(!policy_is_reject_star(NULL, AF_INET, 0));
+ tt_assert(!policy_is_reject_star(NULL, AF_INET6, 0));
addr_policy_list_free(policy);
policy = NULL;
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index deb11d0112..caeae13a38 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -102,18 +102,41 @@ setup_directory(void)
temp_dir_setup_in_pid = getpid();
}
-/** Return a filename relative to our testing temporary directory */
-const char *
-get_fname(const char *name)
+/** Return a filename relative to our testing temporary directory, based on
+ * name and suffix. If name is NULL, return the name of the testing temporary
+ * directory. */
+static const char *
+get_fname_suffix(const char *name, const char *suffix)
{
static char buf[1024];
setup_directory();
if (!name)
return temp_dir;
- tor_snprintf(buf,sizeof(buf),"%s/%s",temp_dir,name);
+ tor_snprintf(buf,sizeof(buf),"%s/%s%s%s",temp_dir,name,suffix ? "_" : "",
+ suffix ? suffix : "");
return buf;
}
+/** Return a filename relative to our testing temporary directory. If name is
+ * NULL, return the name of the testing temporary directory. */
+const char *
+get_fname(const char *name)
+{
+ return get_fname_suffix(name, NULL);
+}
+
+/** Return a filename with a random suffix, relative to our testing temporary
+ * directory. If name is NULL, return the name of the testing temporary
+ * directory, without any suffix. */
+const char *
+get_fname_rnd(const char *name)
+{
+ char rnd[256], rnd32[256];
+ crypto_rand(rnd, RAND_PATH_BYTES);
+ base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
+ return get_fname_suffix(name, rnd32);
+}
+
/* Remove a directory and all of its subdirectories */
static void
rm_rf(const char *dir)
@@ -158,6 +181,9 @@ remove_directory(void)
static void *
passthrough_test_setup(const struct testcase_t *testcase)
{
+ /* Make sure the passthrough doesn't unintentionally fail or skip tests */
+ tor_assert(testcase->setup_data);
+ tor_assert(testcase->setup_data != (void*)TT_SKIP);
return testcase->setup_data;
}
static int