diff --git a/ChangeLog b/ChangeLog index 963066b32f..355b964804 100644 --- a/ChangeLog +++ b/ChangeLog @@ -67,6 +67,10 @@ Changes in version 0.2.0.13-alpha - 2007-12-?? addresses. - Allow multiple HashedControlPassword config lines, to support multiple controller passwords. + - New config options AuthDirBadDir and AuthDirListBadDirs for + authorities to mark certain relays as "bad directories" in the + networkstatus documents. Also supports the "!baddir" directive in + the approved-routers file. Changes in version 0.2.0.12-alpha - 2007-11-16 diff --git a/doc/spec/dir-spec.txt b/doc/spec/dir-spec.txt index e6ca2cc1e1..8ebc905191 100644 --- a/doc/spec/dir-spec.txt +++ b/doc/spec/dir-spec.txt @@ -1528,6 +1528,8 @@ $Id$ - Clients SHOULD NOT download directory information from non-'V2Dir' caches. + See the "path-spec.txt" document for more details. + 6.2. Managing naming In order to provide human-memorable names for individual server diff --git a/src/or/config.c b/src/or/config.c index 9b358fc17e..81c0fcd9ce 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -131,10 +131,12 @@ static config_var_t _option_vars[] = { V(AllowInvalidNodes, CSV, "middle,rendezvous"), V(AllowNonRFC953Hostnames, BOOL, "0"), V(AssumeReachable, BOOL, "0"), + V(AuthDirBadDir, LINELIST, NULL), V(AuthDirBadExit, LINELIST, NULL), V(AuthDirInvalid, LINELIST, NULL), V(AuthDirReject, LINELIST, NULL), V(AuthDirRejectUnlisted, BOOL, "0"), + V(AuthDirListBadDirs, BOOL, "0"), V(AuthDirListBadExits, BOOL, "0"), VAR("AuthoritativeDirectory", BOOL, AuthoritativeDir, "0"), V(AutomapHostsOnResolve, BOOL, "0"), diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 2dc87d11a2..83cbbf6307 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -66,8 +66,9 @@ static int dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); #define FP_NAMED 1 /**< Listed in fingerprint file. */ #define FP_INVALID 2 /**< Believed invalid. */ #define FP_REJECT 4 /**< We will not publish this router. */ -#define FP_BADEXIT 8 /**< We'll tell clients not to use this as an exit. */ -#define FP_UNNAMED 16 /**< Another router has this name in fingerprint file. */ +#define FP_BADDIR 8 /**< We'll tell clients to avoid using this as a dir. */ +#define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */ +#define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */ /** Encapsulate a nickname and an FP_* status; target of status_by_digest * map. */ @@ -149,6 +150,8 @@ add_fingerprint_to_dir(const char *nickname, const char *fp, status->status |= FP_REJECT; } else if (!strcasecmp(nickname, "!invalid")) { status->status |= FP_INVALID; + } else if (!strcasecmp(nickname, "!baddir")) { + status->status |= FP_BADDIR; } else if (!strcasecmp(nickname, "!badexit")) { status->status |= FP_BADEXIT; } @@ -395,6 +398,14 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname, *msg = "Fingerprint is marked invalid"; } + if (authdir_policy_baddir_address(addr, or_port)) { + if (should_log) + log_info(LD_DIRSERV, + "Marking '%s' as bad directory because of address '%s'", + nickname, address); + result |= FP_BADDIR; + } + if (authdir_policy_badexit_address(addr, or_port)) { if (should_log) log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'", @@ -538,6 +549,7 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, /* Okay, looks like we're willing to accept this one. */ ri->is_named = (status & FP_NAMED) ? 1 : 0; ri->is_valid = (status & FP_INVALID) ? 0 : 1; + ri->is_bad_directory = (status & FP_BADDIR) ? 1 : 0; ri->is_bad_exit = (status & FP_BADEXIT) ? 1 : 0; return 0; @@ -779,6 +791,12 @@ directory_remove_invalid(void) ent->is_valid = (r&FP_INVALID)?0:1; changed = 1; } + if (bool_neq((r & FP_BADDIR), ent->is_bad_directory)) { + log_info(LD_DIRSERV, "Router '%s' is now a %s directory", ent->nickname, + (r & FP_BADDIR) ? "bad" : "good"); + ent->is_bad_directory = (r&FP_BADDIR) ? 1: 0; + changed = 1; + } if (bool_neq((r & FP_BADEXIT), ent->is_bad_exit)) { log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname, (r & FP_BADEXIT) ? "bad" : "good"); @@ -1849,9 +1867,10 @@ routerstatus_format_entry(char *buf, size_t buf_len, return 0; cp = buf + strlen(buf); r = tor_snprintf(cp, buf_len - (cp-buf), - "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_directory?" BadDirectory":"", rs->is_bad_exit?" BadExit":"", rs->is_exit?" Exit":"", rs->is_fast?" Fast":"", @@ -1977,7 +1996,7 @@ static void set_routerstatus_from_routerinfo(routerstatus_t *rs, routerinfo_t *ri, time_t now, int naming, int exits_can_be_guards, - int listbadexits) + int listbadexits, int listbaddirs) { int unstable_version = tor_version_as_new_as(ri->platform,"0.1.1.10-alpha") && @@ -2020,6 +2039,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, } else { rs->is_possible_guard = 0; } + rs->is_bad_directory = listbaddirs && ri->is_bad_directory; rs->is_bad_exit = listbadexits && ri->is_bad_exit; ri->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, now); rs->is_hs_dir = ri->is_hs_dir; @@ -2050,7 +2070,8 @@ clear_status_flags_on_sybil(routerstatus_t *rs) { rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast = rs->is_running = rs->is_named = rs->is_valid = rs->is_v2_dir = - rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = 0; + rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = + rs->is_bad_directory = 0; /* FFFF we might want some mechanism to check later on if we * missed zeroing any flags: it's easy to add a new flag but * forget to add it to this clause. */ @@ -2065,7 +2086,7 @@ router_clear_status_flags(routerinfo_t *router) router->is_valid = router->is_running = router->is_hs_dir = router->is_fast = router->is_stable = router->is_possible_guard = router->is_exit = - router->is_bad_exit = 0; + router->is_bad_exit = router->is_bad_directory = 0; } /** If we've been around for less than this amount of time, our reachability @@ -2088,6 +2109,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, char signing_key_digest[DIGEST_LEN]; int naming = options->NamingAuthoritativeDir; int listbadexits = options->AuthDirListBadExits; + int listbaddirs = options->AuthDirListBadDirs; int exits_can_be_guards; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); @@ -2157,7 +2179,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, rs = &vrs->status; set_routerstatus_from_routerinfo(rs, ri, now, naming, exits_can_be_guards, - listbadexits); + listbadexits, listbaddirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(rs); @@ -2211,6 +2233,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (vote_on_reachability) smartlist_add(v3_out->known_flags, tor_strdup("Running")); + if (listbaddirs) + smartlist_add(v3_out->known_flags, tor_strdup("BadDirectory")); if (listbadexits) smartlist_add(v3_out->known_flags, tor_strdup("BadExit")); if (naming) { @@ -2274,6 +2298,7 @@ generate_v2_networkstatus_opinion(void) time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; int naming = options->NamingAuthoritativeDir; int versioning = options->VersioningAuthoritativeDir; + int listbaddirs = options->AuthDirListBadDirs; int listbadexits = options->AuthDirListBadExits; int exits_can_be_guards; const char *contact; @@ -2331,7 +2356,7 @@ generate_v2_networkstatus_opinion(void) "fingerprint %s\n" "contact %s\n" "published %s\n" - "dir-options%s%s%s\n" + "dir-options%s%s%s%s\n" "%s" /* client version line, server version line. */ "dir-signing-key\n%s", hostname, ipaddr, (int)options->DirPort, @@ -2339,6 +2364,7 @@ generate_v2_networkstatus_opinion(void) contact, published, naming ? " Names" : "", + listbaddirs ? " BadDirectories" : "", listbadexits ? " BadExits" : "", versioning ? " Versions" : "", version_lines, @@ -2371,7 +2397,7 @@ generate_v2_networkstatus_opinion(void) set_routerstatus_from_routerinfo(&rs, ri, now, naming, exits_can_be_guards, - listbadexits); + listbadexits, listbaddirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(&rs); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 3b4f9d31b0..6a72340bab 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1619,6 +1619,7 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, router->is_stable = rs->is_stable; router->is_possible_guard = rs->is_possible_guard; router->is_exit = rs->is_exit; + router->is_bad_directory = rs->is_bad_directory; router->is_bad_exit = rs->is_bad_exit; router->is_hs_dir = rs->is_hs_dir; } diff --git a/src/or/or.h b/src/or/or.h index 6b29fd714d..bf56bdd9ee 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1288,6 +1288,8 @@ typedef struct { 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? */ + unsigned int is_bad_directory:1; /**< Do we think this directory is junky, + * underpowered, or otherwise useless? */ unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be * a hidden service directory. */ unsigned int is_hs_dir:1; /**< True iff this router is a hidden service @@ -2195,12 +2197,16 @@ typedef struct { config_line_t *RedirectExit; /**< List of config lines for simple * addr/port redirection */ smartlist_t *RedirectExitList; /**< List of exit_redirect_t */ + config_line_t *AuthDirBadDir; /**< Address policy for descriptors to + * mark as bad dir mirrors. */ config_line_t *AuthDirBadExit; /**< Address policy for descriptors to - * mark as bad exits. */ + * mark as bad exits. */ config_line_t *AuthDirReject; /**< Address policy for descriptors to * reject. */ config_line_t *AuthDirInvalid; /**< Address policy for descriptors to * never mark as valid. */ + int AuthDirListBadDirs; /**< True iff we should list bad dirs, + * and vote for all other dir mirrors as good. */ int AuthDirListBadExits; /**< True iff we should list bad exits, * and vote for all other exits as good. */ int AuthDirRejectUnlisted; /**< Boolean: do we reject all routers that @@ -3377,6 +3383,7 @@ int dir_policy_permits_address(uint32_t addr); int socks_policy_permits_address(uint32_t addr); int authdir_policy_permits_address(uint32_t addr, uint16_t port); int authdir_policy_valid_address(uint32_t addr, uint16_t port); +int authdir_policy_baddir_address(uint32_t addr, uint16_t port); int authdir_policy_badexit_address(uint32_t addr, uint16_t port); int validate_addr_policies(or_options_t *options, char **msg); diff --git a/src/or/policies.c b/src/or/policies.c index 358f766bd5..4148fa471e 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -22,6 +22,9 @@ static addr_policy_t *authdir_reject_policy = NULL; /** Policy that addresses for incoming router descriptors must match in order * to be marked as valid in our networkstatus. */ static addr_policy_t *authdir_invalid_policy = NULL; +/** Policy that addresses for incoming router descriptors must not + * match in order to not be marked as BadDirectory. */ +static addr_policy_t *authdir_baddir_policy = NULL; /** Policy that addresses for incoming router descriptors must not * match in order to not be marked as BadExit. */ static addr_policy_t *authdir_badexit_policy = NULL; @@ -206,6 +209,16 @@ authdir_policy_valid_address(uint32_t addr, uint16_t port) return addr_policy_permits_address(addr, port, authdir_invalid_policy); } +/** Return 1 if addr:port should be marked as a bad dir, + * based on authdir_baddir_policy. Else return 0. + */ +int +authdir_policy_baddir_address(uint32_t addr, uint16_t port) +{ + return ! addr_policy_permits_address(addr, port, authdir_baddir_policy); +} + + /** Return 1 if addr:port should be marked as a bad exit, * based on authdir_badexit_policy. Else return 0. */ @@ -289,6 +302,8 @@ policies_parse_from_options(or_options_t *options) &authdir_reject_policy, ADDR_POLICY_REJECT); load_policy_from_option(options->AuthDirInvalid, &authdir_invalid_policy, ADDR_POLICY_REJECT); + load_policy_from_option(options->AuthDirBadDir, + &authdir_baddir_policy, ADDR_POLICY_REJECT); load_policy_from_option(options->AuthDirBadExit, &authdir_badexit_policy, ADDR_POLICY_REJECT); parse_reachable_addresses();