Browse Source

Add and document router-status line using new unified liveness/verifiedness format; continue to generate running-routers; continue to parse running-routers when no router-status line is found

svn:r2592
Nick Mathewson 21 years ago
parent
commit
b90b2bb848
5 changed files with 278 additions and 155 deletions
  1. 26 4
      doc/tor-spec.txt
  2. 85 70
      src/or/dirserv.c
  3. 8 1
      src/or/or.h
  4. 123 60
      src/or/routerlist.c
  5. 36 20
      src/or/routerparse.c

+ 26 - 4
doc/tor-spec.txt

@@ -706,7 +706,7 @@ line, they must appear in the "ports" lines.
 
 
 A Directory begins with a "signed-directory" item, followed by one each of
 A Directory begins with a "signed-directory" item, followed by one each of
 the following, in any order: "recommended-software", "published",
 the following, in any order: "recommended-software", "published",
-"running-routers".  It may include any number of "opt" items.  After these
+"router-status".  It may include any number of "opt" items.  After these
 items, a directory includes any number of router descriptors, and a single
 items, a directory includes any number of router descriptors, and a single
 "directory-signature" item.
 "directory-signature" item.
 
 
@@ -723,7 +723,7 @@ items, a directory includes any number of router descriptors, and a single
         A list of which versions of which implementations are currently
         A list of which versions of which implementations are currently
         believed to be secure and compatible with the network.
         believed to be secure and compatible with the network.
 
 
-    "running-routers" comma-separated-list
+    "running-routers" space-separated-list
 
 
         A description of which routers are currently believed to be up or
         A description of which routers are currently believed to be up or
         down.  Every entry consists of an optional "!", followed by either an
         down.  Every entry consists of an optional "!", followed by either an
@@ -733,8 +733,30 @@ items, a directory includes any number of router descriptors, and a single
         If a router's nickname is given, exactly one router of that nickname
         If a router's nickname is given, exactly one router of that nickname
         will appear in the directory, and that router is "approved" by the
         will appear in the directory, and that router is "approved" by the
         directory server.  If a hashed identity key is given, that OR is not
         directory server.  If a hashed identity key is given, that OR is not
-        "approved".
+        "approved".  [XXXX The 'running-routers' line is only provided for
+        backward compatibility.  New code should parse 'router-status'
+        instead.]
 
 
+    "router-status" space-separated-list
+
+        A description of which routers are currently believed to be up or
+        down, and which are verified or unverified.  Contains one entry for
+        every router that the directory server knows.  Each entry is of the
+        format:
+
+              !name=$digest  [Verified router, currently not live.]
+              name=$digest   [Verified router, currently live.]
+              !$digest       [Unverified router, currently not live.]
+          or  $digest        [Unverified router, currently live.]
+
+        (where 'name' is the router's nickname and 'digest' is a hexadecimal
+        encoding of the hash of the routers' identity key).
+
+        When parsing this line, clients should only mark a router as
+        'verified' if its nickname AND digest match the one provided.
+        [XXXX 'router-status' was added in 0.0.9pre5; older directory code
+        uses 'running-routers' instead.]
+ 
     "directory-signature" nickname-of-dirserver NL Signature
     "directory-signature" nickname-of-dirserver NL Signature
 
 
 Note:  The router descriptor for the directory server MUST appear first.
 Note:  The router descriptor for the directory server MUST appear first.
@@ -763,7 +785,7 @@ entries.
 
 
         (see 7.2 above)
         (see 7.2 above)
 
 
-     "running-routers" list
+     "router-status" list
 
 
         (see 7.2 above)
         (see 7.2 above)
 
 

+ 85 - 70
src/or/dirserv.c

@@ -20,7 +20,8 @@ extern or_options_t options; /**< command-line and config-file options */
 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;
 
 
-static int list_running_servers(char **nicknames_out);
+static int list_server_status(char **running_routers_out,
+                              char **router_status_out);
 static void directory_remove_unrecognized(void);
 static void directory_remove_unrecognized(void);
 static int dirserv_regenerate_directory(void);
 static int dirserv_regenerate_directory(void);
 
 
@@ -456,71 +457,80 @@ dirserv_load_from_directory_string(const char *dir)
   return 0;
   return 0;
 }
 }
 
 
