[or-cvs] r10571: More work towards making bridge users able to connect via br (in tor/trunk: doc doc/spec src/or)

arma at seul.org arma at seul.org
Tue Jun 12 09:17:23 UTC 2007


Author: arma
Date: 2007-06-12 05:17:23 -0400 (Tue, 12 Jun 2007)
New Revision: 10571

Modified:
   tor/trunk/doc/TODO
   tor/trunk/doc/spec/dir-spec.txt
   tor/trunk/src/or/circuitbuild.c
   tor/trunk/src/or/circuituse.c
   tor/trunk/src/or/config.c
   tor/trunk/src/or/directory.c
   tor/trunk/src/or/main.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/routerlist.c
Log:
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.


Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/doc/TODO	2007-06-12 09:17:23 UTC (rev 10571)
@@ -219,10 +219,19 @@
       D Do we want to maintain our own set of entryguards that we use
         after the bridge? Open research question; let's say no for 0.2.0
         unless we learn otherwise.
-      - Ask all directory questions to bridge via BEGIN_DIR.
+      o if you don't have any routerinfos for your bridges, or you don't
+        like the ones you have, ask a new bridge for its server/authority.
+      . Ask all directory questions to bridge via BEGIN_DIR.
+        - use the bridges for dir fetches even when our dirport is open.
 N     - Design/implement the "local-status" or something like it, from the
         "Descriptor purposes: how to tell them apart" section of
         http://archives.seul.org/or/dev/May-2007/msg00008.html
+      - timeout and retry schedules for fetching bridge descriptors
+      - give extend_info_t a router_purpose again
+      - react faster to download networkstatuses after the first bridge
+        descriptor arrives
+      - be more robust to bridges being marked as down and leaving us
+        stranded without any known "running" bridges.
     - Bridges operators (rudimentary version)
       - Ability to act as dir cache without a dir port.
       o Bridges publish to bridge authorities

Modified: tor/trunk/doc/spec/dir-spec.txt
===================================================================
--- tor/trunk/doc/spec/dir-spec.txt	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/doc/spec/dir-spec.txt	2007-06-12 09:17:23 UTC (rev 10571)
@@ -192,14 +192,13 @@
    corresponding roughly to "status votes" above.  They would compute the
    result of the vote on the client side.
 
-   Authorities used sign documents using the same private keys they used
+   Authorities used to sign documents using the same private keys they used
    for their roles as routers.  This forced them to keep these extremely
    sensitive keys in memory unencrypted.
 
    All of the information in extra-info documents used to be kept in the
    main descriptors.
 
-
 1.2. Document meta-format
 
   Router descriptors, directories, and running-routers documents all obey the

Modified: tor/trunk/src/or/circuitbuild.c
===================================================================
--- tor/trunk/src/or/circuitbuild.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/circuitbuild.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -55,7 +55,6 @@
 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 @@
 /** 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 @@
   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 @@
     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 @@
   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_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 @@
   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 @@
    * 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 @@
       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 @@
   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 @@
  * 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 @@
     });
 }
 
+/** 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
+}
+

Modified: tor/trunk/src/or/circuituse.c
===================================================================
--- tor/trunk/src/or/circuituse.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/circuituse.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -1034,18 +1034,22 @@
                     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. */

Modified: tor/trunk/src/or/config.c
===================================================================
--- tor/trunk/src/or/config.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/config.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -2914,6 +2914,10 @@
     }
   }
 
+  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)

Modified: tor/trunk/src/or/directory.c
===================================================================
--- tor/trunk/src/or/directory.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/directory.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -230,7 +230,21 @@
   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 @@
           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 @@
 
   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 @@
     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 @@
       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);

Modified: tor/trunk/src/or/main.c
===================================================================
--- tor/trunk/src/or/main.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/main.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -884,6 +884,8 @@
 
   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 @@
      * 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

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/or.h	2007-06-12 09:17:23 UTC (rev 10571)
@@ -1384,7 +1384,7 @@
                                           * 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_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 @@
 int entry_guard_register_connect_status(const char *digest, int succeeded,
                                         time_t now);
 void entry_nodes_should_be_added(void);
+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 entry_guards_parse_state(or_state_t *state, int set, char **msg);
 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_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);

Modified: tor/trunk/src/or/routerlist.c
===================================================================
--- tor/trunk/src/or/routerlist.c	2007-06-12 08:19:02 UTC (rev 10570)
+++ tor/trunk/src/or/routerlist.c	2007-06-12 09:17:23 UTC (rev 10571)
@@ -2340,7 +2340,7 @@
  *
  * 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 @@
     /* 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 @@
   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 @@
     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 @@
     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 @@
   });
 
   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 @@
   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 @@
     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 @@
   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 @@
 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 @@
           !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 @@
   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 @@
   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) {



More information about the tor-commits mailing list