Merge branch 'assume_reachable_revamp'

This commit is contained in:
Nick Mathewson 2020-06-26 08:34:56 -04:00
commit dbc2b75009
20 changed files with 123 additions and 50 deletions

3
changes/ticket33224 Normal file
View File

@ -0,0 +1,3 @@
o Minor features (relay, IPv6):
- Add an AssumeReachableIPv6 option to disable self-checking IPv6
reachability. Closes part of ticket 33224.

5
changes/ticket34064 Normal file
View File

@ -0,0 +1,5 @@
o Minor features (relay, ipv6):
- Add new "assume-reachable" and "assume-reachable-ipv6" parameters
to be used in an emergency to tell relays that they should publish
even if they cannot complete their ORPort self-checks.
Closes ticket 34064 and part of 33224.

View File

@ -2145,7 +2145,12 @@ is non-zero):
don't do self-reachability testing; just upload your server descriptor
immediately. If **AuthoritativeDirectory** is also set, this option
instructs the dirserver to bypass remote reachability testing too and list
all connected servers as running.
all connected servers as running. (Default: 0)
[[AssumeReachableIPv6]] **AssumeReachableIPv6** **0**|**1**|**auto**::
Like **AssumeReachable**, but affects only the relay's own IPv6 ORPort.
If this value is set to "auto", then Tor will look at **AssumeReachable**
instead. (Default: auto)
[[BridgeRelay]] **BridgeRelay** **0**|**1**::
Sets the relay to act as a "bridge" with respect to relaying connections

View File

@ -323,6 +323,7 @@ static const config_var_t option_vars_[] = {
V(AlternateDirAuthority, LINELIST, NULL),
OBSOLETE("AlternateHSAuthority"),
V(AssumeReachable, BOOL, "0"),
V(AssumeReachableIPv6, AUTOBOOL, "auto"),
OBSOLETE("AuthDirBadDir"),
OBSOLETE("AuthDirBadDirCCs"),
V(AuthDirBadExit, LINELIST, NULL),
@ -3225,6 +3226,10 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
}
if (options->AssumeReachable && options->AssumeReachableIPv6 == 0) {
REJECT("Cannot set AssumeReachable 1 and AssumeReachableIPv6 0.");
}
if (options->ExcludeExitNodes || options->ExcludeNodes) {
options->ExcludeExitNodesUnion_ = routerset_new();
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);

View File

@ -195,7 +195,14 @@ struct or_options_t {
unsigned int HTTPTunnelPort_set : 1;
/**@}*/
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
/** Whether to publish our descriptor regardless of all our self-tests
*/
int AssumeReachable;
/** Whether to publish our descriptor regardless of IPv6 self-tests.
*
* This is an autobool; when set to AUTO, it uses AssumeReachable.
**/
int AssumeReachableIPv6;
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory
* for version 3 directories? */

View File

@ -90,7 +90,7 @@ static int consensus_nf_pad_single_onion;
* for every single connection, every second.
*/
void
channelpadding_new_consensus_params(networkstatus_t *ns)
channelpadding_new_consensus_params(const networkstatus_t *ns)
{
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW 1500
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH 9500

View File

@ -37,7 +37,6 @@ int channelpadding_send_enable_command(channel_t *chan, uint16_t low_timeout,
int channelpadding_get_circuits_available_timeout(void);
unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int);
void channelpadding_new_consensus_params(networkstatus_t *ns);
void channelpadding_new_consensus_params(const networkstatus_t *ns);
#endif /* !defined(TOR_CHANNELPADDING_H) */

View File

@ -1055,7 +1055,7 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
clear_broken_connection_map(1);
if (server_mode(options) &&
!router_should_skip_orport_reachability_check(options)) {
!router_all_orports_seem_reachable(options)) {
inform_testing_reachability();
router_do_reachability_checks(1, 1);
}

View File

@ -399,7 +399,7 @@ circuit_build_times_initial_timeout(void)
* and learn a new timeout.
*/
static int32_t
circuit_build_times_recent_circuit_count(networkstatus_t *ns)
circuit_build_times_recent_circuit_count(const networkstatus_t *ns)
{
int32_t num;
num = networkstatus_get_param(ns, "cbtrecentcount",
@ -425,7 +425,7 @@ circuit_build_times_recent_circuit_count(networkstatus_t *ns)
*/
void
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
networkstatus_t *ns)
const networkstatus_t *ns)
{
int32_t num;

View File

@ -43,7 +43,7 @@ int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
void circuit_build_times_init(circuit_build_times_t *cbt);
void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
networkstatus_t *ns);
const networkstatus_t *ns);
double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);

View File

