aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app/config/config.c3
-rw-r--r--src/app/config/or_options_st.h4
-rw-r--r--src/core/or/policies.c22
-rw-r--r--src/core/or/policies.h1
-rw-r--r--src/feature/dirauth/dirauth_options.inc4
-rw-r--r--src/feature/dirauth/dirvote.c11
-rw-r--r--src/feature/dirauth/process_descs.c15
-rw-r--r--src/feature/dirauth/process_descs.h3
-rw-r--r--src/feature/dirauth/voteflags.c11
-rw-r--r--src/feature/dirauth/voteflags.h3
-rw-r--r--src/feature/dirparse/ns_parse.c2
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c3
-rw-r--r--src/feature/nodelist/node_st.h2
-rw-r--r--src/feature/nodelist/routerstatus_st.h2
-rw-r--r--src/test/test_voting_flags.c3
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);