-/** Set *<b>nicknames_out</b> to a comma-separated list of all the ORs that we
- * believe are currently running (because we have open connections to
- * them).  Return 0 on success; -1 on error.
+/**
+ * Allocate and return a description of the status of the server <b>desc</b>,
+ * for use in a running-routers line (if <b>rr_format</b> is true), or in a
+ * router-status line (if <b>rr_format</b> is false.  The server is listed 
+ * as running iff <b>is_live</b> is true.
  */
  */
-static int
-list_running_servers(char **nicknames_out)
+static char *
+list_single_server_status(descriptor_entry_t *desc, int is_live,
+                          int rr_format)
 {
 {
-  connection_t **connection_array;
-  int n_conns;
-  connection_t *conn;
+  char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */
   char *cp;
   char *cp;
-  int i;
-  size_t length;
-  smartlist_t *nicknames_up, *nicknames_down;
-  char *name;
-  const char *s;
-
-  *nicknames_out = NULL;
-  nicknames_up = smartlist_create();
-  nicknames_down = smartlist_create();
-  smartlist_add(nicknames_up, tor_strdup(options.Nickname));
-
-  get_connection_array(&connection_array, &n_conns);
-  for (i = 0; i<n_conns; ++i) {
-    conn = connection_array[i];
-    if (conn->type != CONN_TYPE_OR || !conn->nickname)
-      continue; /* only list connections to ORs with certificates. */
-    s = dirserv_get_nickname_by_digest(conn->identity_digest);
-    if (s) {
-      name = tor_strdup(s);
-    } else {
-      name = tor_malloc(HEX_DIGEST_LEN+2);
-      *name = '$';
-      base16_encode(name+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN);
-    }
 
 
-    if(conn->state == OR_CONN_STATE_OPEN)
-      smartlist_add(nicknames_up, name);
-    else
-      smartlist_add(nicknames_down, name);
-  }
-  length = smartlist_len(nicknames_up) +
-           2*smartlist_len(nicknames_down) + 1;
-           /* spaces + EOS + !'s + 1. */
-  SMARTLIST_FOREACH(nicknames_up, char *, c, length += strlen(c));
-  SMARTLIST_FOREACH(nicknames_down, char *, c, length += strlen(c));
-  *nicknames_out = tor_malloc_zero(length);
-  cp = *nicknames_out;
-  for (i = 0; i<smartlist_len(nicknames_up); ++i) {
-    if (i)
-      strcat(cp, " ");
-    strcat(cp, (char*)smartlist_get(nicknames_up,i)); /* can't overflow */
-    while (*cp)
-      ++cp;
-  }
-  for (i = 0; i<smartlist_len(nicknames_down); ++i) {
-    strcat(cp, " !");
-    strcat(cp, (char*)smartlist_get(nicknames_down,i)); /* can't overflow */
-    while (*cp)
-      ++cp;
-  }
-  SMARTLIST_FOREACH(nicknames_up, char *, victim, tor_free(victim));
-  SMARTLIST_FOREACH(nicknames_down, char *, victim, tor_free(victim));
-  smartlist_free(nicknames_up);
-  smartlist_free(nicknames_down);
+  tor_assert(desc);
+  tor_assert(desc->router);
+
+  cp = buf;
+  if (!is_live) {
+    *cp++ = '!';
+  }
+  if (desc->verified) {
+    strcpy(cp, desc->nickname);
+    cp += strlen(cp);
+    if (!rr_format)
+      *cp++ = '=';
+  }
+  if (!desc->verified || !rr_format) {
+    *cp++ = '$';
+    base16_encode(cp, HEX_DIGEST_LEN+1, desc->router->identity_digest,
+                  DIGEST_LEN);
+  }
+  return tor_strdup(buf);
+}
+
+/** Allocate the contents of a running-routers line and a router-status line,
+ * and store them in *<b>running_routers_out</b> and *<b>router_status_out</b>
+ * respectively.  Return 0 on success, -1 on failure.
+ */
+static int
+list_server_status(char **running_routers_out, char **router_status_out)
+{
+  /* List of entries in running-routers style: An optional !, then either
+   * a nickname or a dollar-prefixed hexdigest. */
+  smartlist_t *rr_entries; 
+  /* List of entries in a router-status style: An optional !, then an optional
+   * equals-suffixed nickname, then a dollar-prefixed hexdigest. */
+  smartlist_t *rs_entries;
+
+  tor_assert(running_routers_out || router_status_out);
+
+  rr_entries = smartlist_create();
+  rs_entries = smartlist_create();
+
+  SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
+  {
+    int is_live;
+    tor_assert(d->router);
+    connection_t *conn = connection_get_by_identity_digest(
+                    d->router->identity_digest, CONN_TYPE_OR);
+    is_live = (conn && conn->state == OR_CONN_STATE_OPEN);
+    smartlist_add(rr_entries, list_single_server_status(d, is_live, 1));
+    smartlist_add(rs_entries, list_single_server_status(d, is_live, 0));
+  });
+
+  if (running_routers_out)
+    *running_routers_out = smartlist_join_strings(rr_entries, " ", 0);
+  if (router_status_out)
+    *router_status_out = smartlist_join_strings(rs_entries, " ", 0);
+
+  SMARTLIST_FOREACH(rr_entries, char *, cp, tor_free(cp));
+  SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp));
+  smartlist_free(rr_entries);
+  smartlist_free(rs_entries);
+
   return 0;
   return 0;
 }
 }
 
 
