mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
Merge remote-tracking branch 'tor-github/pr/1718/head' into maint-0.4.2
This commit is contained in:
commit
b504942331
5
changes/ticket33029
Normal file
5
changes/ticket33029
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
o Major bugfixes (directory authority):
|
||||||
|
- Directory authorities will now send a 503 (not enough bandwidth) code to
|
||||||
|
clients when under bandwidth pressure. Known relays and other authorities
|
||||||
|
will always be answered regardless of the bandwidth situation. Fixes bug
|
||||||
|
33029; bugfix on 0.1.2.5-alpha.
|
@ -2925,6 +2925,13 @@ on the public Tor network.
|
|||||||
before it will treat advertised bandwidths as wholly
|
before it will treat advertised bandwidths as wholly
|
||||||
unreliable. (Default: 500)
|
unreliable. (Default: 500)
|
||||||
|
|
||||||
|
[[AuthDirRejectRequestsUnderLoad]] **AuthDirRejectRequestsUnderLoad** **0**|**1**::
|
||||||
|
If set, the directory authority will start rejecting directory requests
|
||||||
|
from non relay connections by sending a 503 error code if it is under
|
||||||
|
bandwidth pressure (reaching the configured limit if any). Relays will
|
||||||
|
always tried to be answered even if this is on. (Default: 1)
|
||||||
|
|
||||||
|
|
||||||
HIDDEN SERVICE OPTIONS
|
HIDDEN SERVICE OPTIONS
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
@ -671,6 +671,7 @@ static const config_var_t option_vars_[] = {
|
|||||||
OBSOLETE("UseNTorHandshake"),
|
OBSOLETE("UseNTorHandshake"),
|
||||||
V(User, STRING, NULL),
|
V(User, STRING, NULL),
|
||||||
OBSOLETE("UserspaceIOCPBuffers"),
|
OBSOLETE("UserspaceIOCPBuffers"),
|
||||||
|
V(AuthDirRejectRequestsUnderLoad, BOOL, "1"),
|
||||||
V(AuthDirSharedRandomness, BOOL, "1"),
|
V(AuthDirSharedRandomness, BOOL, "1"),
|
||||||
V(AuthDirTestEd25519LinkKeys, BOOL, "1"),
|
V(AuthDirTestEd25519LinkKeys, BOOL, "1"),
|
||||||
OBSOLETE("V1AuthoritativeDirectory"),
|
OBSOLETE("V1AuthoritativeDirectory"),
|
||||||
|
@ -1008,6 +1008,13 @@ struct or_options_t {
|
|||||||
*/
|
*/
|
||||||
uint64_t MaxUnparseableDescSizeToLog;
|
uint64_t MaxUnparseableDescSizeToLog;
|
||||||
|
|
||||||
|
/** Bool (default: 1): Under bandwidth pressure, if set to 1, the authority
|
||||||
|
* will always answer directory requests from relays but will start sending
|
||||||
|
* 503 error code for the other connections. If set to 0, all connections
|
||||||
|
* are considered the same and the authority will try to answer them all
|
||||||
|
* regardless of bandwidth pressure or not. */
|
||||||
|
int AuthDirRejectRequestsUnderLoad;
|
||||||
|
|
||||||
/** Bool (default: 1): Switch for the shared random protocol. Only
|
/** Bool (default: 1): Switch for the shared random protocol. Only
|
||||||
* relevant to a directory authority. If off, the authority won't
|
* relevant to a directory authority. If off, the authority won't
|
||||||
* participate in the protocol. If on (default), a flag is added to the
|
* participate in the protocol. If on (default), a flag is added to the
|
||||||
|
@ -3051,7 +3051,7 @@ connection_mark_all_noncontrol_connections(void)
|
|||||||
* uses pluggable transports, since we should then limit it even if it
|
* uses pluggable transports, since we should then limit it even if it
|
||||||
* comes from an internal IP address. */
|
* comes from an internal IP address. */
|
||||||
static int
|
static int
|
||||||
connection_is_rate_limited(connection_t *conn)
|
connection_is_rate_limited(const connection_t *conn)
|
||||||
{
|
{
|
||||||
const or_options_t *options = get_options();
|
const or_options_t *options = get_options();
|
||||||
if (conn->linked)
|
if (conn->linked)
|
||||||
@ -3186,14 +3186,14 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
|
|||||||
global_bucket_val, conn_bucket);
|
global_bucket_val, conn_bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return 1 if the global write buckets are low enough that we
|
/** Return true iff the global write buckets are low enough that we
|
||||||
* shouldn't send <b>attempt</b> bytes of low-priority directory stuff
|
* shouldn't send <b>attempt</b> bytes of low-priority directory stuff
|
||||||
* out to <b>conn</b>. Else return 0.
|
* out to <b>conn</b>.
|
||||||
|
|
||||||
* Priority was 1 for v1 requests (directories and running-routers),
|
|
||||||
* and 2 for v2 requests and later (statuses and descriptors).
|
|
||||||
*
|
*
|
||||||
* There are a lot of parameters we could use here:
|
* If we are a directory authority, always answer dir requests thus true is
|
||||||
|
* always returned.
|
||||||
|
*
|
||||||
|
* Note: There are a lot of parameters we could use here:
|
||||||
* - global_relayed_write_bucket. Low is bad.
|
* - global_relayed_write_bucket. Low is bad.
|
||||||
* - global_write_bucket. Low is bad.
|
* - global_write_bucket. Low is bad.
|
||||||
* - bandwidthrate. Low is bad.
|
* - bandwidthrate. Low is bad.
|
||||||
@ -3205,39 +3205,40 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
|
|||||||
* mean is "total directory bytes added to outbufs recently", but
|
* mean is "total directory bytes added to outbufs recently", but
|
||||||
* that's harder to quantify and harder to keep track of.
|
* that's harder to quantify and harder to keep track of.
|
||||||
*/
|
*/
|
||||||
int
|
bool
|
||||||
global_write_bucket_low(connection_t *conn, size_t attempt, int priority)
|
connection_dir_is_global_write_low(const connection_t *conn, size_t attempt)
|
||||||
{
|
{
|
||||||
size_t smaller_bucket =
|
size_t smaller_bucket =
|
||||||
MIN(token_bucket_rw_get_write(&global_bucket),
|
MIN(token_bucket_rw_get_write(&global_bucket),
|
||||||
token_bucket_rw_get_write(&global_relayed_bucket));
|
token_bucket_rw_get_write(&global_relayed_bucket));
|
||||||
if (authdir_mode(get_options()) && priority>1)
|
|
||||||
return 0; /* there's always room to answer v2 if we're an auth dir */
|
/* Special case for authorities (directory only). */
|
||||||
|
if (authdir_mode_v3(get_options())) {
|
||||||
|
/* Are we configured to possibly reject requests under load? */
|
||||||
|
if (!get_options()->AuthDirRejectRequestsUnderLoad) {
|
||||||
|
/* Answer request no matter what. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Always answer requests from a known relay which includes the other
|
||||||
|
* authorities. The following looks up the addresses for relays that we
|
||||||
|
* have their descriptor _and_ any configured trusted directories. */
|
||||||
|
if (nodelist_probably_contains_address(&conn->addr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!connection_is_rate_limited(conn))
|
if (!connection_is_rate_limited(conn))
|
||||||
return 0; /* local conns don't get limited */
|
return false; /* local conns don't get limited */
|
||||||
|
|
||||||
if (smaller_bucket < attempt)
|
if (smaller_bucket < attempt)
|
||||||
return 1; /* not enough space no matter the priority */
|
return true; /* not enough space. */
|
||||||
|
|
||||||
{
|
{
|
||||||
const time_t diff = approx_time() - write_buckets_last_empty_at;
|
const time_t diff = approx_time() - write_buckets_last_empty_at;
|
||||||
if (diff <= 1)
|
if (diff <= 1)
|
||||||
return 1; /* we're already hitting our limits, no more please */
|
return true; /* we're already hitting our limits, no more please */
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if (priority == 1) { /* old-style v1 query */
|
|
||||||
/* Could we handle *two* of these requests within the next two seconds? */
|
|
||||||
const or_options_t *options = get_options();
|
|
||||||
size_t can_write = (size_t) (smaller_bucket
|
|
||||||
+ 2*(options->RelayBandwidthRate ? options->RelayBandwidthRate :
|
|
||||||
options->BandwidthRate));
|
|
||||||
if (can_write < 2*attempt)
|
|
||||||
return 1;
|
|
||||||
} else { /* v2 query */
|
|
||||||
/* no further constraints yet */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** When did we last tell the accounting subsystem about transmitted
|
/** When did we last tell the accounting subsystem about transmitted
|
||||||
|
@ -195,8 +195,9 @@ int retry_all_listeners(smartlist_t *new_conns,
|
|||||||
void connection_mark_all_noncontrol_listeners(void);
|
void connection_mark_all_noncontrol_listeners(void);
|
||||||
void connection_mark_all_noncontrol_connections(void);
|
void connection_mark_all_noncontrol_connections(void);
|
||||||
|
|
||||||
ssize_t connection_bucket_write_limit(connection_t *conn, time_t now);
|
ssize_t connection_bucket_write_limit(struct connection_t *conn, time_t now);
|
||||||
int global_write_bucket_low(connection_t *conn, size_t attempt, int priority);
|
bool connection_dir_is_global_write_low(const struct connection_t *conn,
|
||||||
|
size_t attempt);
|
||||||
void connection_bucket_init(void);
|
void connection_bucket_init(void);
|
||||||
void connection_bucket_adjust(const or_options_t *options);
|
void connection_bucket_adjust(const or_options_t *options);
|
||||||
void connection_bucket_refill_all(time_t now,
|
void connection_bucket_refill_all(time_t now,
|
||||||
|
@ -951,7 +951,7 @@ handle_get_current_consensus(dir_connection_t *conn,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global_write_bucket_low(TO_CONN(conn), size_guess, 2)) {
|
if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
|
||||||
log_debug(LD_DIRSERV,
|
log_debug(LD_DIRSERV,
|
||||||
"Client asked for network status lists, but we've been "
|
"Client asked for network status lists, but we've been "
|
||||||
"writing too many bytes lately. Sending 503 Dir busy.");
|
"writing too many bytes lately. Sending 503 Dir busy.");
|
||||||
@ -1060,7 +1060,7 @@ handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (global_write_bucket_low(TO_CONN(conn), estimated_len, 2)) {
|
if (connection_dir_is_global_write_low(TO_CONN(conn), estimated_len)) {
|
||||||
write_short_http_response(conn, 503, "Directory busy, try again later");
|
write_short_http_response(conn, 503, "Directory busy, try again later");
|
||||||
goto vote_done;
|
goto vote_done;
|
||||||
}
|
}
|
||||||
@ -1119,7 +1119,7 @@ handle_get_microdesc(dir_connection_t *conn, const get_handler_args_t *args)
|
|||||||
write_short_http_response(conn, 404, "Not found");
|
write_short_http_response(conn, 404, "Not found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (global_write_bucket_low(TO_CONN(conn), size_guess, 2)) {
|
if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
|
||||||
log_info(LD_DIRSERV,
|
log_info(LD_DIRSERV,
|
||||||
"Client asked for server descriptors, but we've been "
|
"Client asked for server descriptors, but we've been "
|
||||||
"writing too many bytes lately. Sending 503 Dir busy.");
|
"writing too many bytes lately. Sending 503 Dir busy.");
|
||||||
@ -1217,7 +1217,7 @@ handle_get_descriptor(dir_connection_t *conn, const get_handler_args_t *args)
|
|||||||
msg = "Not found";
|
msg = "Not found";
|
||||||
write_short_http_response(conn, 404, msg);
|
write_short_http_response(conn, 404, msg);
|
||||||
} else {
|
} else {
|
||||||
if (global_write_bucket_low(TO_CONN(conn), size_guess, 2)) {
|
if (connection_dir_is_global_write_low(TO_CONN(conn), size_guess)) {
|
||||||
log_info(LD_DIRSERV,
|
log_info(LD_DIRSERV,
|
||||||
"Client asked for server descriptors, but we've been "
|
"Client asked for server descriptors, but we've been "
|
||||||
"writing too many bytes lately. Sending 503 Dir busy.");
|
"writing too many bytes lately. Sending 503 Dir busy.");
|
||||||
@ -1313,9 +1313,8 @@ handle_get_keys(dir_connection_t *conn, const get_handler_args_t *args)
|
|||||||
SMARTLIST_FOREACH(certs, authority_cert_t *, c,
|
SMARTLIST_FOREACH(certs, authority_cert_t *, c,
|
||||||
len += c->cache_info.signed_descriptor_len);
|
len += c->cache_info.signed_descriptor_len);
|
||||||
|
|
||||||
if (global_write_bucket_low(TO_CONN(conn),
|
if (connection_dir_is_global_write_low(TO_CONN(conn),
|
||||||
compress_method != NO_METHOD ? len/2 : len,
|
compress_method != NO_METHOD ? len/2 : len)) {
|
||||||
2)) {
|
|
||||||
write_short_http_response(conn, 503, "Directory busy, try again later");
|
write_short_http_response(conn, 503, "Directory busy, try again later");
|
||||||
goto keys_done;
|
goto keys_done;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,37 @@ static smartlist_t *trusted_dir_servers = NULL;
|
|||||||
* and all fallback directory servers. */
|
* and all fallback directory servers. */
|
||||||
static smartlist_t *fallback_dir_servers = NULL;
|
static smartlist_t *fallback_dir_servers = NULL;
|
||||||
|
|
||||||
|
/** Helper: From a given trusted directory entry, add the v4 or/and v6 address
|
||||||
|
* to the nodelist address set. */
|
||||||
|
static void
|
||||||
|
add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir)
|
||||||
|
{
|
||||||
|
tor_assert(dir);
|
||||||
|
tor_assert(dir->is_authority);
|
||||||
|
|
||||||
|
/* Add IPv4 and then IPv6 if applicable. */
|
||||||
|
nodelist_add_addr4_to_address_set(dir->addr);
|
||||||
|
if (!tor_addr_is_null(&dir->ipv6_addr)) {
|
||||||
|
nodelist_add_addr6_to_address_set(&dir->ipv6_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Go over the trusted directory server list and add their address(es) to the
|
||||||
|
* nodelist address set. This is called everytime a new consensus is set. */
|
||||||
|
MOCK_IMPL(void,
|
||||||
|
dirlist_add_trusted_dir_addresses, (void))
|
||||||
|
{
|
||||||
|
if (!trusted_dir_servers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, const dir_server_t *, ent) {
|
||||||
|
if (ent->is_authority) {
|
||||||
|
add_trusted_dir_to_nodelist_addr_set(ent);
|
||||||
|
}
|
||||||
|
} SMARTLIST_FOREACH_END(ent);
|
||||||
|
}
|
||||||
|
|
||||||
/** Return the number of directory authorities whose type matches some bit set
|
/** Return the number of directory authorities whose type matches some bit set
|
||||||
* in <b>type</b> */
|
* in <b>type</b> */
|
||||||
int
|
int
|
||||||
|
@ -44,4 +44,6 @@ void dir_server_add(dir_server_t *ent);
|
|||||||
void clear_dir_servers(void);
|
void clear_dir_servers(void);
|
||||||
void dirlist_free_all(void);
|
void dirlist_free_all(void);
|
||||||
|
|
||||||
|
MOCK_DECL(void, dirlist_add_trusted_dir_addresses, (void));
|
||||||
|
|
||||||
#endif /* !defined(TOR_DIRLIST_H) */
|
#endif /* !defined(TOR_DIRLIST_H) */
|
||||||
|
@ -455,22 +455,43 @@ node_add_to_address_set(const node_t *node)
|
|||||||
|
|
||||||
if (node->rs) {
|
if (node->rs) {
|
||||||
if (node->rs->addr)
|
if (node->rs->addr)
|
||||||
address_set_add_ipv4h(the_nodelist->node_addrs, node->rs->addr);
|
nodelist_add_addr4_to_address_set(node->rs->addr);
|
||||||
if (!tor_addr_is_null(&node->rs->ipv6_addr))
|
if (!tor_addr_is_null(&node->rs->ipv6_addr))
|
||||||
address_set_add(the_nodelist->node_addrs, &node->rs->ipv6_addr);
|
nodelist_add_addr6_to_address_set(&node->rs->ipv6_addr);
|
||||||
}
|
}
|
||||||
if (node->ri) {
|
if (node->ri) {
|
||||||
if (node->ri->addr)
|
if (node->ri->addr)
|
||||||
address_set_add_ipv4h(the_nodelist->node_addrs, node->ri->addr);
|
nodelist_add_addr4_to_address_set(node->ri->addr);
|
||||||
if (!tor_addr_is_null(&node->ri->ipv6_addr))
|
if (!tor_addr_is_null(&node->ri->ipv6_addr))
|
||||||
address_set_add(the_nodelist->node_addrs, &node->ri->ipv6_addr);
|
nodelist_add_addr6_to_address_set(&node->ri->ipv6_addr);
|
||||||
}
|
}
|
||||||
if (node->md) {
|
if (node->md) {
|
||||||
if (!tor_addr_is_null(&node->md->ipv6_addr))
|
if (!tor_addr_is_null(&node->md->ipv6_addr))
|
||||||
address_set_add(the_nodelist->node_addrs, &node->md->ipv6_addr);
|
nodelist_add_addr6_to_address_set(&node->md->ipv6_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add the given v4 address into the nodelist address set. */
|
||||||
|
void
|
||||||
|
nodelist_add_addr4_to_address_set(const uint32_t addr)
|
||||||
|
{
|
||||||
|
if (!the_nodelist || !the_nodelist->node_addrs || addr == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
address_set_add_ipv4h(the_nodelist->node_addrs, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add the given v6 address into the nodelist address set. */
|
||||||
|
void
|
||||||
|
nodelist_add_addr6_to_address_set(const tor_addr_t *addr)
|
||||||
|
{
|
||||||
|
if (BUG(!addr) || tor_addr_is_null(addr) || tor_addr_is_v4(addr) ||
|
||||||
|
!the_nodelist || !the_nodelist->node_addrs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
address_set_add(the_nodelist->node_addrs, addr);
|
||||||
|
}
|
||||||
|
|
||||||
/** Return true if <b>addr</b> is the address of some node in the nodelist.
|
/** Return true if <b>addr</b> is the address of some node in the nodelist.
|
||||||
* If not, probably return false. */
|
* If not, probably return false. */
|
||||||
int
|
int
|
||||||
@ -612,9 +633,12 @@ nodelist_set_consensus(networkstatus_t *ns)
|
|||||||
SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
|
SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
|
||||||
node->rs = NULL);
|
node->rs = NULL);
|
||||||
|
|
||||||
/* Conservatively estimate that every node will have 2 addresses. */
|
/* Conservatively estimate that every node will have 2 addresses (v4 and
|
||||||
const int estimated_addresses = smartlist_len(ns->routerstatus_list) *
|
* v6). Then we add the number of configured trusted authorities we have. */
|
||||||
get_estimated_address_per_node();
|
int estimated_addresses = smartlist_len(ns->routerstatus_list) *
|
||||||
|
get_estimated_address_per_node();
|
||||||
|
estimated_addresses += (get_n_authorities(V3_DIRINFO & BRIDGE_DIRINFO) *
|
||||||
|
get_estimated_address_per_node());
|
||||||
address_set_free(the_nodelist->node_addrs);
|
address_set_free(the_nodelist->node_addrs);
|
||||||
the_nodelist->node_addrs = address_set_new(estimated_addresses);
|
the_nodelist->node_addrs = address_set_new(estimated_addresses);
|
||||||
|
|
||||||
@ -665,6 +689,9 @@ nodelist_set_consensus(networkstatus_t *ns)
|
|||||||
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
||||||
node_add_to_address_set(node);
|
node_add_to_address_set(node);
|
||||||
} SMARTLIST_FOREACH_END(node);
|
} SMARTLIST_FOREACH_END(node);
|
||||||
|
/* Then, add all trusted configured directories. Some might not be in the
|
||||||
|
* consensus so make sure we know them. */
|
||||||
|
dirlist_add_trusted_dir_addresses();
|
||||||
|
|
||||||
if (! authdir) {
|
if (! authdir) {
|
||||||
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
||||||
|
@ -35,6 +35,8 @@ node_t *nodelist_add_microdesc(microdesc_t *md);
|
|||||||
void nodelist_set_consensus(networkstatus_t *ns);
|
void nodelist_set_consensus(networkstatus_t *ns);
|
||||||
void nodelist_ensure_freshness(networkstatus_t *ns);
|
void nodelist_ensure_freshness(networkstatus_t *ns);
|
||||||
int nodelist_probably_contains_address(const tor_addr_t *addr);
|
int nodelist_probably_contains_address(const tor_addr_t *addr);
|
||||||
|
void nodelist_add_addr4_to_address_set(const uint32_t addr);
|
||||||
|
void nodelist_add_addr6_to_address_set(const tor_addr_t *addr);
|
||||||
|
|
||||||
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
|
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
|
||||||
void nodelist_remove_routerinfo(routerinfo_t *ri);
|
void nodelist_remove_routerinfo(routerinfo_t *ri);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "core/or/or.h"
|
#include "core/or/or.h"
|
||||||
#include "lib/crypt_ops/crypto_rand.h"
|
#include "lib/crypt_ops/crypto_rand.h"
|
||||||
#include "core/or/address_set.h"
|
#include "core/or/address_set.h"
|
||||||
|
#include "feature/nodelist/dirlist.h"
|
||||||
#include "feature/nodelist/microdesc.h"
|
#include "feature/nodelist/microdesc.h"
|
||||||
#include "feature/nodelist/networkstatus.h"
|
#include "feature/nodelist/networkstatus.h"
|
||||||
#include "feature/nodelist/nodelist.h"
|
#include "feature/nodelist/nodelist.h"
|
||||||
@ -31,6 +32,12 @@ mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
|
|||||||
return dummy_ns;
|
return dummy_ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mock_dirlist_add_trusted_dir_addresses(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Number of address a single node_t can have. Default to the production
|
/* Number of address a single node_t can have. Default to the production
|
||||||
* value. This is to control the size of the bloom filter. */
|
* value. This is to control the size of the bloom filter. */
|
||||||
static int addr_per_node = 2;
|
static int addr_per_node = 2;
|
||||||
@ -98,6 +105,8 @@ test_nodelist(void *arg)
|
|||||||
mock_networkstatus_get_latest_consensus_by_flavor);
|
mock_networkstatus_get_latest_consensus_by_flavor);
|
||||||
MOCK(get_estimated_address_per_node,
|
MOCK(get_estimated_address_per_node,
|
||||||
mock_get_estimated_address_per_node);
|
mock_get_estimated_address_per_node);
|
||||||
|
MOCK(dirlist_add_trusted_dir_addresses,
|
||||||
|
mock_dirlist_add_trusted_dir_addresses);
|
||||||
|
|
||||||
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
|
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
|
||||||
dummy_ns->flavor = FLAV_MICRODESC;
|
dummy_ns->flavor = FLAV_MICRODESC;
|
||||||
@ -113,7 +122,10 @@ test_nodelist(void *arg)
|
|||||||
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
|
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
|
||||||
addr_per_node = 1024;
|
addr_per_node = 1024;
|
||||||
|
|
||||||
/* No node no nothing. The lookups should be empty. */
|
/* No node no nothing. The lookups should be empty. We've mocked the
|
||||||
|
* dirlist_add_trusted_dir_addresses in order for _no_ authorities to be
|
||||||
|
* added to the filter else it makes this test to trigger many false
|
||||||
|
* positive. */
|
||||||
nodelist_set_consensus(dummy_ns);
|
nodelist_set_consensus(dummy_ns);
|
||||||
|
|
||||||
/* The address set should be empty. */
|
/* The address set should be empty. */
|
||||||
@ -167,6 +179,7 @@ test_nodelist(void *arg)
|
|||||||
UNMOCK(networkstatus_get_latest_consensus);
|
UNMOCK(networkstatus_get_latest_consensus);
|
||||||
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
|
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
|
||||||
UNMOCK(get_estimated_address_per_node);
|
UNMOCK(get_estimated_address_per_node);
|
||||||
|
UNMOCK(dirlist_add_trusted_dir_addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct testcase_t address_set_tests[] = {
|
struct testcase_t address_set_tests[] = {
|
||||||
|
@ -6,18 +6,67 @@
|
|||||||
* \brief tests for bandwidth management / token bucket functions
|
* \brief tests for bandwidth management / token bucket functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CONFIG_PRIVATE
|
||||||
|
#define CONNECTION_PRIVATE
|
||||||
#define TOKEN_BUCKET_PRIVATE
|
#define TOKEN_BUCKET_PRIVATE
|
||||||
|
|
||||||
#include "core/or/or.h"
|
#include "core/or/or.h"
|
||||||
#include "test/test.h"
|
|
||||||
|
|
||||||
|
#include "app/config/config.h"
|
||||||
|
#include "core/mainloop/connection.h"
|
||||||
|
#include "feature/dircommon/directory.h"
|
||||||
|
#include "feature/nodelist/microdesc.h"
|
||||||
|
#include "feature/nodelist/networkstatus.h"
|
||||||
|
#include "feature/nodelist/nodelist.h"
|
||||||
|
#include "feature/nodelist/routerlist.h"
|
||||||
|
#include "lib/crypt_ops/crypto_rand.h"
|
||||||
#include "lib/evloop/token_bucket.h"
|
#include "lib/evloop/token_bucket.h"
|
||||||
|
#include "test/test.h"
|
||||||
|
#include "test/test_helpers.h"
|
||||||
|
|
||||||
|
#include "app/config/or_options_st.h"
|
||||||
|
#include "core/or/connection_st.h"
|
||||||
|
#include "feature/nodelist/microdesc_st.h"
|
||||||
|
#include "feature/nodelist/networkstatus_st.h"
|
||||||
|
#include "feature/nodelist/routerinfo_st.h"
|
||||||
|
#include "feature/nodelist/routerstatus_st.h"
|
||||||
|
|
||||||
// an imaginary time, in timestamp units. Chosen so it will roll over.
|
// an imaginary time, in timestamp units. Chosen so it will roll over.
|
||||||
static const uint32_t START_TS = UINT32_MAX-10;
|
static const uint32_t START_TS = UINT32_MAX-10;
|
||||||
static const int32_t KB = 1024;
|
static const int32_t KB = 1024;
|
||||||
static const uint32_t GB = (UINT64_C(1) << 30);
|
static const uint32_t GB = (UINT64_C(1) << 30);
|
||||||
|
|
||||||
|
static or_options_t mock_options;
|
||||||
|
|
||||||
|
static const or_options_t *
|
||||||
|
mock_get_options(void)
|
||||||
|
{
|
||||||
|
return &mock_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static networkstatus_t *dummy_ns = NULL;
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus(void)
|
||||||
|
{
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
|
||||||
|
{
|
||||||
|
tor_assert(f == FLAV_MICRODESC);
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of address a single node_t can have. Default to the production
|
||||||
|
* value. This is to control the size of the bloom filter. */
|
||||||
|
static int addr_per_node = 2;
|
||||||
|
static int
|
||||||
|
mock_get_estimated_address_per_node(void)
|
||||||
|
{
|
||||||
|
return addr_per_node;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_bwmgt_token_buf_init(void *arg)
|
test_bwmgt_token_buf_init(void *arg)
|
||||||
{
|
{
|
||||||
@ -220,8 +269,162 @@ test_bwmgt_token_buf_helpers(void *arg)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bwmgt_dir_conn_global_write_low(void *arg)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
int addr_family;
|
||||||
|
connection_t *conn = NULL;
|
||||||
|
routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
|
||||||
|
tor_addr_t relay_addr;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
memset(&mock_options, 0, sizeof(or_options_t));
|
||||||
|
MOCK(networkstatus_get_latest_consensus,
|
||||||
|
mock_networkstatus_get_latest_consensus);
|
||||||
|
MOCK(networkstatus_get_latest_consensus_by_flavor,
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
MOCK(get_estimated_address_per_node,
|
||||||
|
mock_get_estimated_address_per_node);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following is rather complex but that is what it takes to add a dummy
|
||||||
|
* consensus with a valid routerlist which will populate our node address
|
||||||
|
* set that we need to lookup to test the known relay code path.
|
||||||
|
*
|
||||||
|
* We MUST do that before we MOCK(get_options) else it is another world of
|
||||||
|
* complexity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This will be the address of our relay. */
|
||||||
|
tor_addr_parse(&relay_addr, "1.2.3.4");
|
||||||
|
|
||||||
|
/* We'll now add a relay into our routerlist and see if we let it. */
|
||||||
|
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
|
||||||
|
dummy_ns->flavor = FLAV_MICRODESC;
|
||||||
|
dummy_ns->routerstatus_list = smartlist_new();
|
||||||
|
|
||||||
|
md = tor_malloc_zero(sizeof(*md));
|
||||||
|
ri = tor_malloc_zero(sizeof(*ri));
|
||||||
|
rs = tor_malloc_zero(sizeof(*rs));
|
||||||
|
crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
|
||||||
|
crypto_rand(md->digest, sizeof(md->digest));
|
||||||
|
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
|
||||||
|
|
||||||
|
/* Set IP address. */
|
||||||
|
rs->addr = tor_addr_to_ipv4h(&relay_addr);
|
||||||
|
ri->addr = rs->addr;
|
||||||
|
/* Add the rs to the consensus becoming a node_t. */
|
||||||
|
smartlist_add(dummy_ns->routerstatus_list, rs);
|
||||||
|
|
||||||
|
/* Add all configured authorities (hardcoded) before we set the consensus so
|
||||||
|
* the address set exists. */
|
||||||
|
ret = consider_adding_dir_servers(&mock_options, &mock_options);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* This will make the nodelist bloom filter very large
|
||||||
|
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
|
||||||
|
addr_per_node = 1024;
|
||||||
|
|
||||||
|
nodelist_set_consensus(dummy_ns);
|
||||||
|
|
||||||
|
/* Ok, now time to control which options we use. */
|
||||||
|
MOCK(get_options, mock_get_options);
|
||||||
|
|
||||||
|
/* Set ourselves as an authoritative dir. */
|
||||||
|
mock_options.AuthoritativeDir = 1;
|
||||||
|
mock_options.V3AuthoritativeDir = 1;
|
||||||
|
mock_options.UseDefaultFallbackDirs = 0;
|
||||||
|
|
||||||
|
/* This will set our global bucket to 1 byte and thus we will hit the
|
||||||
|
* banwdith limit in our test. */
|
||||||
|
mock_options.BandwidthRate = 1;
|
||||||
|
mock_options.BandwidthBurst = 1;
|
||||||
|
|
||||||
|
/* Else an IPv4 address screams. */
|
||||||
|
mock_options.ClientUseIPv4 = 1;
|
||||||
|
mock_options.ClientUseIPv6 = 1;
|
||||||
|
|
||||||
|
/* Initialize the global buckets. */
|
||||||
|
connection_bucket_init();
|
||||||
|
|
||||||
|
/* The address "127.0.0.1" is set with this helper. */
|
||||||
|
conn = test_conn_get_connection(DIR_CONN_STATE_MIN_, CONN_TYPE_DIR,
|
||||||
|
DIR_PURPOSE_MIN_);
|
||||||
|
tt_assert(conn);
|
||||||
|
|
||||||
|
/* First try a non authority non relay IP thus a client but we are not
|
||||||
|
* configured to reject requests under load so we should get a false value
|
||||||
|
* that our limit is _not_ low. */
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* Now, we will reject requests under load so try again a non authority non
|
||||||
|
* relay IP thus a client. We should get a warning that our limit is too
|
||||||
|
* low. */
|
||||||
|
mock_options.AuthDirRejectRequestsUnderLoad = 1;
|
||||||
|
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "1.1.1.1");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Now, lets try with a connection address from moria1. It should always
|
||||||
|
* pass even though our limit is too low. */
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "128.31.0.39");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* IPv6 testing of gabelmoo. */
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "[2001:638:a000:4140::ffff:189]");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET6);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* Lets retry with a known relay address. It should pass. Possible due to
|
||||||
|
* our consensus setting above. */
|
||||||
|
memcpy(&conn->addr, &relay_addr, sizeof(tor_addr_t));
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* Lets retry with a random IP that is not an authority nor a relay. */
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* Finally, just make sure it still denies an IP if we are _not_ a v3
|
||||||
|
* directory authority. */
|
||||||
|
mock_options.V3AuthoritativeDir = 0;
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "1.2.3.4");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Random IPv6 should not be allowed. */
|
||||||
|
addr_family = tor_addr_parse(&conn->addr, "[CAFE::ACAB]");
|
||||||
|
tt_int_op(addr_family, OP_EQ, AF_INET6);
|
||||||
|
ret = connection_dir_is_global_write_low(conn, INT_MAX);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
|
||||||
|
done:
|
||||||
|
connection_free_minimal(conn);
|
||||||
|
routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
|
||||||
|
smartlist_clear(dummy_ns->routerstatus_list);
|
||||||
|
networkstatus_vote_free(dummy_ns);
|
||||||
|
|
||||||
|
UNMOCK(get_estimated_address_per_node);
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus);
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
UNMOCK(get_options);
|
||||||
|
}
|
||||||
|
|
||||||
#define BWMGT(name) \
|
#define BWMGT(name) \
|
||||||
{ #name, test_bwmgt_ ## name , 0, NULL, NULL }
|
{ #name, test_bwmgt_ ## name , TT_FORK, NULL, NULL }
|
||||||
|
|
||||||
struct testcase_t bwmgt_tests[] = {
|
struct testcase_t bwmgt_tests[] = {
|
||||||
BWMGT(token_buf_init),
|
BWMGT(token_buf_init),
|
||||||
@ -229,5 +432,7 @@ struct testcase_t bwmgt_tests[] = {
|
|||||||
BWMGT(token_buf_dec),
|
BWMGT(token_buf_dec),
|
||||||
BWMGT(token_buf_refill),
|
BWMGT(token_buf_refill),
|
||||||
BWMGT(token_buf_helpers),
|
BWMGT(token_buf_helpers),
|
||||||
|
|
||||||
|
BWMGT(dir_conn_global_write_low),
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user