@ -1642,7 +1642,7 @@ static void
circuit_testing_opened(origin_circuit_t *circ)
{
if (have_performed_bandwidth_test ||
!router_should_skip_orport_reachability_check(get_options())) {
!router_all_orports_seem_reachable(get_options())) {
/* either we've already done everything we want with testing circuits,
* or this testing circuit became open due to a fluke, e.g. we picked
* a last hop where we already had the connection open due to an
@ -1661,7 +1661,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
{
const or_options_t *options = get_options();
if (server_mode(options) &&
router_should_skip_orport_reachability_check(options))
router_all_orports_seem_reachable(options))
return;
log_info(LD_GENERAL,

View File

@ -1279,7 +1279,7 @@ getinfo_helper_events(control_connection_t *control_conn,
? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/or")) {
*answer = tor_strdup(
router_should_skip_orport_reachability_check(options) ?
router_all_orports_seem_reachable(options) ?
"1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/dir")) {
*answer = tor_strdup(
@ -1288,7 +1288,7 @@ getinfo_helper_events(control_connection_t *control_conn,
} else if (!strcmp(question, "status/reachability-succeeded")) {
tor_asprintf(
answer, "OR=%d DIR=%d",
router_should_skip_orport_reachability_check(options) ? 1 : 0,
router_all_orports_seem_reachable(options) ? 1 : 0,
router_dirport_seems_reachable(options) ? 1 : 0);
} else if (!strcmp(question, "status/bootstrap-phase")) {
*answer = control_event_boot_last_msg();

View File

@ -1670,7 +1670,35 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
static void
notify_after_networkstatus_changes(void)
{
const networkstatus_t *c = networkstatus_get_latest_consensus();
const or_options_t *options = get_options();
const time_t now = approx_time();
scheduler_notify_networkstatus_changed();
/* The "current" consensus has just been set and it is a usable flavor so
* the first thing we need to do is recalculate the voting schedule static
* object so we can use the timings in there needed by some subsystems
* such as hidden service and shared random. */
dirauth_sched_recalculate_timing(options, now);
reschedule_dirvote(options);
nodelist_set_consensus(c);
update_consensus_networkstatus_fetch_time(now);
/* Change the cell EWMA settings */
cmux_ewma_set_options(options, c);
/* XXXX this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
connection_or_update_token_buckets(get_connection_array(), options);
circuit_build_times_new_consensus_params(
get_circuit_build_times_mutable(), c);
channelpadding_new_consensus_params(c);
circpad_new_consensus_params(c);
router_new_consensus_params(c);
}
/** Copy all the ancillary information (like router download status and so on)
@ -2115,29 +2143,6 @@ networkstatus_set_current_consensus(const char *consensus,
/* Notify that we just changed the consensus so the current global value
* can be looked at. */
notify_after_networkstatus_changes();
/* The "current" consensus has just been set and it is a usable flavor so
* the first thing we need to do is recalculate the voting schedule static
* object so we can use the timings in there needed by some subsystems
* such as hidden service and shared random. */
dirauth_sched_recalculate_timing(options, now);
reschedule_dirvote(options);
nodelist_set_consensus(c);
update_consensus_networkstatus_fetch_time(now);
/* Change the cell EWMA settings */
cmux_ewma_set_options(options, c);
/* XXXX this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
connection_or_update_token_buckets(get_connection_array(), options);
circuit_build_times_new_consensus_params(
get_circuit_build_times_mutable(), c);
channelpadding_new_consensus_params(c);
circpad_new_consensus_params(c);
}
/* Reset the failure count only if this consensus is actually valid. */

View File

@ -621,7 +621,7 @@ get_estimated_address_per_node, (void))
* and grab microdescriptors into nodes as appropriate.
*/
void
nodelist_set_consensus(networkstatus_t *ns)
nodelist_set_consensus(const networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
@ -952,7 +952,7 @@ nodelist_assert_ok(void)
/** Ensure that the nodelist has been created with the most recent consensus.
* If that's not the case, make it so. */
void
nodelist_ensure_freshness(networkstatus_t *ns)
nodelist_ensure_freshness(const networkstatus_t *ns)
{
tor_assert(ns);

View File

@ -32,8 +32,8 @@ const node_t *node_get_by_hex_id(const char *identity_digest,
unsigned flags);
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
void nodelist_set_consensus(networkstatus_t *ns);
void nodelist_ensure_freshness(networkstatus_t *ns);
void nodelist_set_consensus(const networkstatus_t *ns);
void nodelist_ensure_freshness(const networkstatus_t *ns);
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);

View File

@ -1349,6 +1349,17 @@ should_refuse_unknown_exits(const or_options_t *options)
}
}
/**
* If true, then we will publish our descriptor even if our own IPv4 ORPort
* seems to be unreachable.
**/
static bool publish_even_when_ipv4_orport_unreachable = false;
/**
* If true, then we will publish our descriptor even if our own IPv6 ORPort
* seems to be unreachable.
**/
static bool publish_even_when_ipv6_orport_unreachable = false;
/** Decide if we're a publishable server. We are a publishable server if:
* - We don't have the ClientOnly option set
* and
@ -1377,8 +1388,18 @@ decide_if_publishable_server(void)
return 1;
if (!router_get_advertised_or_port(options))
return 0;
if (!router_should_skip_orport_reachability_check(options))
return 0;
if (!router_orport_seems_reachable(options, AF_INET)) {
// We have an ipv4 orport, and it doesn't seem reachable.
if (!publish_even_when_ipv4_orport_unreachable) {
return 0;
}
}
if (!router_orport_seems_reachable(options, AF_INET6)) {
// We have an ipv6 orport, and it doesn't seem reachable.
if (!publish_even_when_ipv6_orport_unreachable) {
return 0;
}
}
if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL) {
/* All set: there are no exits in the consensus (maybe this is a tiny
* test network), so we can't check our DirPort reachability. */
@ -2402,6 +2423,24 @@ router_rebuild_descriptor(int force)
return 0;
}
/** Called when we have a new set of consensus parameters. */
void
router_new_consensus_params(const networkstatus_t *ns)
{
const int32_t DEFAULT_ASSUME_REACHABLE = 0;
const int32_t DEFAULT_ASSUME_REACHABLE_IPV6 = 0;
int ar, ar6;
ar = networkstatus_get_param(ns,
"assume-reachable",
DEFAULT_ASSUME_REACHABLE, 0, 1);
ar6 = networkstatus_get_param(ns,
"assume-reachable-ipv6",
DEFAULT_ASSUME_REACHABLE_IPV6, 0, 1);
publish_even_when_ipv4_orport_unreachable = ar;
publish_even_when_ipv6_orport_unreachable = ar || ar6;
}
/** If our router descriptor ever goes this long without being regenerated
* because something changed, we force an immediate regenerate-and-upload. */
#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)