@@ -557,7 +567,8 @@ int
 dirserv_dump_directory_to_string(char *s, size_t maxlen,
 dirserv_dump_directory_to_string(char *s, size_t maxlen,
                                  crypto_pk_env_t *private_key)
                                  crypto_pk_env_t *private_key)
 {
 {
-  char *cp, *eos;
+  char *eos, *cp;
+  char *running_routers, *router_status;
   char *identity_pkey; /* Identity key, DER64-encoded. */
   char *identity_pkey; /* Identity key, DER64-encoded. */
   char *recommended_versions;
   char *recommended_versions;
   char digest[20];
   char digest[20];
@@ -570,7 +581,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen,
   if (!descriptor_list)
   if (!descriptor_list)
     descriptor_list = smartlist_create();
     descriptor_list = smartlist_create();
 
 
-  if (list_running_servers(&cp))
+  if (list_server_status(&running_routers, &router_status))
     return -1;
     return -1;
 
 
   /* ASN.1-encode the public key.  This is a temporary measure; once
   /* ASN.1-encode the public key.  This is a temporary measure; once
@@ -612,10 +623,13 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen,
            "published %s\n"
            "published %s\n"
            "recommended-software %s\n"
            "recommended-software %s\n"
            "running-routers %s\n"
            "running-routers %s\n"
+           "opt router-status %s\n"
            "opt dir-signing-key %s\n\n",
            "opt dir-signing-key %s\n\n",
-           published, recommended_versions, cp, identity_pkey);
+           published, recommended_versions, running_routers, router_status,
+           identity_pkey);
 
 
-  tor_free(cp);
+  tor_free(running_routers);
+  tor_free(router_status);
   tor_free(identity_pkey);
   tor_free(identity_pkey);
   i = strlen(s);
   i = strlen(s);
   cp = s+i;
   cp = s+i;
@@ -788,6 +802,7 @@ static size_t runningrouters_len=0;
 static int generate_runningrouters(crypto_pk_env_t *private_key)
 static int generate_runningrouters(crypto_pk_env_t *private_key)
 {
 {
   char *s, *cp;
   char *s, *cp;
+  char *router_status;
   char digest[DIGEST_LEN];
   char digest[DIGEST_LEN];
   char signature[PK_BYTES];
   char signature[PK_BYTES];
   int i;
   int i;
@@ -798,7 +813,7 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
 
 
   len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
   len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
   s = tor_malloc_zero(len);
   s = tor_malloc_zero(len);
-  if (list_running_servers(&cp))
+  if (list_server_status(NULL, &router_status))
     return -1;
     return -1;
   /* ASN.1-encode the public key.  This is a temporary measure; once
   /* ASN.1-encode the public key.  This is a temporary measure; once
    * everyone is running 0.0.9pre3 or later, we can shift to using a
    * everyone is running 0.0.9pre3 or later, we can shift to using a
@@ -822,12 +837,12 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
   format_iso_time(published, published_on);
   format_iso_time(published, published_on);
   sprintf(s, "network-status\n"
   sprintf(s, "network-status\n"
              "published %s\n"
              "published %s\n"
-             "running-routers %s\n"
+             "router-status %s\n"
              "opt dir-signing-key %s\n"
              "opt dir-signing-key %s\n"
              "directory-signature %s\n"
              "directory-signature %s\n"
              "-----BEGIN SIGNATURE-----\n",
              "-----BEGIN SIGNATURE-----\n",
-          published, cp, identity_pkey, options.Nickname);
-  tor_free(cp);
+          published, router_status, identity_pkey, options.Nickname);
+  tor_free(router_status);
   tor_free(identity_pkey);
   tor_free(identity_pkey);
   if (router_get_runningrouters_hash(s,digest)) {
   if (router_get_runningrouters_hash(s,digest)) {
     log_fn(LOG_WARN,"couldn't compute digest");
     log_fn(LOG_WARN,"couldn't compute digest");

+ 8 - 1
src/or/or.h

@@ -621,6 +621,7 @@ typedef struct running_routers_t {
   time_t published_on; /**< When was the list marked as published? */
   time_t published_on; /**< When was the list marked as published? */
   /** Which ORs are on the list?  Entries may be prefixed with ! and $. */
   /** Which ORs are on the list?  Entries may be prefixed with ! and $. */
   smartlist_t *running_routers;
   smartlist_t *running_routers;
+  int is_running_routers_format; /**< Are we using the old entry format? */
 } running_routers_t;
 } running_routers_t;
 
 
 /** Holds accounting information for a single step in the layered encryption
 /** Holds accounting information for a single step in the layered encryption
@@ -1469,9 +1470,14 @@ int router_exit_policy_rejects_all(routerinfo_t *router);
 void running_routers_free(running_routers_t *rr);
 void running_routers_free(running_routers_t *rr);
 void routerlist_update_from_runningrouters(routerlist_t *list,
 void routerlist_update_from_runningrouters(routerlist_t *list,
                                            running_routers_t *rr);
                                            running_routers_t *rr);
+int routers_update_status_from_entry(smartlist_t *routers,
+                                        time_t list_time,
+                                        const char *s,
+                                        int rr_format);
 int router_update_status_from_smartlist(routerinfo_t *r,
 int router_update_status_from_smartlist(routerinfo_t *r,
                                         time_t list_time,
                                         time_t list_time,
-                                        smartlist_t *running_list);
+                                        smartlist_t *running_list,
+                                        int rr_format);
 void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest);
 void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest);
 void clear_trusted_dir_servers(void);
 void clear_trusted_dir_servers(void);
 
 
@@ -1493,6 +1499,7 @@ int router_get_runningrouters_hash(const char *s, char *digest);
 int router_parse_list_from_string(const char **s,
 int router_parse_list_from_string(const char **s,
                                   routerlist_t **dest,
                                   routerlist_t **dest,
                                   smartlist_t *good_nickname_list,
                                   smartlist_t *good_nickname_list,
+                                  int rr_format,                        
                                   time_t published);
                                   time_t published);
 int router_parse_routerlist_from_directory(const char *s,
 int router_parse_routerlist_from_directory(const char *s,
                                            routerlist_t **dest,
                                            routerlist_t **dest,

+ 123 - 60
src/or/routerlist.c

@@ -1018,8 +1018,8 @@ void running_routers_free(running_routers_t *rr)
 void routerlist_update_from_runningrouters(routerlist_t *list,
 void routerlist_update_from_runningrouters(routerlist_t *list,
                                            running_routers_t *rr)
                                            running_routers_t *rr)
 {
 {
-  int n_routers, i;
-  routerinfo_t *router, *me = router_get_my_routerinfo();
+  routerinfo_t *me = router_get_my_routerinfo();
+  smartlist_t *all_routers;
   if (!list)
   if (!list)
     return;
     return;
   if (list->published_on >= rr->published_on)
   if (list->published_on >= rr->published_on)
@@ -1027,18 +1027,15 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
   if (list->running_routers_updated_on >= rr->published_on)
   if (list->running_routers_updated_on >= rr->published_on)
     return;
     return;
 
 
-  if(me) { /* learn if the dirservers think I'm verified */
-    router_update_status_from_smartlist(me,
-                                        rr->published_on,
-                                        rr->running_routers);
-  }
-  n_routers = smartlist_len(list->routers);
-  for (i=0; i<n_routers; ++i) {
-    router = smartlist_get(list->routers, i);
-    router_update_status_from_smartlist(router,
-                                        rr->published_on,
-                                        rr->running_routers);
-  }
+  all_routers = smartlist_create();
+  if(me) /* learn if the dirservers think I'm verified */
+    smartlist_add(all_routers, me);
+  
+  smartlist_add_all(all_routers,list->routers);
+  SMARTLIST_FOREACH(rr->running_routers, const char *, cp,
+     routers_update_status_from_entry(all_routers, rr->published_on,
+                                      cp, rr->is_running_routers_format));
+  smartlist_free(all_routers);
   list->running_routers_updated_on = rr->published_on;
   list->running_routers_updated_on = rr->published_on;
 }
 }
 
 
