diff --git a/src/or/dirserv.c b/src/or/dirserv.c index fb6b3950b1..be34aab63e 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -235,22 +235,14 @@ dirserv_free_fingerprint_list() * Descriptor list */ -/** List of routerinfo_t for all server descriptors that this dirserv - * is holding. - * XXXX This should eventually get coalesced into routerlist.c - */ -static smartlist_t *descriptor_list = NULL; - -/** Release all storage that the dirserv is holding for server - * descriptors. */ -void -dirserv_free_descriptors() +static smartlist_t * +get_descriptor_list(void) { - if (!descriptor_list) - return; - SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, - routerinfo_free(ri)); - smartlist_clear(descriptor_list); + routerlist_t *routerlist; + router_get_routerlist(&routerlist); + if (!routerlist) + return NULL; + return routerlist->routers; } /** Return -1 if ri has a private or otherwise bad address, @@ -274,6 +266,64 @@ dirserv_router_has_valid_address(routerinfo_t *ri) return 0; } +int +dirserv_wants_to_reject_router(routerinfo_t *ri, int *verified, + const char **msg) +{ + /* Okay. Now check whether the fingerprint is recognized. */ + int r = dirserv_router_fingerprint_is_known(ri); + time_t now; + if (r==-1) { + log_fn(LOG_WARN, "Known nickname '%s', wrong fingerprint. Not adding (ContactInfo '%s', platform '%s').", + ri->nickname, ri->contact_info ? ri->contact_info : "", + ri->platform ? ri->platform : ""); + *msg = "Rejected: There is already a verified server with this nickname and a different fingerprint."; + return -1; + } else if (r==0) { + char fp[FINGERPRINT_LEN+1]; + log_fn(LOG_INFO, "Unknown nickname '%s' (%s:%d). Will try to add.", + ri->nickname, ri->address, ri->or_port); + if (crypto_pk_get_fingerprint(ri->identity_pkey, fp, 1) < 0) { + log_fn(LOG_WARN, "Error computing fingerprint for '%s'", ri->nickname); + } else { + log_fn(LOG_INFO, "Fingerprint line: %s %s", ri->nickname, fp); + } + *verified = 0; + } else { + *verified = 1; + } + /* Is there too much clock skew? */ + now = time(NULL); + if (ri->published_on > now+ROUTER_ALLOW_SKEW) { + log_fn(LOG_NOTICE, "Publication time for nickname '%s' is too far (%d minutes) in the future; possible clock skew. Not adding (ContactInfo '%s', platform '%s').", + ri->nickname, (int)((ri->published_on-now)/60), + ri->contact_info ? ri->contact_info : "", + ri->platform ? ri->platform : ""); + *msg = "Rejected: Your clock is set too far in the future, or your timezone is not correct."; + return -1; + } + if (ri->published_on < now-ROUTER_MAX_AGE) { + log_fn(LOG_NOTICE, "Publication time for router with nickname '%s' is too far (%d minutes) in the past. Not adding (ContactInfo '%s', platform '%s').", + ri->nickname, (int)((now-ri->published_on)/60), + ri->contact_info ? ri->contact_info : "", + ri->platform ? ri->platform : ""); + *msg = "Rejected: Server is expired, or your clock is too far in the past, or your timezone is not correct."; + return -1; + } + if (dirserv_router_has_valid_address(ri) < 0) { + log_fn(LOG_NOTICE, "Router with nickname '%s' has invalid address '%s'. Not adding (ContactInfo '%s', platform '%s').", + ri->nickname, ri->address, + ri->contact_info ? ri->contact_info : "", + ri->platform ? ri->platform : ""); + *msg = "Rejected: Address is not an IP, or IP is a private address."; + return -1; + } + + return 0; +} + + + /** Parse the server descriptor at *desc and maybe insert it into the * list of server descriptors, and (if the descriptor is well-formed) * advance *desc immediately past the descriptor's end. Set msg to a @@ -288,17 +338,12 @@ dirserv_router_has_valid_address(routerinfo_t *ri) int dirserv_add_descriptor(const char **desc, const char **msg) { - routerinfo_t *ri = NULL, *ri_old=NULL; - int i, r, found=-1; + routerinfo_t *ri = NULL; char *start, *end; char *desc_tmp = NULL; size_t desc_len; - time_t now; - int verified=1; /* whether we knew its fingerprint already */ tor_assert(msg); *msg = NULL; - if (!descriptor_list) - descriptor_list = smartlist_create(); start = strstr(*desc, "router "); if (!start) { @@ -323,104 +368,11 @@ dirserv_add_descriptor(const char **desc, const char **msg) *msg = "Rejected: Couldn't parse server descriptor."; return -1; } - /* Okay. Now check whether the fingerprint is recognized. */ - r = dirserv_router_fingerprint_is_known(ri); - if (r==-1) { - log_fn(LOG_WARN, "Known nickname '%s', wrong fingerprint. Not adding (ContactInfo '%s', platform '%s').", - ri->nickname, ri->contact_info ? ri->contact_info : "", - ri->platform ? ri->platform : ""); - *msg = "Rejected: There is already a verified server with this nickname and a different fingerprint."; - routerinfo_free(ri); - *desc = end; + if (router_add_to_routerlist(ri, msg)) { return -1; - } else if (r==0) { - char fp[FINGERPRINT_LEN+1]; - log_fn(LOG_INFO, "Unknown nickname '%s' (%s:%d). Will try to add.", - ri->nickname, ri->address, ri->or_port); - if (crypto_pk_get_fingerprint(ri->identity_pkey, fp, 1) < 0) { - log_fn(LOG_WARN, "Error computing fingerprint for '%s'", ri->nickname); - } else { - log_fn(LOG_INFO, "Fingerprint line: %s %s", ri->nickname, fp); - } - verified = 0; - } - /* Is there too much clock skew? */ - now = time(NULL); - if (ri->published_on > now+ROUTER_ALLOW_SKEW) { - log_fn(LOG_NOTICE, "Publication time for nickname '%s' is too far (%d minutes) in the future; possible clock skew. Not adding (ContactInfo '%s', platform '%s').", - ri->nickname, (int)((ri->published_on-now)/60), - ri->contact_info ? ri->contact_info : "", - ri->platform ? ri->platform : ""); - *msg = "Rejected: Your clock is set too far in the future, or your timezone is not correct."; - routerinfo_free(ri); - *desc = end; - return -1; - } - if (ri->published_on < now-ROUTER_MAX_AGE) { - log_fn(LOG_NOTICE, "Publication time for router with nickname '%s' is too far (%d minutes) in the past. Not adding (ContactInfo '%s', platform '%s').", - ri->nickname, (int)((now-ri->published_on)/60), - ri->contact_info ? ri->contact_info : "", - ri->platform ? ri->platform : ""); - *msg = "Rejected: Server is expired, or your clock is too far in the past, or your timezone is not correct."; - routerinfo_free(ri); - *desc = end; - return -1; - } - if (dirserv_router_has_valid_address(ri) < 0) { - log_fn(LOG_NOTICE, "Router with nickname '%s' has invalid address '%s'. Not adding (ContactInfo '%s', platform '%s').", - ri->nickname, ri->address, - ri->contact_info ? ri->contact_info : "", - ri->platform ? ri->platform : ""); - *msg = "Rejected: Address is not an IP, or IP is a private address."; - routerinfo_free(ri); - *desc = end; - return -1; - } - - /* Do we already have an entry for this router? */ - for (i = 0; i < smartlist_len(descriptor_list); ++i) { - ri_old = smartlist_get(descriptor_list, i); - if (!memcmp(ri->identity_digest, ri_old->identity_digest, DIGEST_LEN)) { - found = i; - break; - } - } - if (found >= 0) { - char hex_digest[HEX_DIGEST_LEN+1]; - base16_encode(hex_digest, HEX_DIGEST_LEN+1, ri->identity_digest,DIGEST_LEN); - /* if so, decide whether to update it. */ - if (ri_old->published_on >= ri->published_on) { - /* We already have a newer or equal-time descriptor */ - log_fn(LOG_INFO,"We already have a new enough desc for server %s (nickname '%s'). Not adding.",hex_digest,ri->nickname); - *msg = "We already have a newer descriptor."; - /* This isn't really an error; return success. */ - routerinfo_free(ri); - *desc = end; - return verified; - } - /* We don't already have a newer one; we'll update this one. */ - log_fn(LOG_INFO,"Dirserv updating desc for server %s (nickname '%s')",hex_digest,ri->nickname); - if (ri->addr == ri_old->addr && ri->or_port == ri_old->or_port) { - ri->last_reachable = ri_old->last_reachable; /* these carry over */ - ri->testing_since = ri_old->testing_since; - } - *msg = verified?"Verified server updated":"Unverified server updated. (Have you sent us your key fingerprint?)"; - routerinfo_free(ri_old); - smartlist_del_keeporder(descriptor_list, found); } else { - /* Add at the end. */ - log_fn(LOG_INFO,"Dirserv adding desc for nickname '%s'",ri->nickname); - *msg = verified?"Verified server added":"Unverified server added. (Have you sent us your key fingerprint?)"; + return ri->is_verified ? 1 : 0; } - - ri->is_verified = verified || - tor_version_as_new_as(ri->platform,"0.1.0.2-rc"); - smartlist_add(descriptor_list, ri); - - *desc = end; - directory_set_dirty(); - - return verified; } /** Remove all descriptors whose nicknames or fingerprints no longer @@ -431,27 +383,33 @@ static void directory_remove_invalid(void) { int i; - int r; - routerinfo_t *ent; + int changed = 0; + smartlist_t *descriptor_list = get_descriptor_list(); + if (!descriptor_list) - descriptor_list = smartlist_create(); + return; for (i = 0; i < smartlist_len(descriptor_list); ++i) { - ent = smartlist_get(descriptor_list, i); - r = dirserv_router_fingerprint_is_known(ent); + routerinfo_t *ent = smartlist_get(descriptor_list, i); + int r = dirserv_router_fingerprint_is_known(ent); if (r<0) { log(LOG_INFO, "Router '%s' is now verified with a key; removing old router with same name and different key.", ent->nickname); routerinfo_free(ent); smartlist_del(descriptor_list, i--); + changed = 1; } else if (r>0 && !ent->is_verified) { log(LOG_INFO, "Router '%s' is now approved.", ent->nickname); ent->is_verified = 1; + changed = 1; } else if (r==0 && ent->is_verified) { log(LOG_INFO, "Router '%s' is no longer approved.", ent->nickname); ent->is_verified = 0; + changed = 1; } } + if (changed) + directory_set_dirty(); } /** Write a list of unregistered descriptors into a newly allocated @@ -467,6 +425,7 @@ dirserver_getinfo_unregistered(const char *question) char *answer; routerinfo_t *ent; int min_bw = atoi(question); + smartlist_t *descriptor_list = get_descriptor_list(); if (!descriptor_list) return tor_strdup(""); @@ -608,7 +567,11 @@ list_server_status(smartlist_t *routers, char **router_status_out) * been found unreachable for the past several testing periods. */ void -dirserv_log_unreachable_servers(time_t now) { +dirserv_log_unreachable_servers(time_t now) +{ + smartlist_t *descriptor_list = get_descriptor_list(); + if (!descriptor_list) + return; SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, { @@ -631,7 +594,9 @@ dirserv_log_unreachable_servers(time_t now) { * (This function can go away when we merge descriptor-list and router-list.) */ void -dirserv_router_has_begun_reachability_testing(char *digest, time_t now) { +dirserv_router_has_begun_reachability_testing(char *digest, time_t now) +{ + smartlist_t *descriptor_list = get_descriptor_list(); if (!descriptor_list) return; SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, @@ -642,30 +607,6 @@ dirserv_router_has_begun_reachability_testing(char *digest, time_t now) { }); } -/** Remove any descriptors from the directory that are more than age - * seconds old. - */ -void -dirserv_remove_old_servers(int age) -{ - int i; - time_t cutoff; - routerinfo_t *ent; - if (!descriptor_list) - descriptor_list = smartlist_create(); - - cutoff = time(NULL) - age; - for (i = 0; i < smartlist_len(descriptor_list); ++i) { - ent = smartlist_get(descriptor_list, i); - if (ent->published_on <= cutoff) { - /* descriptor_list[i] is too old. Remove it. */ - routerinfo_free(ent); - smartlist_del(descriptor_list, i--); - directory_set_dirty(); - } - } -} - /* Given a (possibly empty) list of config_line_t, each line of which contains * a list of comma-separated version numbers surrounded by optional space, * allocate and return a new string containing the version numbers, in order, @@ -704,12 +645,13 @@ dirserv_dump_directory_to_string(char **dir_out, char *buf = NULL; size_t buf_len; size_t identity_pkey_len; + smartlist_t *descriptor_list = get_descriptor_list(); tor_assert(dir_out); *dir_out = NULL; if (!descriptor_list) - descriptor_list = smartlist_create(); + return -1; if (list_server_status(descriptor_list, &router_status)) return -1; @@ -722,14 +664,13 @@ dirserv_dump_directory_to_string(char **dir_out, recommended_versions = format_versions_list(get_options()->RecommendedVersions); - dirserv_remove_old_servers(ROUTER_MAX_AGE); published_on = time(NULL); format_iso_time(published, published_on); buf_len = 2048+strlen(recommended_versions)+ strlen(router_status); SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, - buf_len += strlen(ri->signed_descriptor)); + buf_len += ri->signed_descriptor_len); buf = tor_malloc(buf_len); /* We'll be comparing against buf_len throughout the rest of the function, though strictly speaking we shouldn't be able to exceed @@ -997,9 +938,7 @@ generate_runningrouters(void) crypto_pk_env_t *private_key = get_identity_key(); char *identity_pkey; /* Identity key, DER64-encoded. */ size_t identity_pkey_len; - - if (!descriptor_list) - descriptor_list = smartlist_create(); + smartlist_t *descriptor_list = get_descriptor_list(); if (list_server_status(descriptor_list, &router_status)) { goto err; @@ -1113,6 +1052,12 @@ generate_v2_networkstatus(void) struct in_addr in; uint32_t addr; crypto_pk_env_t *private_key = get_identity_key(); + smartlist_t *descriptor_list = get_descriptor_list(); + + if (!descriptor_list) { + log_fn(LOG_WARN, "Couldn't get router list."); + goto done; + } if (resolve_my_address(options, &addr, &hostname)<0) { log_fn(LOG_WARN, "Couldn't resolve my hostname"); @@ -1285,22 +1230,12 @@ dirserv_get_networkstatus_v2(const char **directory, const char *key, void dirserv_get_routerdescs(smartlist_t *descs_out, const char *key) { - smartlist_t *complete_list; - - /* This is annoying. Can we unify these? */ - if (descriptor_list) - complete_list = descriptor_list; - else { - routerlist_t *rlst; - router_get_routerlist(&rlst); - complete_list = rlst->routers; - } - + smartlist_t *complete_list = get_descriptor_list(); if (!complete_list) return; if (!strcmp(key, "/tor/server/all")) { - smartlist_add_all(descs_out, descriptor_list); + smartlist_add_all(descs_out, complete_list); } else if (!strcmp(key, "/tor/server/authority")) { routerinfo_t *ri = router_get_my_routerinfo(); if (ri) @@ -1323,7 +1258,7 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key) smartlist_free(hexdigests); /* XXXX should always return own descriptor. or special-case it. or * something. */ - SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, + SMARTLIST_FOREACH(complete_list, routerinfo_t *, ri, SMARTLIST_FOREACH(digests, const char *, d, if (!memcmp(d,ri->identity_digest,DIGEST_LEN)) { smartlist_add(descs_out,ri); @@ -1352,6 +1287,7 @@ dirserv_orconn_tls_done(const char *address, int as_advertised) { int i; + smartlist_t *descriptor_list = get_descriptor_list(); tor_assert(address); tor_assert(digest_rcvd); tor_assert(nickname_rcvd); @@ -1359,6 +1295,8 @@ dirserv_orconn_tls_done(const char *address, if (!descriptor_list) return; + // XXXXNM We should really have a better solution here than dropping + // XXXXNM whole routers; otherwise, they come back way too easily. for (i = 0; i < smartlist_len(descriptor_list); ++i) { routerinfo_t *ri = smartlist_get(descriptor_list, i); int drop = 0; @@ -1399,12 +1337,6 @@ dirserv_free_all(void) smartlist_free(fingerprint_list); fingerprint_list = NULL; } - if (descriptor_list) { - SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri, - routerinfo_free(ri)); - smartlist_free(descriptor_list); - descriptor_list = NULL; - } clear_cached_dir(&the_directory); clear_cached_dir(&the_runningrouters); clear_cached_dir(&cached_directory); diff --git a/src/or/main.c b/src/or/main.c index ed35987d2b..105e792ab5 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -692,8 +692,6 @@ run_scheduled_events(time_t now) routerlist_remove_old_routers(ROUTER_MAX_AGE); if (authdir_mode(options)) { - /* Dump any old descriptors. */ - dirserv_remove_old_servers(ROUTER_MAX_AGE); dirserv_log_unreachable_servers(now); if (!we_are_hibernating()) { /* try to determine reachability */ router_retry_connections(1); diff --git a/src/or/or.h b/src/or/or.h index 405881a150..621dd31141 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -736,15 +736,16 @@ typedef struct { addr_policy_t *exit_policy; /**< What streams will this OR permit * to exit? */ long uptime; /**< How many seconds the router claims to have been up */ + smartlist_t *declared_family; /**< Nicknames of router which this router + * claims are its family. */ + char *contact_info; /**< Declared contact info for this router. */ + /* local info */ int is_running; /**< As far as we know, is this OR currently running? */ time_t status_set_at; /**< When did we last update is_running? */ - int is_verified; /**< Has a trusted dirserver validated this OR? */ - - smartlist_t *declared_family; /**< Nicknames of router which this router - * claims are its family. */ - - char *contact_info; /**< Declared contact info for this router. */ + int is_verified; /**< Has a trusted dirserver validated this OR? + * (For Authdir: Have we validated this OR?) + */ /* The below items are used only by authdirservers right now for * reachability testing. */ @@ -1636,7 +1637,6 @@ void dirserv_free_descriptors(void); int list_server_status(smartlist_t *routers, char **router_status_out); void dirserv_log_unreachable_servers(time_t now); void dirserv_router_has_begun_reachability_testing(char *digest, time_t now); -void dirserv_remove_old_servers(int age); int dirserv_dump_directory_to_string(char **dir_out, crypto_pk_env_t *private_key); void directory_set_dirty(void); @@ -1654,6 +1654,8 @@ void dirserv_orconn_tls_done(const char *address, const char *digest_rcvd, const char *nickname, int as_advertised); +int dirserv_wants_to_reject_router(routerinfo_t *ri, int *verified, + const char **msg); void dirserv_free_all(void); /********************************* dns.c ***************************/ @@ -1991,6 +1993,7 @@ void free_trusted_dir_servers(void); routerinfo_t *routerinfo_copy(const routerinfo_t *router); void router_mark_as_down(const char *digest); void routerlist_remove_old_routers(int age); +int router_add_to_routerlist(routerinfo_t *router, const char **msg); int router_load_single_router(const char *s, const char **msg); int router_load_routerlist_from_directory(const char *s,crypto_pk_env_t *pkey, int dir_is_recent, int dir_is_cached); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 802784688d..b38b9bd1a8 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -861,40 +861,59 @@ router_mark_as_down(const char *digest) * *msg a static string describing the reason for refusing the * routerinfo. */ -static int +int router_add_to_routerlist(routerinfo_t *router, const char **msg) { int i; - routerinfo_t *r; char id_digest[DIGEST_LEN]; + int authdir = get_options()->AuthoritativeDir; + int authdir_verified = 0; tor_assert(routerlist); crypto_pk_get_digest(router->identity_pkey, id_digest); + if (authdir) { + if (dirserv_wants_to_reject_router(router, &authdir_verified, msg)) + return -1; + router->is_verified = authdir_verified; + if (tor_version_as_new_as(router->platform,"0.1.0.2-rc")) + router->is_verified = 1; + } + /* If we have a router with this name, and the identity key is the same, * choose the newer one. If the identity key has changed, drop the router. */ for (i = 0; i < smartlist_len(routerlist->routers); ++i) { - r = smartlist_get(routerlist->routers, i); - - if (!crypto_pk_cmp_keys(router->identity_pkey, r->identity_pkey)) { - if (router->published_on > r->published_on) { - log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]", - router->nickname, r->nickname, hex_str(id_digest,DIGEST_LEN)); -//XXXRD /* Remember whether we trust this router as a dirserver. */ - routerinfo_free(r); - smartlist_set(routerlist->routers, i, router); - return 0; - } else { + routerinfo_t *old_router = smartlist_get(routerlist->routers, i); + if (!crypto_pk_cmp_keys(router->identity_pkey,old_router->identity_pkey)) { + if (router->published_on <= old_router->published_on) { log_fn(LOG_DEBUG, "Skipping not-new descriptor for router '%s'", router->nickname); - /* Update the is_running status to whatever we were told. */ - r->is_running = router->is_running; + if (!authdir) + /* Update the is_running status to whatever we were told. */ + old_router->is_running = router->is_running; routerinfo_free(router); if (msg) *msg = "Router descriptor was not new."; return -1; + } else { + log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]", + router->nickname, old_router->nickname, + hex_str(id_digest,DIGEST_LEN)); + if (router->addr == old_router->addr && + router->or_port == old_router->or_port) { + /* these carry over when the address and orport are unchanged.*/ + router->last_reachable = old_router->last_reachable; + router->testing_since = old_router->testing_since; + } + if (msg) + *msg = authdir_verified ? "Verified server updated": + "Unverified server updated. (Have you sent us your key finerprint?)"; + routerinfo_free(old_router); + smartlist_set(routerlist->routers, i, router); + directory_set_dirty(); + return 0; } - } else if (!strcasecmp(router->nickname, r->nickname)) { + } else if (!strcasecmp(router->nickname, old_router->nickname)) { /* nicknames match, keys don't. */ if (router->is_verified) { /* The new verified router replaces the old one; remove the @@ -905,14 +924,15 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg) * make new ones with the new key. */ connection_t *conn; - while ((conn = connection_get_by_identity_digest(r->identity_digest, - CONN_TYPE_OR))) { - log_fn(LOG_INFO,"Closing conn to obsolete router '%s'", r->nickname); + while ((conn = connection_get_by_identity_digest( + old_router->identity_digest, CONN_TYPE_OR))) { + log_fn(LOG_INFO,"Closing conn to obsolete router '%s'", + old_router->nickname); connection_mark_for_close(conn); } - routerinfo_free(r); + routerinfo_free(old_router); smartlist_del_keeporder(routerlist->routers, i--); - } else if (r->is_verified) { + } else if (old_router->is_verified) { /* Can't replace a verified router with an unverified one. */ log_fn(LOG_DEBUG, "Skipping unverified entry for verified router '%s'", router->nickname); @@ -925,16 +945,13 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg) /* We haven't seen a router with this name before. Add it to the end of * the list. */ smartlist_add(routerlist->routers, router); + directory_set_dirty(); return 0; } /** Remove any routers from the routerlist that are more than age * seconds old. - * - * (This function is just like dirserv_remove_old_servers. One day we should - * merge them.) */ -//XXXRD void routerlist_remove_old_routers(int age) { @@ -956,7 +973,7 @@ routerlist_remove_old_routers(int age) } } -/* +/** * Code to parse a single router descriptor and insert it into the * routerlist. Return -1 if the descriptor was ill-formed; 0 if the * descriptor was well-formed but could not be added; and 1 if the @@ -965,6 +982,8 @@ routerlist_remove_old_routers(int age) * If we don't add it and msg is not NULL, then assign to * *msg a static string describing the reason for refusing the * descriptor. + * + * This is used only by the controller. */ int router_load_single_router(const char *s, const char **msg) @@ -1350,6 +1369,7 @@ routers_update_status_from_entry(smartlist_t *routers, time_t list_time, const char *s) { + int authdir = get_options()->AuthoritativeDir; int is_running = 1; int is_verified = 0; int hex_digest_set = 0; @@ -1421,13 +1441,22 @@ routers_update_status_from_entry(smartlist_t *routers, { int nickname_matches = is_verified && !strcasecmp(r->nickname, nickname); int digest_matches = !memcmp(digest, r->identity_digest, DIGEST_LEN); - if (nickname_matches && digest_matches) - r->is_verified = 1; - else if (digest_matches) - r->is_verified = 0; + if (!authdir) { + /* If we're not an authoritative directory, update verified status. + */ + if (nickname_matches && digest_matches) + r->is_verified = 1; + else if (digest_matches) + r->is_verified = 0; + } if (digest_matches) if (r->status_set_at < list_time) { - r->is_running = is_running; + if (!authdir || is_running) + /* If we're an authoritative directory, only believe that servers + * are down when we hear it ourselves. Otherwise, believe + * what we're told. + */ + r->is_running = is_running; r->status_set_at = time(NULL); } });