Browse Source

Dirservers now do their own external reachability testing of each
Tor server, and only list them as running if they've been found to
be reachable.

Dirservers also log trouble servers, but only start complaining loudly
after they've been up for an hour, to reduce false positives. We still
need to do something about the fact that it is quite loud when there
are many trouble servers.


svn:r4829

Roger Dingledine 20 years ago
parent
commit
a120cc20c1
7 changed files with 56 additions and 40 deletions
  1. 0 9
      src/or/connection_or.c
  2. 0 1
      src/or/directory.c
  3. 32 14
      src/or/dirserv.c
  4. 10 8
      src/or/main.c
  5. 2 1
      src/or/or.h
  6. 10 5
      src/or/router.c
  7. 2 2
      src/or/routerparse.c

+ 0 - 9
src/or/connection_or.c

@@ -334,15 +334,6 @@ connection_or_connect(uint32_t addr, uint16_t port, const char *id_digest)
     return NULL;
     return NULL;
   }
   }
 
 
-  /* this function should never be called if we're already connected to
-   * id_digest, but check first to be sure */
-  conn = connection_get_by_identity_digest(id_digest, CONN_TYPE_OR);
-  if (conn) {
-    tor_assert(conn->nickname);
-    log_fn(LOG_WARN,"Asked me to connect to router '%s', but there's already a connection.", conn->nickname);
-    return conn;
-  }
-
   conn = connection_new(CONN_TYPE_OR);
   conn = connection_new(CONN_TYPE_OR);
 
 
   /* set up conn so it's got all the data we need to remember */
   /* set up conn so it's got all the data we need to remember */

+ 0 - 1
src/or/directory.c

@@ -807,7 +807,6 @@ connection_dir_client_reached_eof(connection_t *conn)
       log_fn(LOG_INFO,"updated routers.");
       log_fn(LOG_INFO,"updated routers.");
     }
     }
     /* do things we've been waiting to do */
     /* do things we've been waiting to do */
-    helper_nodes_set_status_from_directory();
     directory_has_arrived(time(NULL), conn->identity_digest);
     directory_has_arrived(time(NULL), conn->identity_digest);
   }
   }
 
 

+ 32 - 14
src/or/dirserv.c

@@ -17,6 +17,8 @@ const char dirserv_c_id[] = "$Id$";
 /** How many seconds do we wait before regenerating the directory? */
 /** How many seconds do we wait before regenerating the directory? */
 #define DIR_REGEN_SLACK_TIME 5
 #define DIR_REGEN_SLACK_TIME 5
 
 
+extern long stats_n_seconds_working;
+
 /** Do we need to regenerate the directory when someone asks for it? */
 /** Do we need to regenerate the directory when someone asks for it? */
 static int the_directory_is_dirty = 1;
 static int the_directory_is_dirty = 1;
 static int runningrouters_is_dirty = 1;
 static int runningrouters_is_dirty = 1;
@@ -393,8 +395,9 @@ dirserv_add_descriptor(const char **desc, const char **msg)
       *desc = end;
       *desc = end;
       return verified;
       return verified;
     }
     }
-    /* We don't alrady have a newer one; we'll update this one. */
+    /* 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);
     log_fn(LOG_INFO,"Dirserv updating desc for server %s (nickname '%s')",hex_digest,ri->nickname);
+    ri->last_reachable = ri_old->last_reachable; /* this carries over */
     *msg = verified?"Verified server updated":"Unverified server updated. (Have you sent us your key fingerprint?)";
     *msg = verified?"Verified server updated":"Unverified server updated. (Have you sent us your key fingerprint?)";
     routerinfo_free(ri_old);
     routerinfo_free(ri_old);
     smartlist_del_keeporder(descriptor_list, found);
     smartlist_del_keeporder(descriptor_list, found);
@@ -546,6 +549,9 @@ list_single_server_status(routerinfo_t *desc, int is_live)
   return tor_strdup(buf);
   return tor_strdup(buf);
 }
 }
 
 