@@ -1046,6 +1043,14 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
  * based in its status in the list of strings stored in <b>running_list</b>.
  * based in its status in the list of strings stored in <b>running_list</b>.
  * All entries in <b>running_list</b> follow one of these formats:
  * All entries in <b>running_list</b> follow one of these formats:
  * <ol><li> <b>nickname</b> -- router is running and verified.
  * <ol><li> <b>nickname</b> -- router is running and verified.
+ *          (running-routers format)
+ *     <li> !<b>nickname</b> -- router is not-running and verified.
+ *          (running-routers format)
+ *     <li> <b>nickname</b>=$<b>hexdigest</b> -- router is running and 
+ *          verified. (router-status format)
+ *          (router-status format)
+ *     <li> !<b>nickname</b>=$<b>hexdigest</b> -- router is running and 
+ *          verified. (router-status format)
  *     <li> !<b>nickname</b> -- router is not-running and verified.
  *     <li> !<b>nickname</b> -- router is not-running and verified.
  *     <li> $<b>hexdigest</b> -- router is running and unverified.
  *     <li> $<b>hexdigest</b> -- router is running and unverified.
  *     <li> !$<b>hexdigest</b> -- router is not-running and unverified.
  *     <li> !$<b>hexdigest</b> -- router is not-running and unverified.
