Merge branch 'tor-gitlab/mr/452_squashed' into main

This commit is contained in:
Alexander Færøy 2021-10-21 12:57:37 +00:00
commit ae05f06597
18 changed files with 158 additions and 18 deletions

11
changes/prop335 Normal file
View File

@ -0,0 +1,11 @@
o Major features (directory authority):
- Authorities can now be configured to label relays as "MiddleOnly".
When voting for this flag, authorities automatically vote against
Exit, Guard, HSDir, and V2Dir; and in favor of BadExit.
Implements part of proposal 335. Based on a patch from Neel
Chauhan.
- Add a new consensus method to handle MiddleOnly specially. When
enough authorities are using this method, then any relay
tagged with the MiddleOnly flag will have its Exit, Guard, HSDir,
and V2Dir flags automatically cleared, and will have its BadExit flag
automatically set. Implements part of proposal 335.

View File

@ -3091,6 +3091,11 @@ on the public Tor network.
is the same as for exit policies, except that you don't need to say
"accept" or "reject", and ports are not needed.)
[[AuthDirMiddleOnly]] **AuthMiddleOnly** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
will be listed as middle-only in any network status document this authority
publishes, if **AuthDirListMiddleOnly** is set. +
[[AuthDirFastGuarantee]] **AuthDirFastGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**|**KBits**|**MBits**|**GBits**|**TBits**::
Authoritative directories only. If non-zero, always vote the
Fast flag for any relay advertising this amount of capacity or
@ -3138,6 +3143,13 @@ on the public Tor network.
1 unless you plan to list non-functioning exits as bad; otherwise, you are
effectively voting in favor of every declared exit as an exit.)
[[AuthDirListMiddleOnly]] **AuthDirListMiddleOnly** **0**|**1**::
Authoritative directories only. If set to 1, this directory has some
opinion about which nodes should only be used in the middle position.
(Do not set this to 1 unless you plan to list questionable relays
as "middle only"; otherwise, you are effectively voting _against_
middle-only status for every relay.)
[[AuthDirMaxServersPerAddr]] **AuthDirMaxServersPerAddr** __NUM__::
Authoritative directories only. The maximum number of servers that we will
list as acceptable on a single IP address. Set this to "0" for "no limit".
@ -3156,18 +3168,20 @@ on the public Tor network.
authority publishes, or accepted as an OR address in any descriptor
submitted for publication by this authority.
[[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)
//Out of order because it logically belongs with the other CCs options.
[[AuthDirBadExitCCs]] **AuthDirBadExitCCs** __CC__,... +
//Out of order because it logically belongs with the other CCs options.
[[AuthDirInvalidCCs]] **AuthDirInvalidCCs** __CC__,... +
[[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)
//Out of order because it logically belongs with the other CCs options.
[[AuthDirMiddleOnlytCCs]] **AuthDirMiddleOnlyCCs** __CC__,... +
[[AuthDirRejectCCs]] **AuthDirRejectCCs** __CC__,...::
Authoritative directories only. These options contain a comma-separated
@ -3889,7 +3903,8 @@ __DataDirectory__/**`approved-routers`**::
descriptors are accepted, but marked in the vote as not valid.
If it is **!badexit**, then the authority will vote for it to receive a
BadExit flag, indicating that it shouldn't be used for traffic leaving
the Tor network.
the Tor network. If it is **!middleonly**, then the authority will
vote for it to only be used in the middle of circuits.
(Neither rejected nor invalid relays are included in the consensus.)
__DataDirectory__/**`v3-status-votes`**::

View File

@ -193,6 +193,7 @@ static const config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadDirCC),
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
PLURAL(AuthDirMiddleOnlyCC),
PLURAL(AuthDirRejectCC),
PLURAL(EntryNode),
PLURAL(ExcludeNode),
@ -331,6 +332,8 @@ static const config_var_t option_vars_[] = {
V(AuthDirBadExitCCs, CSV, ""),
V(AuthDirInvalid, LINELIST, NULL),
V(AuthDirInvalidCCs, CSV, ""),
V(AuthDirMiddleOnly, LINELIST, NULL),
V(AuthDirMiddleOnlyCCs, CSV, ""),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
OBSOLETE("AuthDirRejectUnlisted"),

View File

@ -499,6 +499,9 @@ struct or_options_t {
struct smartlist_t *NodeFamilySets;
struct config_line_t *AuthDirBadExit; /**< Address policy for descriptors to
* mark as bad exits. */
/** Address policy for descriptors to mark as only suitable for the
* middle position in circuits. */
struct config_line_t *AuthDirMiddleOnly;
struct config_line_t *AuthDirReject; /**< Address policy for descriptors to
* reject. */
struct config_line_t *AuthDirInvalid; /**< Address policy for descriptors to
@ -512,6 +515,7 @@ struct or_options_t {
*/
struct smartlist_t *AuthDirBadExitCCs;
struct smartlist_t *AuthDirInvalidCCs;
struct smartlist_t *AuthDirMiddleOnlyCCs;
struct smartlist_t *AuthDirRejectCCs;
/**@}*/

View File

@ -59,6 +59,9 @@ static smartlist_t *authdir_invalid_policy = NULL;
/** Policy that addresses for incoming router descriptors must <b>not</b>
* match in order to not be marked as BadExit. */
static smartlist_t *authdir_badexit_policy = NULL;
/** Policy that addresses for incoming router descriptors must <b>not</b>
* match in order to not be marked as MiddleOnly. */
static smartlist_t *authdir_middleonly_policy = NULL;
/** Parsed addr_policy_t describing which addresses we believe we can start
* circuits at. */
@ -1119,6 +1122,17 @@ authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port)
return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs);
}
/** Return 1 if <b>addr</b>:<b>port</b> should be marked as MiddleOnly,
* based on <b>authdir_middleonly_policy</b>. Else return 0.
*/
int
authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port)
{
if (!addr_policy_permits_tor_addr(addr, port, authdir_middleonly_policy))
return 1;
return addr_is_in_cc_list(addr, get_options()->AuthDirMiddleOnlyCCs);
}
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); goto err; STMT_END
@ -1173,6 +1187,9 @@ validate_addr_policies(const or_options_t *options, char **msg)
if (parse_addr_policy(options->AuthDirBadExit, &addr_policy,
ADDR_POLICY_REJECT))
REJECT("Error in AuthDirBadExit entry.");
if (parse_addr_policy(options->AuthDirMiddleOnly, &addr_policy,
ADDR_POLICY_REJECT))
REJECT("Error in AuthDirMiddleOnly entry.");
if (parse_addr_policy(options->ReachableAddresses, &addr_policy,
ADDR_POLICY_ACCEPT))
@ -1266,6 +1283,9 @@ policies_parse_from_options(const or_options_t *options)
if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit",
&authdir_badexit_policy, ADDR_POLICY_REJECT) < 0)
ret = -1;
if (load_policy_from_option(options->AuthDirMiddleOnly, "AuthDirMiddleOnly",
&authdir_middleonly_policy, ADDR_POLICY_REJECT) < 0)
ret = -1;
if (parse_metrics_port_policy(options) < 0) {
ret = -1;
}
@ -3112,6 +3132,8 @@ policies_free_all(void)
authdir_invalid_policy = NULL;
addr_policy_list_free(authdir_badexit_policy);
authdir_badexit_policy = NULL;
addr_policy_list_free(authdir_middleonly_policy);
authdir_middleonly_policy = NULL;
if (!HT_EMPTY(&policy_root)) {
policy_map_ent_t **ent;

View File

@ -106,6 +106,7 @@ int metrics_policy_permits_address(const tor_addr_t *addr);
int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port);
int authdir_policy_middleonly_address(const tor_addr_t *addr, uint16_t port);
int validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);

