diff options
-rw-r--r-- | src/app/config/config.c | 3 | ||||
-rw-r--r-- | src/app/config/or_options_st.h | 4 | ||||
-rw-r--r-- | src/core/or/policies.c | 22 | ||||
-rw-r--r-- | src/core/or/policies.h | 1 | ||||
-rw-r--r-- | src/feature/dirauth/dirauth_options.inc | 4 | ||||
-rw-r--r-- | src/feature/dirauth/dirvote.c | 11 | ||||
-rw-r--r-- | src/feature/dirauth/process_descs.c | 15 | ||||
-rw-r--r-- | src/feature/dirauth/process_descs.h | 3 | ||||
-rw-r--r-- | src/feature/dirauth/voteflags.c | 11 | ||||
-rw-r--r-- | src/feature/dirauth/voteflags.h | 3 | ||||
-rw-r--r-- | src/feature/dirparse/ns_parse.c | 2 | ||||
-rw-r--r-- | src/feature/nodelist/fmt_routerstatus.c | 3 | ||||
-rw-r--r-- | src/feature/nodelist/node_st.h | 2 | ||||
-rw-r--r-- | src/feature/nodelist/routerstatus_st.h | 2 | ||||
-rw-r--r-- | src/test/test_voting_flags.c | 3 |
15 files changed, 81 insertions, 8 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c index 15b4585954..8df5275cc6 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -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"), diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 812fa92cae..3a1acad044 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -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; /**@}*/ diff --git a/src/core/or/policies.c b/src/core/or/policies.c index f91c23ad31..a53849b4d0 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -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; diff --git a/src/core/or/policies.h b/src/core/or/policies.h index a32f50ab1d..e11e1d0ff5 100644 --- a/src/core/or/policies.h +++ b/src/core/or/policies.h @@ -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); diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc index 05726b8c2f..968f8e6c3d 100644 --- a/src/feature/dirauth/dirauth_options.inc +++ b/src/feature/dirauth/dirauth_options.inc @@ -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") diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index ffaa78b997..4f8cf2b8e6 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -4581,6 +4581,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 @@ -4598,7 +4599,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; @@ -4703,7 +4705,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, @@ -4827,8 +4830,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) { diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c index eca987b8b5..db4eca5329 100644 --- a/src/feature/dirauth/process_descs.c +++ b/src/feature/dirauth/process_descs.c @@ -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); diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h index 6c056d11dd..a509eb1fbe 100644 --- a/src/feature/dirauth/process_descs.h +++ b/src/feature/dirauth/process_descs.h @@ -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) */ diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c index d755a270be..05c19ff501 100644 --- a/src/feature/dirauth/voteflags.c +++ b/src/feature/dirauth/voteflags.c @@ -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; diff --git a/src/feature/dirauth/voteflags.h b/src/feature/dirauth/voteflags.h index 818a0bafd2..8371f1c315 100644 --- a/src/feature/dirauth/voteflags.h +++ b/src/feature/dirauth/voteflags.h @@ -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) */ diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c index 947b3810a4..cd3e2731be 100644 --- a/src/feature/dirparse/ns_parse.c +++ b/src/feature/dirparse/ns_parse.c @@ -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") && diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c index 6db40c0b68..95379a7721 100644 --- a/src/feature/nodelist/fmt_routerstatus.c +++ b/src/feature/nodelist/fmt_routerstatus.c @@ -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":"", diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h index b15e7154c4..df67a47ada 100644 --- a/src/feature/nodelist/node_st.h +++ b/src/feature/nodelist/node_st.h @@ -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. */ diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h index 46ff0bdeac..55b76de581 100644 --- a/src/feature/nodelist/routerstatus_st.h +++ b/src/feature/nodelist/routerstatus_st.h @@ -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 diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c index 4c5f3a3270..457b0fa796 100644 --- a/src/test/test_voting_flags.c +++ b/src/test/test_voting_flags.c @@ -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); |