@@ -1053,57 +1058,115 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
  *
  *
  * Return 1 if we found router in running_list, else return 0.
  * Return 1 if we found router in running_list, else return 0.
  */
  */
-int router_update_status_from_smartlist(routerinfo_t *router,
-                                        time_t list_time,
-                                        smartlist_t *running_list)
+int routers_update_status_from_entry(smartlist_t *routers,
+                                     time_t list_time,
+                                     const char *s,
+                                     int rr_format)
 {
 {
-  int n_names, i, running, approved;
-  const char *name;
-#if 1
-  char *cp;
-  size_t n;
-  n = 0;
-  for (i=0; i<smartlist_len(running_list); ++i) {
-    name = smartlist_get(running_list, i);
-    n += strlen(name) + 1;
+  int is_running = 1;
+  int is_verified = 0;
+  int hex_digest_set = 0;
+  char nickname[MAX_NICKNAME_LEN+1];
+  char hexdigest[HEX_DIGEST_LEN+1];
+  char digest[DIGEST_LEN];
+  const char *cp, *end;
+
+  /* First, parse the entry. */
+  cp = s;
+  if (*cp == '!') {
+    is_running = 0;
+    ++cp;
   }
   }
-  cp = tor_malloc(n+2);
-  cp[0] = '\0';
-  for (i=0; i<smartlist_len(running_list); ++i) {
-    name = smartlist_get(running_list, i);
-    strlcat(cp, name, n);
-    strlcat(cp, " ", n);
+
+  if (*cp != '$') {
+    /* It starts with a non-dollar character; that's a nickname.  The nickname
+     * entry will either extend to a NUL (old running-routers format) or to an
+     * equals sign (new router-status format). */
+    is_verified = 1;
+    end = strchr(cp, '=');
+    if (!end)
+      end = strchr(cp,'\0');
+    tor_assert(end);
+    /* 'end' now points on character beyond the end of the nickname */
+    if (end == cp || end-cp > MAX_NICKNAME_LEN) {
+      log_fn(LOG_WARN, "Bad nickname length (%d) in router status entry (%s)",
+             end-cp, s);
+      return -1;
+    }
+    memcpy(nickname, cp, end-cp);
+    nickname[end-cp]='\0';
+    if (!is_legal_nickname(nickname)) {
+      log_fn(LOG_WARN, "Bad nickname (%s) in router status entry (%s)",
+             nickname, s);
+      return -1;
+    }
+    cp = end;
+    if (*cp == '=')
+      ++cp;
   }
   }
-  log_fn(LOG_DEBUG, "Updating status of %s from list \"%s\"",
-         router->nickname, cp);
-  tor_free(cp);
-#endif
-
-  running = approved = 0;
-  n_names = smartlist_len(running_list);
-  for (i=0; i<n_names; ++i) {
-    name = smartlist_get(running_list, i);
-    if (*name != '!') {
-      if (router_nickname_matches(router, name)) {
-        if (router->status_set_at < list_time) {
-          router->status_set_at = list_time;
-          router->is_running = 1;
-        }
-        router->is_verified = (name[0] != '$');
-        return 1;
-      }
-    } else { /* *name == '!' */
-      name++;
-      if (router_nickname_matches(router, name)) {
-        if (router->status_set_at < list_time) {
-          router->status_set_at = list_time;
-          router->is_running = 0;
-        }
-        router->is_verified = (name[0] != '$');
-        return 1;
-      }
+  /* 'end' now points to the start of a hex digest, or EOS. */
+
+  /* Parse the hexdigest portion of the status. */
+  if (*cp == '$') {
+    hex_digest_set = 1;
+    ++cp;
+    if (strlen(cp) != HEX_DIGEST_LEN) {
+      log_fn(LOG_WARN, "Bad length (%d) on digest in router status entry (%s)",
+             strlen(cp), s);
+      return -1;
+    }
+    strcpy(hexdigest, cp);
+    if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0) {
+      log_fn(LOG_WARN, "Invalid digest in router status entry (%s)", s);
+      return -1;
     }
     }
   }
   }
+
+  /* Make sure that the entry was in the right format. */
+  if (rr_format) {
+    if (is_verified == hex_digest_set) {
+      log_fn(LOG_WARN, "Invalid syntax for running-routers member (%s)", s);
+      return -1;
+    }
+  } else {
+    if (!hex_digest_set) {
+      log_fn(LOG_WARN, "Invalid syntax for router-status member (%s)", s);
+      return -1;
+    }
+  }
+
+  /* Okay, we're done parsing. For all routers that match, update their status.
+   */
+  SMARTLIST_FOREACH(routers, routerinfo_t *, r,
+  {
+    int nickname_matches = is_verified && !strcasecmp(r->nickname, nickname);
+    int digest_matches = !memcmp(digest, r->identity_digest, DIGEST_LEN);
+    if (nickname_matches && (digest_matches||rr_format))
+      r->is_verified = 1;
+    else if (digest_matches)
+      r->is_verified = 0;
+    if (digest_matches || (nickname_matches&&rr_format))
+      if (r->status_set_at < list_time) {
+        r->is_running = is_running;
+        r->status_set_at = time(NULL);
+      }
+  });
+ 
+  return 0;
+}
+
+int router_update_status_from_smartlist(routerinfo_t *router,
+                                        time_t list_time,
+                                        smartlist_t *running_list,
+                                        int rr_format)
+{
+  smartlist_t *rl;
+  rl = smartlist_create();
+  smartlist_add(rl,router);
+  SMARTLIST_FOREACH(running_list, const char *, cp,
+            routers_update_status_from_entry(rl,list_time,cp,rr_format));
+                                                
+  smartlist_free(rl);
   return 0;
   return 0;
 }
 }
 
 