View File

@ -27,6 +27,10 @@ CONF_VAR(AuthDirHasIPv6Connectivity, BOOL, 0, "0")
* good. */
CONF_VAR(AuthDirListBadExits, BOOL, 0, "0")
/** True iff we should list middle-only relays, and vote for all other
* relays as possibly suitable for other positions. */
CONF_VAR(AuthDirListMiddleOnly, BOOL, 0, "0")
/** Do not permit more than this number of servers per IP address. */
CONF_VAR(AuthDirMaxServersPerAddr, POSINT, 0, "2")

View File

@ -1479,6 +1479,21 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes)
return result;
}
/** Helper: Takes a smartlist of `const char *` flags, and a flag to remove.
*
* Removes that flag if it is present in the list. Doesn't free it.
*/
static void
remove_flag(smartlist_t *sl, const char *flag)
{
/* We can't use smartlist_string_remove() here, since that doesn't preserve
* order, and since it frees elements from the string. */
int idx = smartlist_string_pos(sl, flag);
if (idx >= 0)
smartlist_del_keeporder(sl, idx);
}
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
* and the number of <b>total_authorities</b> that we believe exist in our
@ -1633,6 +1648,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
tor_free(votesec_list);
tor_free(distsec_list);
}
// True if anybody is voting on the BadExit flag.
const bool badexit_flag_is_listed =
smartlist_contains_string(flags, "BadExit");
chunks = smartlist_new();
@ -1924,7 +1942,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
const char *chosen_name = NULL;
int exitsummary_disagreement = 0;
int is_named = 0, is_unnamed = 0, is_running = 0, is_valid = 0;
int is_guard = 0, is_exit = 0, is_bad_exit = 0;
int is_guard = 0, is_exit = 0, is_bad_exit = 0, is_middle_only = 0;
int naming_conflict = 0;
int n_listing = 0;
char microdesc_digest[DIGEST256_LEN];
@ -2055,7 +2073,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* Set the flags. */
smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */
SMARTLIST_FOREACH_BEGIN(flags, const char *, fl) {
if (!strcmp(fl, "Named")) {
if (is_named)
@ -2077,6 +2094,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
is_running = 1;
else if (!strcmp(fl, "BadExit"))
is_bad_exit = 1;
else if (!strcmp(fl, "MiddleOnly"))
is_middle_only = 1;
else if (!strcmp(fl, "Valid"))
is_valid = 1;
}
@ -2093,6 +2112,22 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (!is_valid)
continue;
/* Starting with consensus method 32, we handle the middle-only
* flag specially: when it is present, we clear some flags, and
* set others. */
if (is_middle_only && consensus_method >= MIN_METHOD_FOR_MIDDLEONLY) {
remove_flag(chosen_flags, "Exit");
remove_flag(chosen_flags, "V2Dir");
remove_flag(chosen_flags, "Guard");
remove_flag(chosen_flags, "HSDir");
is_exit = is_guard = 0;
if (! is_bad_exit && badexit_flag_is_listed) {
is_bad_exit = 1;
smartlist_add(chosen_flags, (char *)"BadExit");
smartlist_sort_strings(chosen_flags); // restore order.
}
}
/* Pick the version. */
if (smartlist_len(versions)) {
sort_version_list(versions, 0);
@ -2253,6 +2288,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add_asprintf(chunks, "m %s\n", m);
}
/* Next line is all flags. The "\n" is missing. */
smartlist_add_asprintf(chunks, "s%s",
smartlist_len(chosen_flags)?" ":"");
smartlist_add(chunks,
smartlist_join_strings(chosen_flags, " ", 0, NULL));
/* Now the version line. */
@ -4582,6 +4619,7 @@ const char DIRVOTE_UNIVERSAL_FLAGS[] =
* depending on our configuration. */
const char DIRVOTE_OPTIONAL_FLAGS[] =
"BadExit "
"MiddleOnly "
"Running";
/** Return a new networkstatus_t* containing our current opinion. (For v3
@ -4599,7 +4637,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_t *routers, *routerstatuses;
char identity_digest[DIGEST_LEN];
char signing_key_digest[DIGEST_LEN];
const int listbadexits = d_options->AuthDirListBadExits;
const int list_bad_exits = d_options->AuthDirListBadExits;
const int list_middle_only = d_options->AuthDirListMiddleOnly;
routerlist_t *rl = router_get_routerlist();
time_t now = time(NULL);
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
@ -4704,7 +4743,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now,
listbadexits);
list_bad_exits,
list_middle_only);
if (ri->cache_info.signing_key_cert) {
memcpy(vrs->ed25519_id,
@ -4828,8 +4868,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (vote_on_reachability)
smartlist_add_strdup(v3_out->known_flags, "Running");
if (listbadexits)
if (list_bad_exits)
smartlist_add_strdup(v3_out->known_flags, "BadExit");
if (list_middle_only)
smartlist_add_strdup(v3_out->known_flags, "MiddleOnly");
smartlist_sort_strings(v3_out->known_flags);
if (d_options->ConsensusParams) {

View File

@ -53,7 +53,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 28
/** The highest consensus method that we currently support. */
#define MAX_SUPPORTED_CONSENSUS_METHOD 31
#define MAX_SUPPORTED_CONSENSUS_METHOD 32
/**
* Lowest consensus method where microdescriptor lines are put in canonical
@ -70,6 +70,10 @@
*/
#define MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE 31
/** Lowest consensus method for which we handle the MiddleOnly flag specially.
*/
#define MIN_METHOD_FOR_MIDDLEONLY 32
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */

View File

@ -226,6 +226,8 @@ dirserv_load_fingerprint_file(void)
add_status = RTR_BADEXIT;
} else if (!strcasecmp(nickname, "!invalid")) {
add_status = RTR_INVALID;
} else if (!strcasecmp(nickname, "!middleonly")) {
add_status = RTR_MIDDLEONLY;
}
/* Check if fingerprint is RSA or ed25519 by verifying it. */
@ -496,6 +498,13 @@ dirserv_get_status_impl(const char *id_digest,
result |= RTR_BADEXIT;
}
if (authdir_policy_middleonly_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV,
"Marking '%s' as middle-only because of address '%s'",
nickname, fmt_addr(ipv4_addr));
result |= RTR_MIDDLEONLY;
}
if (!authdir_policy_permits_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'",
nickname, fmt_addr(ipv4_addr));
@ -630,6 +639,7 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node,
{
node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1;
node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0;
node->is_middle_only = (authstatus & RTR_MIDDLEONLY) ? 1 : 0;
}
/** True iff <b>a</b> is more severe than <b>b</b>. */
@ -963,6 +973,11 @@ directory_remove_invalid(void)
(r & RTR_BADEXIT) ? "bad" : "good");
node->is_bad_exit = (r&RTR_BADEXIT) ? 1: 0;
}
if (bool_neq((r & RTR_MIDDLEONLY), node->is_middle_only)) {
log_info(LD_DIRSERV, "Router '%s' is now %smiddle-only", description,
(r & RTR_MIDDLEONLY) ? "" : "not");
node->is_middle_only = (r&RTR_MIDDLEONLY) ? 1: 0;
}
} SMARTLIST_FOREACH_END(node);
routerlist_assert_ok(rl);