View File

@ -81,6 +81,7 @@ int router_should_advertise_dirport(const or_options_t *options,
void consider_publishable_server(int force);
int should_refuse_unknown_exits(const or_options_t *options);
void router_new_consensus_params(const networkstatus_t *);
void router_upload_dir_desc_to_dirservers(int force);
void mark_my_descriptor_dirty_if_too_old(time_t now);
void mark_my_descriptor_dirty(const char *reason);

View File

@ -86,9 +86,8 @@ router_reachability_checks_disabled(const or_options_t *options)
* orport checks.
*/
int
router_orport_seems_reachable(
const or_options_t *options,
int family)
router_orport_seems_reachable(const or_options_t *options,
int family)
{
tor_assert_nonfatal(family == AF_INET || family == AF_INET6 || family == 0);
int reach_checks_disabled = router_reachability_checks_disabled(options);
@ -96,6 +95,11 @@ router_orport_seems_reachable(
return true;
}
// Note that we do a == 1 here, not just a boolean check. This value
// is also an autobool, so CFG_AUTO does not mean that we should
// assume IPv6 ports are reachable.
const bool ipv6_assume_reachable = (options->AssumeReachableIPv6 == 1);
// Which reachability flags should we look at?
const bool checking_ipv4 = (family == AF_INET || family == 0);
const bool checking_ipv6 = (family == AF_INET6 || family == 0);
@ -105,7 +109,7 @@ router_orport_seems_reachable(
return false;
}
}
if (checking_ipv6) {
if (checking_ipv6 && !ipv6_assume_reachable) {
if (have_orport_for_family(AF_INET6) && !can_reach_or_port_ipv6) {
return false;
}
@ -409,7 +413,7 @@ ready_to_publish(const or_options_t *options)
{
return options->PublishServerDescriptor_ != NO_DIRINFO &&
router_dirport_seems_reachable(options) &&
router_should_skip_orport_reachability_check(options);
router_all_orports_seem_reachable(options);
}
/** Annotate that we found our ORPort reachable with a given address

View File

@ -15,7 +15,7 @@
#ifdef HAVE_MODULE_RELAY
struct or_options_t;
#define router_should_skip_orport_reachability_check(opts) \
#define router_all_orports_seem_reachable(opts) \
router_orport_seems_reachable((opts),0)
int router_orport_seems_reachable(
const struct or_options_t *options,
@ -34,7 +34,7 @@ void router_reset_reachability(void);
#else /* !defined(HAVE_MODULE_RELAY) */
#define router_should_skip_orport_reachability_check(opts) \
#define router_all_orports_seem_reachable(opts) \
((void)(opts), 0)
#define router_orport_seems_reachable(opts, fam) \
((void)(opts), (void)(fam), 0)

View File

@ -270,7 +270,7 @@ rep_hist_circbuilding_dormant(time_t now)
/* see if we'll still need to build testing circuits */
if (server_mode(options) &&
(!router_should_skip_orport_reachability_check(options) ||
(!router_all_orports_seem_reachable(options) ||
!circuit_enough_testing_circs()))
return 0;
if (!router_dirport_seems_reachable(options))