+ 36 - 20
src/or/routerparse.c

@@ -32,6 +32,7 @@ typedef enum {
   K_ROUTER_SIGNATURE,
   K_ROUTER_SIGNATURE,
   K_PUBLISHED,
   K_PUBLISHED,
   K_RUNNING_ROUTERS,
   K_RUNNING_ROUTERS,
+  K_ROUTER_STATUS,
   K_PLATFORM,
   K_PLATFORM,
   K_OPT,
   K_OPT,
   K_BANDWIDTH,
   K_BANDWIDTH,
@@ -106,6 +107,7 @@ static struct {
   { "onion-key",           K_ONION_KEY,           NO_ARGS, NEED_KEY,RTR_ONLY },
   { "onion-key",           K_ONION_KEY,           NO_ARGS, NEED_KEY,RTR_ONLY },
   { "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ,RTR_ONLY },
   { "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ,RTR_ONLY },
   { "running-routers",     K_RUNNING_ROUTERS,     ARGS,    NO_OBJ,  DIR_ONLY },
   { "running-routers",     K_RUNNING_ROUTERS,     ARGS,    NO_OBJ,  DIR_ONLY },
+  { "router-status",       K_ROUTER_STATUS,       ARGS,    NO_OBJ,  DIR_ONLY },
   { "ports",               K_PORTS,               ARGS,    NO_OBJ,  RTR_ONLY },
   { "ports",               K_PORTS,               ARGS,    NO_OBJ,  RTR_ONLY },
   { "bandwidth",           K_BANDWIDTH,           ARGS,    NO_OBJ,  RTR_ONLY },
   { "bandwidth",           K_BANDWIDTH,           ARGS,    NO_OBJ,  RTR_ONLY },
   { "platform",            K_PLATFORM,        CONCAT_ARGS, NO_OBJ,  RTR_ONLY },
   { "platform",            K_PLATFORM,        CONCAT_ARGS, NO_OBJ,  RTR_ONLY },
@@ -393,9 +395,13 @@ router_parse_routerlist_from_directory(const char *str,
   }
   }
   versions = tok->n_args ? tor_strdup(tok->args[0]) : tor_strdup("");
   versions = tok->n_args ? tor_strdup(tok->args[0]) : tor_strdup("");
 
 
-  if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
-    log_fn(LOG_WARN, "Missing running-routers line from directory.");
-    goto err;
+  /* Prefer router-status, then running-routers. */
+  if (!(tok = find_first_by_keyword(tokens, K_ROUTER_STATUS))) {
+    if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
+      log_fn(LOG_WARN,
+             "Missing running-routers/router-status line from directory.");
+      goto err;
+    }
   }
   }
 
 
   good_nickname_list = smartlist_create();
   good_nickname_list = smartlist_create();
@@ -408,25 +414,21 @@ router_parse_routerlist_from_directory(const char *str,
    * router. */
    * router. */
   str = end;
   str = end;
   if (router_parse_list_from_string(&str, &new_dir,
   if (router_parse_list_from_string(&str, &new_dir,
-                                    good_nickname_list, published_on)) {
+                                    good_nickname_list, 
+                                    tok->tp==K_RUNNING_ROUTERS,
+                                    published_on)) {
     log_fn(LOG_WARN, "Error reading routers from directory");
     log_fn(LOG_WARN, "Error reading routers from directory");
     goto err;
     goto err;
   }
   }
 
 
-  new_dir->software_versions = versions; versions = NULL;
-  new_dir->published_on = published_on;
-
-  SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
-  smartlist_free(tokens);
-  tokens = NULL;
-
   /* Determine if my routerinfo is considered verified. */
   /* Determine if my routerinfo is considered verified. */
   {
   {
     static int have_warned_about_unverified_status = 0;
     static int have_warned_about_unverified_status = 0;
     routerinfo_t *me = router_get_my_routerinfo();
     routerinfo_t *me = router_get_my_routerinfo();
     if(me) {
     if(me) {
       if(router_update_status_from_smartlist(me, published_on,
       if(router_update_status_from_smartlist(me, published_on,
-                                             good_nickname_list)==1 &&
+                                             good_nickname_list,
+                                          tok->tp==K_RUNNING_ROUTERS)==1 &&
         me->is_verified == 0 && !have_warned_about_unverified_status) {
         me->is_verified == 0 && !have_warned_about_unverified_status) {
         log_fn(LOG_WARN,"Dirserver %s lists your server as unverified. Please consider sending your identity fingerprint to the tor-ops.", dirnickname);
         log_fn(LOG_WARN,"Dirserver %s lists your server as unverified. Please consider sending your identity fingerprint to the tor-ops.", dirnickname);
         have_warned_about_unverified_status = 1;
         have_warned_about_unverified_status = 1;
@@ -434,6 +436,13 @@ router_parse_routerlist_from_directory(const char *str,
     }
     }
   }
   }
 
 
+  new_dir->software_versions = versions; versions = NULL;
+  new_dir->published_on = published_on;
+
+  SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
+  smartlist_free(tokens);
+  tokens = NULL;
+
   if (*dest)
   if (*dest)
     routerlist_free(*dest);
     routerlist_free(*dest);
   *dest = new_dir;
   *dest = new_dir;
@@ -497,14 +506,18 @@ router_parse_runningrouters(const char *str)
      goto err;
      goto err;
   }
   }
 
 
-  if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
-    log_fn(LOG_WARN, "Missing running-routers line from directory.");
-    goto err;
+  if (!(tok = find_first_by_keyword(tokens, K_ROUTER_STATUS))) {
+    if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
+      log_fn(LOG_WARN,
+             "Missing running-routers/router-status line from directory.");
+      goto err;
+    }
   }
   }
 
 
   new_list = tor_malloc_zero(sizeof(running_routers_t));
   new_list = tor_malloc_zero(sizeof(running_routers_t));
   new_list->published_on = published_on;
   new_list->published_on = published_on;
   new_list->running_routers = smartlist_create();
   new_list->running_routers = smartlist_create();
+  new_list->is_running_routers_format = (tok->tp == K_RUNNING_ROUTERS);
   for (i=0;i<tok->n_args;++i) {
   for (i=0;i<tok->n_args;++i) {
     smartlist_add(new_list->running_routers, tok->args[i]);
     smartlist_add(new_list->running_routers, tok->args[i]);
   }
   }
@@ -661,7 +674,7 @@ static int check_directory_signature(const char *digest,
 int
 int
 router_parse_list_from_string(const char **s, routerlist_t **dest,
 router_parse_list_from_string(const char **s, routerlist_t **dest,
                               smartlist_t *good_nickname_list,
                               smartlist_t *good_nickname_list,
-                              time_t published_on)
+                              int rr_format, time_t published_on)
 {
 {
   routerinfo_t *router;
   routerinfo_t *router;
   smartlist_t *routers;
   smartlist_t *routers;
@@ -692,10 +705,7 @@ router_parse_list_from_string(const char **s, routerlist_t **dest,
       continue;
       continue;
     }
     }
 
 
-    if (good_nickname_list) {
-      router_update_status_from_smartlist(router, published_on,
-                                          good_nickname_list);
-    } else {
+    if (!good_nickname_list) {
       router->is_running = 1; /* start out assuming all dirservers are up */
       router->is_running = 1; /* start out assuming all dirservers are up */
       router->is_verified = 1;
       router->is_verified = 1;
       router->status_set_at = time(NULL);
       router->status_set_at = time(NULL);
@@ -704,6 +714,12 @@ router_parse_list_from_string(const char **s, routerlist_t **dest,
     log_fn(LOG_DEBUG,"just added router #%d.",smartlist_len(routers));
     log_fn(LOG_DEBUG,"just added router #%d.",smartlist_len(routers));
   }
   }
 
 
+  if (good_nickname_list) {
+    SMARTLIST_FOREACH(good_nickname_list, const char *, cp,
+           routers_update_status_from_entry(routers, published_on,
+                                            cp, rr_format));
+  }
+
   if (*dest)
   if (*dest)
     routerlist_free(*dest);
     routerlist_free(*dest);
   *dest = tor_malloc_zero(sizeof(routerlist_t));
   *dest = tor_malloc_zero(sizeof(routerlist_t));