+#define REACHABLE_TIMEOUT (60*60) /* an hour */
+/* Make sure this is 3 times the value of get_dir_fetch_period() */
+
 /** Based on the routerinfo_ts in <b>routers</b>, allocate the
 /** Based on the routerinfo_ts in <b>routers</b>, allocate the
  * contents of a router-status line, and store it in
  * contents of a router-status line, and store it in
  * *<b>router_status_out</b>.  Return 0 on success, -1 on failure.
  * *<b>router_status_out</b>.  Return 0 on success, -1 on failure.
@@ -556,6 +562,7 @@ list_server_status(smartlist_t *routers, char **router_status_out)
   /* List of entries in a router-status style: An optional !, then an optional
   /* List of entries in a router-status style: An optional !, then an optional
    * equals-suffixed nickname, then a dollar-prefixed hexdigest. */
    * equals-suffixed nickname, then a dollar-prefixed hexdigest. */
   smartlist_t *rs_entries;
   smartlist_t *rs_entries;
+  time_t now = time(NULL);
   int authdir_mode = get_options()->AuthoritativeDir;
   int authdir_mode = get_options()->AuthoritativeDir;
   tor_assert(router_status_out);
   tor_assert(router_status_out);
 
 
@@ -563,16 +570,25 @@ list_server_status(smartlist_t *routers, char **router_status_out)
 
 
   SMARTLIST_FOREACH(routers, routerinfo_t *, ri,
   SMARTLIST_FOREACH(routers, routerinfo_t *, ri,
   {
   {
-    int is_live;
+    int is_live = 0;
     connection_t *conn;
     connection_t *conn;
     conn = connection_get_by_identity_digest(
     conn = connection_get_by_identity_digest(
                     ri->identity_digest, CONN_TYPE_OR);
                     ri->identity_digest, CONN_TYPE_OR);
     if (authdir_mode) {
     if (authdir_mode) {
       /* Treat a router as alive if
       /* Treat a router as alive if
        *    - It's me, and I'm not hibernating.
        *    - It's me, and I'm not hibernating.
-       * or - we're connected to it. */
-      is_live = (router_is_me(ri) && !we_are_hibernating()) ||
-        (conn && conn->state == OR_CONN_STATE_OPEN);
+       * or - we're connected to it and we've found it reachable recently. */
+      if (router_is_me(ri) && !we_are_hibernating()) {
+        is_live = 1;
+      } else if (conn && conn->state == OR_CONN_STATE_OPEN) {
+        if (now < ri->last_reachable + REACHABLE_TIMEOUT) {
+          is_live = 1;
+        } else {
+          log_fn(stats_n_seconds_working>REACHABLE_TIMEOUT ? LOG_NOTICE : LOG_INFO,
+                 "Router %s (%s:%d) is connected to us but not reachable by us.",
+                 ri->nickname, ri->address, ri->or_port);
+        }
+      }
     } else {
     } else {
       is_live = ri->is_running;
       is_live = ri->is_running;
     }
     }
@@ -982,7 +998,7 @@ dirserv_orconn_tls_done(const char *address,
                         uint16_t or_port,
                         uint16_t or_port,
                         const char *digest_rcvd,
                         const char *digest_rcvd,
                         const char *nickname_rcvd,
                         const char *nickname_rcvd,
-                        int as_advertised) //XXXRD
+                        int as_advertised)
 {
 {
   int i;
   int i;
   tor_assert(address);
   tor_assert(address);
@@ -995,10 +1011,9 @@ dirserv_orconn_tls_done(const char *address,
   for (i = 0; i < smartlist_len(descriptor_list); ++i) {
   for (i = 0; i < smartlist_len(descriptor_list); ++i) {
     routerinfo_t *ri = smartlist_get(descriptor_list, i);
     routerinfo_t *ri = smartlist_get(descriptor_list, i);
     int drop = 0;
     int drop = 0;
-    if (ri->is_verified)
+    if (strcasecmp(address, ri->address) || or_port != ri->or_port)
       continue;
       continue;
-    if (!strcasecmp(address, ri->address) &&
-        or_port == ri->or_port) {
+    if (!ri->is_verified) {
       /* We have a router at the same address! */
       /* We have a router at the same address! */
       if (strcasecmp(ri->nickname, nickname_rcvd)) {
       if (strcasecmp(ri->nickname, nickname_rcvd)) {
         log_fn(LOG_NOTICE, "Dropping descriptor: nickname '%s' does not match nickname '%s' in cert from %s:%d",
         log_fn(LOG_NOTICE, "Dropping descriptor: nickname '%s' does not match nickname '%s' in cert from %s:%d",
@@ -1009,11 +1024,14 @@ dirserv_orconn_tls_done(const char *address,
                address, or_port);
                address, or_port);
         drop = 1;
         drop = 1;
       }
       }
-      if (drop) {
-        routerinfo_free(ri);
-        smartlist_del(descriptor_list, i--);
-        directory_set_dirty();
-      }
+    }
+    if (drop) {
+      routerinfo_free(ri);
+      smartlist_del(descriptor_list, i--);
+      directory_set_dirty();
+    } else { /* correct nickname and digest. mark this router reachable! */
+      log_fn(LOG_INFO,"Found router %s to be reachable. Yay.", ri->nickname);
+      ri->last_reachable = time(NULL);
     }
     }
   }
   }
 }
 }

+ 10 - 8
src/or/main.c

@@ -546,6 +546,9 @@ directory_has_arrived(time_t now, char *identity_digest)
   if (!time_to_fetch_running_routers)
   if (!time_to_fetch_running_routers)
     time_to_fetch_running_routers = now + get_status_fetch_period(options);
     time_to_fetch_running_routers = now + get_status_fetch_period(options);
 
 
+  if (identity_digest) /* if it's fresh */
+    helper_nodes_set_status_from_directory();
+
   if (server_mode(options) && identity_digest) {
   if (server_mode(options) && identity_digest) {
     /* if this is us, then our dirport is reachable */
     /* if this is us, then our dirport is reachable */
     if (router_digest_is_me(identity_digest))
     if (router_digest_is_me(identity_digest))
@@ -554,7 +557,8 @@ directory_has_arrived(time_t now, char *identity_digest)
 
 
   if (server_mode(options) &&
   if (server_mode(options) &&
       !we_are_hibernating()) { /* connect to the appropriate routers */
       !we_are_hibernating()) { /* connect to the appropriate routers */
-    router_retry_connections();
+    if (!authdir_mode(options))
+      router_retry_connections(0);
     if (identity_digest) /* we got a fresh directory */
     if (identity_digest) /* we got a fresh directory */
       consider_testing_reachability();
       consider_testing_reachability();
   }
   }
@@ -688,13 +692,11 @@ run_scheduled_events(time_t now)
     routerlist_remove_old_routers(ROUTER_MAX_AGE);
     routerlist_remove_old_routers(ROUTER_MAX_AGE);
 
 
     if (authdir_mode(options)) {
     if (authdir_mode(options)) {
-      /* We're a directory; dump any old descriptors. */
+      /* Dump any old descriptors. */
       dirserv_remove_old_servers(ROUTER_MAX_AGE);
       dirserv_remove_old_servers(ROUTER_MAX_AGE);
-    }
-    if (server_mode(options) && !we_are_hibernating()) {
-      /* dirservers try to reconnect, in case connections have failed;
-       * and normal servers try to reconnect to dirservers */
-      router_retry_connections();
+      if (!we_are_hibernating()) { /* try to determine reachability */
+        router_retry_connections(1);
+      }
     }
     }
 
 
     directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
     directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 1);
@@ -975,7 +977,7 @@ do_main_loop(void)
 
 
   if (authdir_mode(get_options())) {
   if (authdir_mode(get_options())) {
     /* the directory is already here, run startup things */
     /* the directory is already here, run startup things */
-    router_retry_connections();
+    router_retry_connections(1);
   }
   }
 
 
   if (server_mode(get_options())) {
   if (server_mode(get_options())) {

+ 2 - 1
src/or/or.h

@@ -737,6 +737,7 @@ typedef struct {
   /* local info */
   /* local info */
   int is_running; /**< As far as we know, is this OR currently running? */
   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? */
   time_t status_set_at; /**< When did we last update is_running? */
+  time_t last_reachable; /**< When was the last time we could reach this OR? */
   int is_verified; /**< Has a trusted dirserver validated this OR? */
   int is_verified; /**< Has a trusted dirserver validated this OR? */
 
 
   smartlist_t *declared_family; /**< Nicknames of router which this router
   smartlist_t *declared_family; /**< Nicknames of router which this router
@@ -1901,7 +1902,7 @@ int server_mode(or_options_t *options);
 int advertised_server_mode(void);
 int advertised_server_mode(void);
 int proxy_mode(or_options_t *options);
 int proxy_mode(or_options_t *options);
 
 
-void router_retry_connections(void);
+void router_retry_connections(int force);
 int router_is_clique_mode(routerinfo_t *router);
 int router_is_clique_mode(routerinfo_t *router);
 void router_upload_dir_desc_to_dirservers(int force);
 void router_upload_dir_desc_to_dirservers(int force);
 void mark_my_descriptor_dirty_if_older_than(time_t when);
 void mark_my_descriptor_dirty_if_older_than(time_t when);

+ 10 - 5
src/or/router.c

@@ -568,10 +568,13 @@ consider_publishable_server(time_t now, int force)
 
 
 /** OR only: if in clique mode, try to open connections to all of the
 /** OR only: if in clique mode, try to open connections to all of the
  * other ORs we know about. Otherwise, open connections to those we
  * other ORs we know about. Otherwise, open connections to those we
- * think are in clique mode.
+ * think are in clique mode.o
+ *
+ * If <b>force</b> is zero, only open the connection if we don't already
+ * have one.
  */
  */
 void
 void
-router_retry_connections(void)
+router_retry_connections(int force)
 {
 {
   int i;
   int i;
   routerinfo_t *router;
   routerinfo_t *router;
@@ -588,10 +591,12 @@ router_retry_connections(void)
       continue;
       continue;
     if (!clique_mode(options) && !router_is_clique_mode(router))
     if (!clique_mode(options) && !router_is_clique_mode(router))
       continue;
       continue;
-    if (!connection_get_by_identity_digest(router->identity_digest,
+    if (force ||
+        !connection_get_by_identity_digest(router->identity_digest,
                                            CONN_TYPE_OR)) {
                                            CONN_TYPE_OR)) {
-      /* not in the list */
-      log_fn(LOG_DEBUG,"connecting to OR at %s:%u.",router->address,router->or_port);
+      log_fn(LOG_INFO,"%sconnecting to %s at %s:%u.",
+             clique_mode(options) ? "(forced) " : "",
+             router->nickname, router->address, router->or_port);
       connection_or_connect(router->addr, router->or_port, router->identity_digest);
       connection_or_connect(router->addr, router->or_port, router->identity_digest);
     }
     }
   }
   }

+ 2 - 2
src/or/routerparse.c

@@ -738,7 +738,7 @@ check_directory_signature(const char *digest,
     return -1;
     return -1;
   }
   }
   log_fn(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
   log_fn(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
-  if (memcmp(digest, signed_digest, 20)) {
+  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
     log_fn(LOG_WARN, "Error reading directory: signature does not match.");
     log_fn(LOG_WARN, "Error reading directory: signature does not match.");
     return -1;
     return -1;
   }
   }
@@ -992,7 +992,7 @@ router_parse_entry_from_string(const char *s, const char *end)
     log_fn(LOG_WARN, "Invalid signature %d",t);
     log_fn(LOG_WARN, "Invalid signature %d",t);
     goto err;
     goto err;
   }
   }
-  if (memcmp(digest, signed_digest, 20)) {
+  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
     log_fn(LOG_WARN, "Mismatched signature");
     log_fn(LOG_WARN, "Mismatched signature");
     goto err;
     goto err;
   }
   }