diff options
author | Roger Dingledine <arma@torproject.org> | 2007-06-12 09:17:23 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2007-06-12 09:17:23 +0000 |
commit | af658b7828e2ab814d70acbbb99f414dee239def (patch) | |
tree | 427b317c28c17c9cd2aa50f32f10b4bf56719afa /src/or | |
parent | 622dd4927e1d3044fe34a1ec6c9785e044923953 (diff) | |
download | tor-af658b7828e2ab814d70acbbb99f414dee239def.tar.gz tor-af658b7828e2ab814d70acbbb99f414dee239def.zip |
More work towards making bridge users able to connect via bridges:
- demand options->Bridges and options->TunnelDirConns if
options->UseBridges is set.
- after directory fetches, accept descriptors that aren't referenced by
our networkstatuses, *if* they're for a configured bridge.
- delay directory fetching until we have at least one bridge descriptor.
- learn how to build a one-hop circuit when we have neither routerinfo
nor routerstatus for our destination.
- teach directory connections how to pick a bridge as the destination
directory when doing non-anonymous fetches.
- tolerate directory commands for which the dir_port is 0.
- remember descriptors when the requested_resource was "authority",
rather than just ignoring them.
- put bridges on our entry_guards list once we have a descriptor for them.
When UseBridges is set, only pick entry guards that are bridges. Else
vice versa.
svn:r10571
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuitbuild.c | 153 | ||||
-rw-r--r-- | src/or/circuituse.c | 24 | ||||
-rw-r--r-- | src/or/config.c | 4 | ||||
-rw-r--r-- | src/or/directory.c | 35 | ||||
-rw-r--r-- | src/or/main.c | 3 | ||||
-rw-r--r-- | src/or/or.h | 18 | ||||
-rw-r--r-- | src/or/routerlist.c | 53 |
7 files changed, 224 insertions, 66 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index ae25ac50ee..a58c68d190 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -55,7 +55,6 @@ static int onion_extend_cpath(origin_circuit_t *circ); static int count_acceptable_routers(smartlist_t *routers); static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); -static routerinfo_t *choose_random_entry(cpath_build_state_t *state); static void entry_guards_changed(void); /** Iterate over values of circ_id, starting from conn-\>next_circ_id, @@ -1581,10 +1580,10 @@ choose_good_middle_server(uint8_t purpose, /** Pick a good entry server for the circuit to be built according to * <b>state</b>. Don't reuse a chosen exit (if any), don't use this * router (if we're an OR), and respect firewall settings; if we're - * using entry_guards, return one. + * configured to use entry guards, return one. * - * If <b>state</b> is NULL, we're choosing routers to serve as entry - * nodes, not for any particular circuit. + * If <b>state</b> is NULL, we're choosing a router to serve as an entry + * guard, not for any particular circuit. */ static routerinfo_t * choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) @@ -1721,49 +1720,62 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) return 0; } +/** Allocate a new extend_info object based on the various arguments. */ +extend_info_t * +extend_info_alloc(const char *nickname, const char *digest, + crypto_pk_env_t *onion_key, + uint32_t addr, uint16_t port) +{ + extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t)); + memcpy(info->identity_digest, digest, DIGEST_LEN); + if (nickname) + strlcpy(info->nickname, nickname, sizeof(info->nickname)); + else { + /* make one up */ + } + if (onion_key) + info->onion_key = crypto_pk_dup_key(onion_key); + info->addr = addr; + info->port = port; + return info; +} + /** Allocate and return a new extend_info_t that can be used to build a * circuit to or through the router <b>r</b>. */ extend_info_t * extend_info_from_router(routerinfo_t *r) { - extend_info_t *info; tor_assert(r); - info = tor_malloc_zero(sizeof(extend_info_t)); - strlcpy(info->nickname, r->nickname, sizeof(info->nickname)); - memcpy(info->identity_digest, r->cache_info.identity_digest, DIGEST_LEN); - info->onion_key = crypto_pk_dup_key(r->onion_pkey); - info->addr = r->addr; - info->port = r->or_port; - info->router_purpose = r->purpose; - return info; + return extend_info_alloc(r->nickname, r->cache_info.identity_digest, + r->onion_pkey, r->addr, r->or_port); } +#if 0 /** What router purpose is <b>digest</b>? * It's a general purpose router unless it's on our bridges list. */ static uint8_t get_router_purpose_from_digest(char *digest) { - (void)digest; - return ROUTER_PURPOSE_GENERAL; /* XXX020 */ + if (digest_is_a_bridge(digest)) + return ROUTER_PURPOSE_BRIDGE; + return ROUTER_PURPOSE_GENERAL; } +#endif +#if 0 /** Allocate and return a new extend_info_t that can be used to build a * circuit to or through the router <b>r</b>. */ extend_info_t * extend_info_from_routerstatus(routerstatus_t *s) { - extend_info_t *info; tor_assert(s); - info = tor_malloc_zero(sizeof(extend_info_t)); - strlcpy(info->nickname, s->nickname, sizeof(info->nickname)); - memcpy(info->identity_digest, s->identity_digest, DIGEST_LEN); - info->onion_key = NULL; /* routerstatus doesn't know this */ - info->addr = s->addr; - info->port = s->or_port; - info->router_purpose = get_router_purpose_from_digest(info->identity_digest); - return info; + /* routerstatus doesn't know onion_key; leave it NULL */ + return extend_info_alloc(s->nickname, s->identity_digest, + NULL, s->addr, s->or_port); +// get_router_purpose_from_digest(s->identity_digest)); } +#endif /** Release storage held by an extend_info_t struct. */ void @@ -1834,7 +1846,9 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri, reason = "unlisted"; else if (!ri->is_running) reason = "down"; - else if (!ri->is_possible_guard && + else if (options->UseBridges && ri->purpose != ROUTER_PURPOSE_BRIDGE) + reason = "not a bridge"; + else if (!options->UseBridges && !ri->is_possible_guard && !router_nickname_is_in_list(ri, options->EntryNodes)) reason = "not recommended as a guard"; else if (router_nickname_is_in_list(ri, options->ExcludeNodes)) @@ -1909,6 +1923,10 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, r = router_get_by_digest(e->identity); if (!r) return NULL; + if (get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_BRIDGE) + return NULL; + if (!get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_GENERAL) + return NULL; if (router_is_unreliable(r, need_uptime, need_capacity, 0)) return NULL; if (firewall_is_fascist_or() && @@ -2337,18 +2355,33 @@ entry_guards_prepend_from_config(void) entry_guards_changed(); } -/** Pick a live (up and listed) entry guard from entry_guards, and - * make sure not to pick this circuit's exit. */ -static routerinfo_t * +/** Return 1 if we're fine adding arbitrary routers out of the + * directory to our entry guard list. Else return 0. */ +static int +can_grow_entry_list(or_options_t *options) +{ + if (options->StrictEntryNodes) + return 0; + if (options->UseBridges) + return 0; + return 1; +} + +/** Pick a live (up and listed) entry guard from entry_guards. If + * <b>state</b> is non-NULL, this is for a specific circuit -- + * make sure not to pick this circuit's exit or any node in the + * exit's family. If <b>state</b> is NULL, we're looking for a random + * guard (likely a bridge). */ +routerinfo_t * choose_random_entry(cpath_build_state_t *state) { or_options_t *options = get_options(); smartlist_t *live_entry_guards = smartlist_create(); smartlist_t *exit_family = smartlist_create(); - routerinfo_t *chosen_exit = build_state_get_exit_router(state); + routerinfo_t *chosen_exit = state?build_state_get_exit_router(state) : NULL; routerinfo_t *r = NULL; - int need_uptime = state->need_uptime; - int need_capacity = state->need_capacity; + int need_uptime = state ? state->need_uptime : 0; + int need_capacity = state ? state->need_capacity : 0; if (chosen_exit) { smartlist_add(exit_family, chosen_exit); @@ -2361,7 +2394,7 @@ choose_random_entry(cpath_build_state_t *state) if (should_add_entry_nodes) entry_guards_prepend_from_config(); - if (!options->StrictEntryNodes && + if (can_grow_entry_list(options) && (! entry_guards || smartlist_len(entry_guards) < options->NumEntryGuards)) pick_entry_guards(); @@ -2383,7 +2416,7 @@ choose_random_entry(cpath_build_state_t *state) * using him. * (We might get 2 live-but-crummy entry guards, but so be it.) */ if (smartlist_len(live_entry_guards) < 2) { - if (!options->StrictEntryNodes) { + if (can_grow_entry_list(options)) { /* still no? try adding a new entry then */ /* XXX if guard doesn't imply fast and stable, then we need * to tell add_an_entry_guard below what we want, or it might @@ -2403,7 +2436,7 @@ choose_random_entry(cpath_build_state_t *state) need_capacity = 0; goto retry; } - /* live_entry_guards will be empty below. Oh well, we tried. */ + /* live_entry_guards may be empty below. Oh well, we tried. */ } r = smartlist_choose(live_entry_guards); @@ -2641,6 +2674,18 @@ clear_bridge_list(void) smartlist_clear(bridge_list); } +/** Return 1 if <b>digest</b> is one of our known bridges. */ +int +identity_digest_is_a_bridge(const char *digest) +{ + SMARTLIST_FOREACH(bridge_list, bridge_info_t *, bridge, + { + if (!memcmp(bridge->identity, digest, DIGEST_LEN)) + return 1; + }); + return 0; +} + /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b> * is set, it tells us the identity key too. */ void @@ -2660,7 +2705,7 @@ bridge_add_from_config(uint32_t addr, uint16_t port, char *digest) * descriptor, fetch a new copy of its descriptor -- either directly * from the bridge or via a bridge authority. */ void -learn_bridge_descriptors(void) +fetch_bridge_descriptors(void) { char address_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; @@ -2698,3 +2743,41 @@ learn_bridge_descriptors(void) }); } +/** We just learned a descriptor for a bridge. See if that + * digest is in our entry guard list, and add it if not. */ +void +learned_bridge_descriptor(routerinfo_t *ri) +{ + tor_assert(ri); + tor_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE); + if (get_options()->UseBridges) { + ri->is_running = 1; + add_an_entry_guard(ri); + log_notice(LD_DIR, "new bridge descriptor '%s'", ri->nickname); + } +} + +/** Return 1 if any of our entry guards have descriptors that + * are marked with purpose 'bridge'. Else return 0. + * + * We use this function to decide if we're ready to start building + * circuits through our bridges, or if we need to wait until the + * directory "server/authority" requests finish. */ +int +any_bridge_descriptors_known(void) +{ + return choose_random_entry(NULL)!=NULL ? 1 : 0; +#if 0 + routerinfo_t *ri; + if (!entry_guards) + entry_guards = smartlist_create(); + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, + { + ri = router_get_by_digest(e->identity); + if (ri && ri->purpose == ROUTER_PURPOSE_BRIDGE) + return 1; + }); + return 0; +#endif +} + diff --git a/src/or/circuituse.c b/src/or/circuituse.c index d1044b491e..fef1471fdd 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1034,18 +1034,22 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn, want_onehop, conn->chosen_exit_name); if (want_onehop && conn->chosen_exit_name[0] == '$') { /* We're asking for a one-hop circuit to a router that - * we don't have a routerinfo about. Hope we have a - * routerstatus or equivalent. */ - routerstatus_t *s = - routerstatus_get_by_hexdigest(conn->chosen_exit_name+1); - if (s) { - extend_info = extend_info_from_routerstatus(s); - } else { - log_warn(LD_APP, - "Requested router '%s' is not known. Closing.", - conn->chosen_exit_name); + * we don't have a routerinfo about. Make up an extend_info. */ + char digest[DIGEST_LEN]; + char *hexdigest = conn->chosen_exit_name+1; + struct in_addr in; + if (strlen(hexdigest) < HEX_DIGEST_LEN || + base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN)<0) { + log_info(LD_DIR, "Broken exit digest on tunnel conn. Closing."); return -1; } + if (!tor_inet_aton(conn->socks_request->address, &in)) { + log_info(LD_DIR, "Broken address on tunnel conn. Closing."); + return -1; + } + extend_info = extend_info_alloc(conn->chosen_exit_name+1, + digest, NULL, ntohl(in.s_addr), + conn->socks_request->port); } else { /* We will need an onion key for the router, and we * don't have one. Refuse or relax requirements. */ diff --git a/src/or/config.c b/src/or/config.c index 8e69f45ac6..844e802b97 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -2914,6 +2914,10 @@ options_validate(or_options_t *old_options, or_options_t *options, } } + if (options->UseBridges && !options->Bridges) + REJECT("If you set UseBridges, you must specify at least one bridge."); + if (options->UseBridges && !options->TunnelDirConns) + REJECT("If you set UseBridges, you must set TunnelDirConns."); if (options->Bridges) { for (cl = options->Bridges; cl; cl = cl->next) { if (parse_bridge_line(cl->value, 1)<0) diff --git a/src/or/directory.c b/src/or/directory.c index 3390f3a8bd..8c483f5cae 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -230,7 +230,21 @@ directory_get_from_dirserver(uint8_t dir_purpose, const char *resource, if (!options->FetchServerDescriptors && type != HIDSERV_AUTHORITY) return; - if (directconn) { + if (directconn && options->UseBridges) { + /* want to pick a bridge for which we have a descriptor. */ + routerinfo_t *ri = choose_random_entry(NULL); + if (ri) { + directory_initiate_command(ri->address, ri->addr, + ri->or_port, 0, + 1, ri->cache_info.identity_digest, + dir_purpose, + ROUTER_PURPOSE_GENERAL, + 0, resource, NULL, 0); + } else + log_notice(LD_DIR, "Ignoring directory request, since no bridge " + "nodes are available yet."); + return; + } else if (directconn) { if (prefer_authority) { /* only ask authdirservers, and don't ask myself */ rs = router_pick_trusteddirserver(type, 1, 1, @@ -259,8 +273,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, const char *resource, directconn = 0; /* last resort: try routing it via Tor */ } } - } - if (!directconn) { + } else { /* !directconn */ /* Never use fascistfirewall; we're going via Tor. */ if (dir_purpose == DIR_PURPOSE_FETCH_RENDDESC) { /* only ask hidserv authorities, any of them will do */ @@ -463,7 +476,7 @@ directory_initiate_command(const char *address, uint32_t addr, tor_assert(address); tor_assert(addr); - tor_assert(dir_port); + tor_assert(or_port || dir_port); tor_assert(digest); log_debug(LD_DIR, "anonymized %d, want_to_tunnel %d.", @@ -1221,7 +1234,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn) smartlist_t *which = NULL; int n_asked_for = 0; log_info(LD_DIR,"Received %s (size %d) from server '%s:%d'", - was_ei ? "server info" : "extra server info", + was_ei ? "extra server info" : "server info", (int)body_len, conn->_base.address, conn->_base.port); if (was_ei) note_request(was_compressed?"dl/extra.z":"dl/extra", orig_len); @@ -1255,13 +1268,15 @@ connection_dir_client_reached_eof(dir_connection_t *conn) tor_free(body); tor_free(headers); tor_free(reason); return dir_okay ? 0 : -1; } - /* Learn the routers, assuming we requested by fingerprint or "all". - * Right now, we only use "authority" to fetch ourself, so we don't want - * to risk replacing ourself with a router running at the addr:port we - * think we have. + /* Learn the routers, assuming we requested by fingerprint or "all" + * or "authority". (We use "authority" to fetch our own descriptor for + * testing, and to fetch bridge descriptors for bootstrapping.) */ + /* XXX020 We now risk replacing ourself with a router running at + * the addr:port we think we have. Might want to check more carefully. */ if (which || (conn->requested_resource && - !strcmpstart(conn->requested_resource, "all"))) { + (!strcmpstart(conn->requested_resource, "all") || + !strcmpstart(conn->requested_resource, "authority")))) { /* as we learn from them, we remove them from 'which' */ if (was_ei) { router_load_extrainfo_from_string(body, NULL, SAVED_NOWHERE, which); diff --git a/src/or/main.c b/src/or/main.c index ef72f49ab4..73a0401178 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -884,6 +884,8 @@ run_scheduled_events(time_t now) if (time_to_reset_descriptor_failures < now) { router_reset_descriptor_download_failures(); + if (options->UseBridges) + fetch_bridge_descriptors(); /* XXX get this its own retry schedule -RD */ time_to_reset_descriptor_failures = now + DESCRIPTOR_FAILURE_RESET_INTERVAL; } @@ -951,6 +953,7 @@ run_scheduled_events(time_t now) * and the rend cache. */ rep_history_clean(now - options->RephistTrackTime); rend_cache_clean(); + /* XXX020 we only clean this stuff if DirPort is set?! -RD */ } /* 2b. Once per minute, regenerate and upload the descriptor if the old diff --git a/src/or/or.h b/src/or/or.h index ced00a6805..cf6fe12d7d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1384,7 +1384,7 @@ typedef struct extend_info_t { * display. */ char identity_digest[DIGEST_LEN]; /**< Hash of this router's identity key. */ uint16_t port; /**< OR port. */ - uint8_t router_purpose; /**< General, controller, or bridge. */ +// uint8_t router_purpose; /**< General, controller, or bridge. */ uint32_t addr; /**< IP address in host order. */ crypto_pk_env_t *onion_key; /**< Current onionskin key. */ } extend_info_t; @@ -2200,8 +2200,11 @@ int circuit_all_predicted_ports_handled(time_t now, int *need_uptime, int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info); int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); +extend_info_t *extend_info_alloc(const char *nickname, const char *digest, + crypto_pk_env_t *onion_key, + uint32_t addr, uint16_t port); extend_info_t *extend_info_from_router(routerinfo_t *r); -extend_info_t *extend_info_from_routerstatus(routerstatus_t *s); +//extend_info_t *extend_info_from_routerstatus(routerstatus_t *s); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free(extend_info_t *info); routerinfo_t *build_state_get_exit_router(cpath_build_state_t *state); @@ -2211,15 +2214,19 @@ void entry_guards_compute_status(void); int entry_guard_register_connect_status(const char *digest, int succeeded, time_t now); void entry_nodes_should_be_added(void); -void entry_guards_update_state(or_state_t *state); +routerinfo_t *choose_random_entry(cpath_build_state_t *state); int entry_guards_parse_state(or_state_t *state, int set, char **msg); +void entry_guards_update_state(or_state_t *state); int getinfo_helper_entry_guards(control_connection_t *conn, const char *question, char **answer); void entry_guards_free_all(void); void clear_bridge_list(void); +int identity_digest_is_a_bridge(const char *digest); void bridge_add_from_config(uint32_t addr, uint16_t port, char *digest); -void learn_bridge_descriptors(void); +void fetch_bridge_descriptors(void); +void learned_bridge_descriptor(routerinfo_t *ri); +int any_bridge_descriptors_known(void); /********************************* circuitlist.c ***********************/ @@ -3315,7 +3322,8 @@ local_routerstatus_t *router_get_combined_status_by_digest(const char *digest); local_routerstatus_t *router_get_combined_status_by_descriptor_digest( const char *digest); -routerstatus_t *routerstatus_get_by_hexdigest(const char *hexdigest); +//routerstatus_t *routerstatus_get_by_hexdigest(const char *hexdigest); +int should_delay_dir_fetches(or_options_t *options); void update_networkstatus_downloads(time_t now); void update_router_descriptor_downloads(time_t now); void update_extrainfo_downloads(time_t now); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 5d3cb70129..4ff3659da4 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2340,7 +2340,7 @@ router_set_status(const char *digest, int up) * * This function should be called *after* * routers_update_status_from_networkstatus; subsequently, you should call - * router_rebuild_store and control_event_descriptors_changed. + * router_rebuild_store and routerlist_descriptors_added. */ int router_add_to_routerlist(routerinfo_t *router, const char **msg, @@ -2387,7 +2387,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, /* Only check the descriptor digest against the network statuses when * we are receiving in response to a fetch. */ - if (!signed_desc_digest_is_recognized(&router->cache_info)) { + if (!signed_desc_digest_is_recognized(&router->cache_info) && + !identity_digest_is_a_bridge(router->cache_info.identity_digest)) { /* We asked for it, so some networkstatus must have listed it when we * did. Save it if we're a cache in case somebody else asks for it. */ log_info(LD_DIR, @@ -2725,6 +2726,19 @@ routerlist_remove_old_routers(void) digestmap_free(retain, NULL); } +/** We just added a new descriptor that isn't of purpose + * ROUTER_PURPOSE_GENERAL. Take whatever extra steps we need. */ +static void +routerlist_descriptors_added(smartlist_t *sl) +{ + tor_assert(sl); + control_event_descriptors_changed(sl); + SMARTLIST_FOREACH(sl, routerinfo_t *, ri, + if (ri->purpose == ROUTER_PURPOSE_BRIDGE) + learned_bridge_descriptor(ri); + ); +} + /** * Code to parse a single router descriptor and insert it into the * routerlist. Return -1 if the descriptor was ill-formed; 0 if the @@ -2753,7 +2767,7 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg) return -1; } ri->purpose = purpose; - if (purpose != ROUTER_PURPOSE_GENERAL) + if (ri->purpose != ROUTER_PURPOSE_GENERAL) ri->cache_info.do_not_cache = 1; if (router_is_me(ri)) { log_warn(LD_DIR, "Router's identity key matches mine; dropping."); @@ -2774,7 +2788,7 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg) smartlist_free(lst); return 0; } else { - control_event_descriptors_changed(lst); + routerlist_descriptors_added(lst); smartlist_free(lst); log_debug(LD_DIR, "Added router to list"); return 1; @@ -2837,7 +2851,7 @@ router_load_routers_from_string(const char *s, const char *eos, }); if (smartlist_len(changed)) - control_event_descriptors_changed(changed); + routerlist_descriptors_added(changed); routerlist_assert_ok(routerlist); router_rebuild_store(0, 0); @@ -3272,6 +3286,7 @@ router_get_combined_status_by_nickname(const char *nickname, return best; } +#if 0 /** Find a routerstatus_t that corresponds to <b>hexdigest</b>, if * any. Prefer ones that belong to authorities. */ routerstatus_t * @@ -3290,6 +3305,7 @@ routerstatus_get_by_hexdigest(const char *hexdigest) return &(rs->status); return NULL; } +#endif /** Return true iff any networkstatus includes a descriptor whose digest * is that of <b>desc</b>. */ @@ -3503,11 +3519,26 @@ update_networkstatus_client_downloads(time_t now) smartlist_free(missing); } +/** Return 1 if there's a reason we shouldn't try any directory + * fetches yet (e.g. we demand bridges and none are yet known). + * Else return 0. */ +int +should_delay_dir_fetches(or_options_t *options) +{ + if (options->UseBridges && !any_bridge_descriptors_known()) { + log_notice(LD_DIR, "delaying dir fetches"); + return 1; + } + return 0; +} + /** Launch requests for networkstatus documents as appropriate. */ void update_networkstatus_downloads(time_t now) { or_options_t *options = get_options(); + if (should_delay_dir_fetches(options)) + return; if (options->DirPort) update_networkstatus_cache_downloads(now); else @@ -4729,6 +4760,8 @@ void update_router_descriptor_downloads(time_t now) { or_options_t *options = get_options(); + if (should_delay_dir_fetches(options)) + return; if (options->DirPort) { update_router_descriptor_cache_downloads(now); } else { @@ -4753,7 +4786,7 @@ should_download_extrainfo(signed_descriptor_t *sd, !digestmap_get(pending, d)); } -/** Laucnch extrainfo downloads as needed. */ +/** Launch extrainfo downloads as needed. */ void update_extrainfo_downloads(time_t now) { @@ -4764,6 +4797,8 @@ update_extrainfo_downloads(time_t now) int i; if (! options->DownloadExtraInfo) return; + if (should_delay_dir_fetches(options)) + return; pending = digestmap_new(); list_pending_descriptor_downloads(pending, 1); @@ -4853,6 +4888,12 @@ update_router_have_minimum_dir_info(void) routerlist_remove_old_routers(); networkstatus_list_clean(now); + if (should_delay_dir_fetches(get_options())) { + log_notice(LD_DIR, "no bridge descs known yet"); + res = 0; + goto done; + } + n_authorities = get_n_v2_authorities(); n_ns = smartlist_len(networkstatus_list); if (n_ns<=n_authorities/2) { |