View File

@ -45,7 +45,8 @@ typedef struct authdir_config_t {
#define RTR_REJECT 4 /**< We will not publish this router. */
/* 8 Historically used to avoid using this as a dir. */
#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
/* 32 Historically used to indicade Unnamed */
/** We'll vote to only use this router as a midpoint. */
#define RTR_MIDDLEONLY 32
#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */

View File

@ -565,7 +565,8 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
const routerinfo_t *ri,
time_t now,
int listbadexits)
int listbadexits,
int listmiddleonly)
{
const or_options_t *options = get_options();
uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
@ -597,6 +598,14 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
/* Override rs->is_bad_exit */
rs->is_bad_exit = listbadexits && node->is_bad_exit;
/* Override rs->is_middle_only and related flags. */
rs->is_middle_only = listmiddleonly && node->is_middle_only;
if (rs->is_middle_only) {
if (listbadexits)
rs->is_bad_exit = 1;
rs->is_exit = rs->is_possible_guard = rs->is_hs_dir = rs->is_v2_dir = 0;
}
/* Set rs->is_staledesc. */
rs->is_staledesc =
(ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now;

View File

@ -22,7 +22,8 @@ void dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
const routerinfo_t *ri,
time_t now,
int listbadexits);
int listbadexits,
int listmiddleonly);
void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil);
#endif /* defined(HAVE_MODULE_DIRAUTH) */

