diff options
Diffstat (limited to 'src/or/dirserv.c')
-rw-r--r-- | src/or/dirserv.c | 226 |
1 files changed, 161 insertions, 65 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c index aa2e74b0b..be62459b1 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -212,7 +212,7 @@ dirserv_load_fingerprint_file(void) authdir_config_t *fingerprint_list_new; int result; config_line_t *front=NULL, *list; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); fname = get_datadir_fname("approved-routers"); log_info(LD_GENERAL, @@ -518,14 +518,15 @@ dirserv_router_has_valid_address(routerinfo_t *ri) if (get_options()->DirAllowPrivateAddresses) return 0; /* whatever it is, we're fine with it */ if (!tor_inet_aton(ri->address, &iaddr)) { - log_info(LD_DIRSERV,"Router '%s' published non-IP address '%s'. Refusing.", - ri->nickname, ri->address); + log_info(LD_DIRSERV,"Router %s published non-IP address '%s'. Refusing.", + router_describe(ri), + ri->address); return -1; } if (is_internal_IP(ntohl(iaddr.s_addr), 0)) { log_info(LD_DIRSERV, - "Router '%s' published internal IP address '%s'. Refusing.", - ri->nickname, ri->address); + "Router %s published internal IP address '%s'. Refusing.", + router_describe(ri), ri->address); return -1; /* it's a private IP, we should reject it */ } return 0; @@ -554,10 +555,11 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, /* Is there too much clock skew? */ now = time(NULL); if (ri->cache_info.published_on > now+ROUTER_ALLOW_SKEW) { - log_fn(severity, LD_DIRSERV, "Publication time for nickname '%s' is too " + log_fn(severity, LD_DIRSERV, "Publication time for %s is too " "far (%d minutes) in the future; possible clock skew. Not adding " "(%s)", - ri->nickname, (int)((ri->cache_info.published_on-now)/60), + router_describe(ri), + (int)((ri->cache_info.published_on-now)/60), esc_router_info(ri)); *msg = "Rejected: Your clock is set too far in the future, or your " "timezone is not correct."; @@ -565,9 +567,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, } if (ri->cache_info.published_on < now-ROUTER_MAX_AGE_TO_PUBLISH) { log_fn(severity, LD_DIRSERV, - "Publication time for router with nickname '%s' is too far " + "Publication time for %s is too far " "(%d minutes) in the past. Not adding (%s)", - ri->nickname, (int)((now-ri->cache_info.published_on)/60), + router_describe(ri), + (int)((now-ri->cache_info.published_on)/60), esc_router_info(ri)); *msg = "Rejected: Server is expired, or your clock is too far in the past," " or your timezone is not correct."; @@ -575,9 +578,10 @@ authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, } if (dirserv_router_has_valid_address(ri) < 0) { log_fn(severity, LD_DIRSERV, - "Router with nickname '%s' has invalid address '%s'. " + "Router %s has invalid address '%s'. " "Not adding (%s).", - ri->nickname, ri->address, + router_describe(ri), + ri->address, esc_router_info(ri)); *msg = "Rejected: Address is not an IP, or IP is a private address."; return -1; @@ -729,9 +733,9 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) && router_differences_are_cosmetic(ri_old, ri) && !router_is_me(ri)) { log_info(LD_DIRSERV, - "Not replacing descriptor from '%s' (source: %s); " + "Not replacing descriptor from %s (source: %s); " "differences are cosmetic.", - ri->nickname, source); + router_describe(ri), source); *msg = "Not replacing router descriptor; no information has changed since " "the last one with this identity."; control_event_or_authdir_new_descriptor("DROPPED", @@ -831,13 +835,15 @@ directory_remove_invalid(void) SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) { const char *msg; routerinfo_t *ent = node->ri; + char description[NODE_DESC_BUF_LEN]; uint32_t r; if (!ent) continue; r = dirserv_router_get_status(ent, &msg); + router_get_description(description, ent); if (r & FP_REJECT) { - log_info(LD_DIRSERV, "Router '%s' is now rejected: %s", - ent->nickname, msg?msg:""); + log_info(LD_DIRSERV, "Router %s is now rejected: %s", + description, msg?msg:""); routerlist_remove(rl, ent, 0, time(NULL)); changed = 1; continue; @@ -845,33 +851,33 @@ directory_remove_invalid(void) #if 0 if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) { log_info(LD_DIRSERV, - "Router '%s' is now %snamed.", ent->nickname, + "Router %s is now %snamed.", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NAMED)?1:0; changed = 1; } if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) { log_info(LD_DIRSERV, - "Router '%s' is now %snamed. (FP_UNNAMED)", ent->nickname, + "Router '%s' is now %snamed. (FP_UNNAMED)", description, (r&FP_NAMED)?"":"un"); ent->is_named = (r&FP_NUNAMED)?0:1; changed = 1; } #endif if (bool_neq((r & FP_INVALID), !node->is_valid)) { - log_info(LD_DIRSERV, "Router '%s' is now %svalid.", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description, (r&FP_INVALID) ? "in" : ""); node->is_valid = (r&FP_INVALID)?0:1; changed = 1; } if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) { - log_info(LD_DIRSERV, "Router '%s' is now a %s directory", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description, (r & FP_BADDIR) ? "bad" : "good"); node->is_bad_directory = (r&FP_BADDIR) ? 1: 0; changed = 1; } if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) { - log_info(LD_DIRSERV, "Router '%s' is now a %s exit", ent->nickname, + log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description, (r & FP_BADEXIT) ? "bad" : "good"); node->is_bad_exit = (r&FP_BADEXIT) ? 1: 0; changed = 1; @@ -1026,7 +1032,7 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out, smartlist_t *rs_entries; time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); /* We include v2 dir auths here too, because they need to answer * controllers. Eventually we'll deprecate this whole function; * see also networkstatus_getinfo_by_purpose(). */ @@ -1193,7 +1199,7 @@ dirserv_dump_directory_to_string(char **dir_out, /** Return 1 if we fetch our directory material directly from the * authorities, rather than from a mirror. */ int -directory_fetches_from_authorities(or_options_t *options) +directory_fetches_from_authorities(const or_options_t *options) { const routerinfo_t *me; uint32_t addr; @@ -1220,7 +1226,7 @@ directory_fetches_from_authorities(or_options_t *options) * on the "mirror" schedule rather than the "client" schedule. */ int -directory_fetches_dir_info_early(or_options_t *options) +directory_fetches_dir_info_early(const or_options_t *options) { return directory_fetches_from_authorities(options); } @@ -1232,7 +1238,7 @@ directory_fetches_dir_info_early(or_options_t *options) * client as a directory guard. */ int -directory_fetches_dir_info_later(or_options_t *options) +directory_fetches_dir_info_later(const or_options_t *options) { return options->UseBridges != 0; } @@ -1240,7 +1246,7 @@ directory_fetches_dir_info_later(or_options_t *options) /** Return 1 if we want to cache v2 dir info (each status file). */ int -directory_caches_v2_dir_info(or_options_t *options) +directory_caches_v2_dir_info(const or_options_t *options) { return options->DirPort != 0; } @@ -1249,7 +1255,7 @@ directory_caches_v2_dir_info(or_options_t *options) * and we're willing to serve them to others. Else return 0. */ int -directory_caches_dir_info(or_options_t *options) +directory_caches_dir_info(const or_options_t *options) { if (options->BridgeRelay || options->DirPort) return 1; @@ -1265,7 +1271,7 @@ directory_caches_dir_info(or_options_t *options) * requests via the "begin_dir" interface, which doesn't require * having any separate port open. */ int -directory_permits_begindir_requests(or_options_t *options) +directory_permits_begindir_requests(const or_options_t *options) { return options->BridgeRelay != 0 || options->DirPort != 0; } @@ -1274,7 +1280,7 @@ directory_permits_begindir_requests(or_options_t *options) * requests via the controller interface, which doesn't require * having any separate port open. */ int -directory_permits_controller_requests(or_options_t *options) +directory_permits_controller_requests(const or_options_t *options) { return options->DirPort != 0; } @@ -1284,7 +1290,8 @@ directory_permits_controller_requests(or_options_t *options) * lately. */ int -directory_too_idle_to_fetch_descriptors(or_options_t *options, time_t now) +directory_too_idle_to_fetch_descriptors(const or_options_t *options, + time_t now) { return !directory_caches_dir_info(options) && !options->FetchUselessDescriptors && @@ -1554,7 +1561,7 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src, const char *name, dirinfo_type_t auth_type) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)) || (auth_type == V2_DIRINFO && authdir_mode_v2(options)); @@ -1713,12 +1720,6 @@ should_generate_v2_networkstatus(void) /** If a router's MTBF is at least this value, then it is always stable. * See above. (Corresponds to about 7 days for current decay rates.) */ #define MTBF_TO_GUARANTEE_STABLE (60*60*24*5) -/** Similarly, we protect sufficiently fast nodes from being pushed - * out of the set of Fast nodes. */ -#define BANDWIDTH_TO_GUARANTEE_FAST ROUTER_REQUIRED_MIN_BANDWIDTH -/** Similarly, every node with sufficient bandwidth can be considered - * for Guard status. */ -#define BANDWIDTH_TO_GUARANTEE_GUARD (250*1024) /** Similarly, every node with at least this much weighted time known can be * considered familiar enough to be a guard. Corresponds to about 20 days for * current decay rates. @@ -1863,6 +1864,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl) long *tks; double *mtbfs, *wfus; time_t now = time(NULL); + const or_options_t *options = get_options(); /* initialize these all here, in case there are no routers */ stable_uptime = 0; @@ -1935,8 +1937,11 @@ dirserv_compute_performance_thresholds(routerlist_t *rl) if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR) guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR; - if (fast_bandwidth > BANDWIDTH_TO_GUARANTEE_FAST) - fast_bandwidth = BANDWIDTH_TO_GUARANTEE_FAST; + /* Protect sufficiently fast nodes from being pushed out of the set + * of Fast nodes. */ + if (options->AuthDirFastGuarantee && + fast_bandwidth > options->AuthDirFastGuarantee) + fast_bandwidth = (uint32_t)options->AuthDirFastGuarantee; /* Now that we have a time-known that 7/8 routers are known longer than, * fill wfus with the wfu of every such "familiar" router. */ @@ -2245,7 +2250,7 @@ _compare_routerinfo_by_ip_and_bw(const void **a, const void **b) static digestmap_t * get_possible_sybil_list(const smartlist_t *routers) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); digestmap_t *omit_as_sybil; smartlist_t *routers_by_ip = smartlist_create(); uint32_t last_addr; @@ -2281,6 +2286,75 @@ get_possible_sybil_list(const smartlist_t *routers) return omit_as_sybil; } +/** Return non-zero iff a relay running the Tor version specified in + * <b>platform</b> is suitable for use as a potential entry guard. */ +static int +is_router_version_good_for_possible_guard(const char *platform) +{ + static int parsed_versions_initialized = 0; + static tor_version_t first_good_0_2_1_guard_version; + static tor_version_t first_good_0_2_2_guard_version; + static tor_version_t first_good_later_guard_version; + + tor_version_t router_version; + + /* XXX023 This block should be extracted into its own function. */ + /* XXXX Begin code copied from tor_version_as_new_as (in routerparse.c) */ + { + char *s, *s2, *start; + char tmp[128]; + + tor_assert(platform); + + /* nonstandard Tor; be safe and say yes */ + if (strcmpstart(platform,"Tor ")) + return 1; + + start = (char *)eat_whitespace(platform+3); + if (!*start) return 0; + s = (char *)find_whitespace(start); /* also finds '\0', which is fine */ + s2 = (char*)eat_whitespace(s); + if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-")) + s = (char*)find_whitespace(s2); + + if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */ + return 0; + strlcpy(tmp, start, s-start+1); + + if (tor_version_parse(tmp, &router_version)<0) { + log_info(LD_DIR,"Router version '%s' unparseable.",tmp); + return 1; /* be safe and say yes */ + } + } + /* XXXX End code copied from tor_version_as_new_as (in routerparse.c) */ + + if (!parsed_versions_initialized) { + /* CVE-2011-2769 was fixed on the relay side in Tor versions + * 0.2.1.31, 0.2.2.34, and 0.2.3.6-alpha. */ + tor_assert(tor_version_parse("0.2.1.31", + &first_good_0_2_1_guard_version)>=0); + tor_assert(tor_version_parse("0.2.2.34", + &first_good_0_2_2_guard_version)>=0); + tor_assert(tor_version_parse("0.2.3.6-alpha", + &first_good_later_guard_version)>=0); + + /* Don't parse these constant version strings once for every relay + * for every vote. */ + parsed_versions_initialized = 1; + } + + return ((tor_version_same_series(&first_good_0_2_1_guard_version, + &router_version) && + tor_version_compare(&first_good_0_2_1_guard_version, + &router_version) <= 0) || + (tor_version_same_series(&first_good_0_2_2_guard_version, + &router_version) && + tor_version_compare(&first_good_0_2_2_guard_version, + &router_version) <= 0) || + (tor_version_compare(&first_good_later_guard_version, + &router_version) <= 0)); +} + /** Extract status information from <b>ri</b> and from other authority * functions and store it in <b>rs</b>>. If <b>naming</b>, consider setting * the named flag in <b>rs</b>. @@ -2294,10 +2368,13 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, routerinfo_t *ri, time_t now, int naming, int listbadexits, - int listbaddirs) + int listbaddirs, int vote_on_hsdirs) { + const or_options_t *options = get_options(); int unstable_version = !tor_version_as_new_as(ri->platform,"0.1.1.16-rc-cvs"); + uint32_t routerbw = router_get_advertised_bandwidth(ri); + memset(rs, 0, sizeof(routerstatus_t)); rs->is_authority = @@ -2323,20 +2400,25 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, rs->is_valid = node->is_valid; if (node->is_fast && - (router_get_advertised_bandwidth(ri) >= BANDWIDTH_TO_GUARANTEE_GUARD || - router_get_advertised_bandwidth(ri) >= - MIN(guard_bandwidth_including_exits, - guard_bandwidth_excluding_exits))) { - long tk = rep_hist_get_weighted_time_known(node->identity, now); - double wfu = rep_hist_get_weighted_fractional_uptime(node->identity, now); + ((options->AuthDirGuardBWGuarantee && + routerbw >= options->AuthDirGuardBWGuarantee) || + routerbw >= MIN(guard_bandwidth_including_exits, + guard_bandwidth_excluding_exits)) && + (options->GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays || + is_router_version_good_for_possible_guard(ri->platform))) { + long tk = rep_hist_get_weighted_time_known( + node->identity, now); + double wfu = rep_hist_get_weighted_fractional_uptime( + node->identity, now); rs->is_possible_guard = (wfu >= guard_wfu && tk >= guard_tk) ? 1 : 0; } else { rs->is_possible_guard = 0; } + rs->is_bad_directory = listbaddirs && node->is_bad_directory; rs->is_bad_exit = listbadexits && node->is_bad_exit; node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now); - rs->is_hs_dir = node->is_hs_dir; + rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir; rs->is_v2_dir = ri->dir_port != 0; if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME)) @@ -2433,7 +2515,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) tor_free(line); return -1; } - strncpy(out->node_hex, cp, sizeof(out->node_hex)); + strlcpy(out->node_hex, cp, sizeof(out->node_hex)); got_node_id=1; } } while ((cp = tor_strtok_r(NULL, " \t", &strtok_state))); @@ -2545,7 +2627,7 @@ networkstatus_t * dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, authority_cert_t *cert) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); networkstatus_t *v3_out = NULL; uint32_t addr; char *hostname = NULL, *client_versions = NULL, *server_versions = NULL; @@ -2556,6 +2638,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, int naming = options->NamingAuthoritativeDir; int listbadexits = options->AuthDirListBadExits; int listbaddirs = options->AuthDirListBadDirs; + int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; routerlist_t *rl = router_get_routerlist(); time_t now = time(NULL); time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; @@ -2622,7 +2705,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, vrs = tor_malloc_zero(sizeof(vote_routerstatus_t)); rs = &vrs->status; set_routerstatus_from_routerinfo(rs, node, ri, now, - naming, listbadexits, listbaddirs); + naming, listbadexits, listbaddirs, + vote_on_hsdirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(rs); @@ -2699,7 +2783,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, v3_out->server_versions = server_versions; v3_out->known_flags = smartlist_create(); smartlist_split_string(v3_out->known_flags, - "Authority Exit Fast Guard HSDir Stable V2Dir Valid", + "Authority Exit Fast Guard Stable V2Dir Valid", 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (vote_on_reachability) smartlist_add(v3_out->known_flags, tor_strdup("Running")); @@ -2711,6 +2795,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, smartlist_add(v3_out->known_flags, tor_strdup("Named")); smartlist_add(v3_out->known_flags, tor_strdup("Unnamed")); } + if (vote_on_hsdirs) + smartlist_add(v3_out->known_flags, tor_strdup("HSDir")); smartlist_sort_strings(v3_out->known_flags); if (options->ConsensusParams) { @@ -2726,7 +2812,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key, voter->sigs = smartlist_create(); voter->address = hostname; voter->addr = addr; - voter->dir_port = router_get_advertised_dir_port(options); + voter->dir_port = router_get_advertised_dir_port(options, 0); voter->or_port = router_get_advertised_or_port(options); voter->contact = tor_strdup(contact); if (options->V3AuthUseLegacyKey) { @@ -2760,7 +2846,7 @@ generate_v2_networkstatus_opinion(void) char *status = NULL, *client_versions = NULL, *server_versions = NULL, *identity_pkey = NULL, *hostname = NULL; char *outp, *endp; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char fingerprint[FINGERPRINT_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; @@ -2773,6 +2859,7 @@ generate_v2_networkstatus_opinion(void) int versioning = options->VersioningAuthoritativeDir; int listbaddirs = options->AuthDirListBadDirs; int listbadexits = options->AuthDirListBadExits; + int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2; const char *contact; char *version_lines = NULL; smartlist_t *routers = NULL; @@ -2801,7 +2888,7 @@ generate_v2_networkstatus_opinion(void) goto done; } - contact = get_options()->ContactInfo; + contact = options->ContactInfo; if (!contact) contact = "(none)"; @@ -2830,7 +2917,7 @@ generate_v2_networkstatus_opinion(void) "%s" /* client version line, server version line. */ "dir-signing-key\n%s", hostname, fmt_addr32(addr), - (int)router_get_advertised_dir_port(options), + (int)router_get_advertised_dir_port(options, 0), fingerprint, contact, published, @@ -2867,7 +2954,8 @@ generate_v2_networkstatus_opinion(void) continue; } set_routerstatus_from_routerinfo(&rs, node, ri, now, - naming, listbadexits, listbaddirs); + naming, listbadexits, listbaddirs, + vote_on_hsdirs); if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(&rs); @@ -2883,7 +2971,7 @@ generate_v2_networkstatus_opinion(void) }); if (tor_snprintf(outp, endp-outp, "directory-signature %s\n", - get_options()->Nickname)<0) { + options->Nickname)<0) { log_warn(LD_BUG, "Unable to write signature line."); goto done; } @@ -3191,8 +3279,9 @@ dirserv_orconn_tls_done(const char *address, if (!bridge_auth || ri->purpose == ROUTER_PURPOSE_BRIDGE) { tor_addr_t addr, *addrp=NULL; log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.", - ri->nickname, address, ri->or_port ); - if (tor_addr_from_str(&addr, ri->address) != -1) + router_describe(ri), + address, ri->or_port); + if (tor_addr_parse(&addr, ri->address) != -1) addrp = &addr; else log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address); @@ -3467,15 +3556,14 @@ connection_dirserv_finish_spooling(dir_connection_t *conn) static int connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn) { -#ifdef TRACK_SERVED_TIME - time_t now = time(NULL); -#endif int by_fp = (conn->dir_spool_src == DIR_SPOOL_SERVER_BY_FP || conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP); int extra = (conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_FP || conn->dir_spool_src == DIR_SPOOL_EXTRA_BY_DIGEST); time_t publish_cutoff = time(NULL)-ROUTER_MAX_AGE_TO_PUBLISH; + const or_options_t *options = get_options(); + while (smartlist_len(conn->fingerprint_stack) && connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN) { const char *body; @@ -3497,9 +3585,17 @@ connection_dirserv_add_servers_to_outbuf(dir_connection_t *conn) * unknown bridge descriptor has shown up between then and now. */ continue; } -#ifdef TRACK_SERVED_TIME - sd->last_served_at = now; -#endif + + /** If we are the bridge authority and the descriptor is a bridge + * descriptor, remember that we served this descriptor for desc stats. */ + if (options->BridgeAuthoritativeDir && by_fp) { + const routerinfo_t *router = + router_get_by_id_digest(sd->identity_digest); + /* router can be NULL here when the bridge auth is asked for its own + * descriptor. */ + if (router && router->purpose == ROUTER_PURPOSE_BRIDGE) + rep_hist_note_desc_served(sd->identity_digest); + } body = signed_descriptor_get_body(sd); if (conn->zlib_state) { /* XXXX022 This 'last' business should actually happen on the last |