View File

@ -434,6 +434,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->is_possible_guard = 1;
else if (!strcmp(tok->args[i], "BadExit"))
rs->is_bad_exit = 1;
else if (!strcmp(tok->args[i], "MiddleOnly"))
rs->is_middle_only = 1;
else if (!strcmp(tok->args[i], "Authority"))
rs->is_authority = 1;
else if (!strcmp(tok->args[i], "Unnamed") &&

View File

@ -87,7 +87,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
goto done;
smartlist_add_asprintf(chunks,
"s%s%s%s%s%s%s%s%s%s%s%s%s\n",
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
rs->is_bad_exit?" BadExit":"",
@ -95,6 +95,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
rs->is_fast?" Fast":"",
rs->is_possible_guard?" Guard":"",
rs->is_hs_dir?" HSDir":"",
rs->is_middle_only?" MiddleOnly":"",
rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
rs->is_staledesc?" StaleDesc":"",

View File

@ -70,6 +70,8 @@ struct node_t {
unsigned int is_exit:1; /**< Do we think this is an OK exit? */
unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
* or otherwise nasty? */
/** Is this unsuitable for use as anything besides a middle relay? */
unsigned int is_middle_only:1;
unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
* directory according to the authorities. */

View File

@ -51,6 +51,8 @@ struct routerstatus_t {
* choice as an entry guard. */
unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for
* an exit node. */
unsigned int is_middle_only:1; /**< True iff this node is marked as bad
* for anything besides middle positions. */
unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden
* service directory. */
unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort

View File

@ -62,7 +62,8 @@ check_result(flag_vote_test_cfg_t *c)
bool result = false;
routerstatus_t rs;
memset(&rs, 0, sizeof(rs));
dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now, 0);
dirauth_set_routerstatus_from_routerinfo(&rs, &c->node, &c->ri, c->now,
0, 0);
tt_i64_op(rs.published_on, OP_EQ, c->expected.published_on);
tt_str_op(rs.nickname, OP_EQ, c->expected.nickname);