[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] Remove descriptor_list and use routerlist instead. Make di...



Update of /home/or/cvsroot/tor/src/or
In directory moria:/tmp/cvs-serv32430/src/or

Modified Files:
	dirserv.c main.c or.h routerlist.c 
Log Message:
Remove descriptor_list and use routerlist instead.  Make directories manage routerlist a little better.

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/dirserv.c,v
retrieving revision 1.187
retrieving revision 1.188
diff -u -d -r1.187 -r1.188
--- dirserv.c	26 Aug 2005 20:08:12 -0000	1.187
+++ dirserv.c	26 Aug 2005 20:59:04 -0000	1.188
@@ -235,22 +235,14 @@
  *    Descriptor list
  */
 
-/** List of routerinfo_t for all server descriptors that this dirserv
- * is holding.
- * XXXX This should eventually get coalesced into routerlist.c
- */
-static smartlist_t *descriptor_list = NULL;
-
-/** Release all storage that the dirserv is holding for server
- * descriptors. */
-void
-dirserv_free_descriptors()
+static smartlist_t *
+get_descriptor_list(void)
 {
-  if (!descriptor_list)
-    return;
-  SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
-                    routerinfo_free(ri));
-  smartlist_clear(descriptor_list);
+  routerlist_t *routerlist;
+  router_get_routerlist(&routerlist);
+  if (!routerlist)
+    return NULL;
+  return routerlist->routers;
 }
 
 /** Return -1 if <b>ri</b> has a private or otherwise bad address,
@@ -274,64 +266,18 @@
   return 0;
 }
 
-/** Parse the server descriptor at *desc and maybe insert it into the
- * list of server descriptors, and (if the descriptor is well-formed)
- * advance *desc immediately past the descriptor's end.  Set msg to a
- * message that should be passed back to the origin of this descriptor, or
- * to NULL.
- *
- * Return 1 if descriptor is well-formed and accepted;
- *  0 if well-formed and server is unapproved but accepted;
- * -1 if it looks vaguely like a router descriptor but rejected;
- * -2 if we can't find a router descriptor in *desc.
- */
 int
-dirserv_add_descriptor(const char **desc, const char **msg)
+dirserv_wants_to_reject_router(routerinfo_t *ri, int *verified,
+                               const char **msg)
 {
-  routerinfo_t *ri = NULL, *ri_old=NULL;
-  int i, r, found=-1;
-  char *start, *end;
-  char *desc_tmp = NULL;
-  size_t desc_len;
-  time_t now;
-  int verified=1; /* whether we knew its fingerprint already */
-  tor_assert(msg);
-  *msg = NULL;
-  if (!descriptor_list)
-    descriptor_list = smartlist_create();
-
-  start = strstr(*desc, "router ");
-  if (!start) {
-    log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
-    return -2;
-  }
-  if ((end = strstr(start+6, "\nrouter "))) {
-    ++end; /* Include NL. */
-  } else if ((end = strstr(start+6, "\ndirectory-signature"))) {
-    ++end;
-  } else {
-    end = start+strlen(start);
-  }
-  desc_len = end-start;
-  desc_tmp = tor_strndup(start, desc_len); /* Is this strndup still needed???*/
-
-  /* Check: is the descriptor syntactically valid? */
-  ri = router_parse_entry_from_string(desc_tmp, NULL);
-  tor_free(desc_tmp);
-  if (!ri) {
-    log(LOG_WARN, "Couldn't parse descriptor");
-    *msg = "Rejected: Couldn't parse server descriptor.";
-    return -1;
-  }
   /* Okay.  Now check whether the fingerprint is recognized. */
-  r = dirserv_router_fingerprint_is_known(ri);
+  int r = dirserv_router_fingerprint_is_known(ri);
+  time_t now;
   if (r==-1) {
     log_fn(LOG_WARN, "Known nickname '%s', wrong fingerprint. Not adding (ContactInfo '%s', platform '%s').",
            ri->nickname, ri->contact_info ? ri->contact_info : "",
            ri->platform ? ri->platform : "");
     *msg = "Rejected: There is already a verified server with this nickname and a different fingerprint.";
-    routerinfo_free(ri);
-    *desc = end;
     return -1;
   } else if (r==0) {
     char fp[FINGERPRINT_LEN+1];
@@ -342,7 +288,9 @@
     } else {
       log_fn(LOG_INFO, "Fingerprint line: %s %s", ri->nickname, fp);
     }
-    verified = 0;
+    *verified = 0;
+  } else {
+    *verified = 1;
   }
   /* Is there too much clock skew? */
   now = time(NULL);
@@ -352,8 +300,6 @@
            ri->contact_info ? ri->contact_info : "",
            ri->platform ? ri->platform : "");
     *msg = "Rejected: Your clock is set too far in the future, or your timezone is not correct.";
-    routerinfo_free(ri);
-    *desc = end;
     return -1;
   }
   if (ri->published_on < now-ROUTER_MAX_AGE) {
@@ -362,8 +308,6 @@
            ri->contact_info ? ri->contact_info : "",
            ri->platform ? ri->platform : "");
     *msg = "Rejected: Server is expired, or your clock is too far in the past, or your timezone is not correct.";
-    routerinfo_free(ri);
-    *desc = end;
     return -1;
   }
   if (dirserv_router_has_valid_address(ri) < 0) {
@@ -372,55 +316,63 @@
            ri->contact_info ? ri->contact_info : "",
            ri->platform ? ri->platform : "");
     *msg = "Rejected: Address is not an IP, or IP is a private address.";
-    routerinfo_free(ri);
-    *desc = end;
     return -1;
   }
 
-  /* Do we already have an entry for this router? */
-  for (i = 0; i < smartlist_len(descriptor_list); ++i) {
-    ri_old = smartlist_get(descriptor_list, i);
-    if (!memcmp(ri->identity_digest, ri_old->identity_digest, DIGEST_LEN)) {
-      found = i;
-      break;
-    }
+  return 0;
+}
+
+
+
+/** Parse the server descriptor at *desc and maybe insert it into the
+ * list of server descriptors, and (if the descriptor is well-formed)
+ * advance *desc immediately past the descriptor's end.  Set msg to a
+ * message that should be passed back to the origin of this descriptor, or
+ * to NULL.
+ *
+ * Return 1 if descriptor is well-formed and accepted;
+ *  0 if well-formed and server is unapproved but accepted;
+ * -1 if it looks vaguely like a router descriptor but rejected;
+ * -2 if we can't find a router descriptor in *desc.
+ */
+int
+dirserv_add_descriptor(const char **desc, const char **msg)
+{
+  routerinfo_t *ri = NULL;
+  char *start, *end;
+  char *desc_tmp = NULL;
+  size_t desc_len;
+  tor_assert(msg);
+  *msg = NULL;
+
+  start = strstr(*desc, "router ");
+  if (!start) {
+    log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
+    return -2;
   }
-  if (found >= 0) {
-    char hex_digest[HEX_DIGEST_LEN+1];
-    base16_encode(hex_digest, HEX_DIGEST_LEN+1, ri->identity_digest,DIGEST_LEN);
-    /* if so, decide whether to update it. */
-    if (ri_old->published_on >= ri->published_on) {
-      /* We already have a newer or equal-time descriptor */
-      log_fn(LOG_INFO,"We already have a new enough desc for server %s (nickname '%s'). Not adding.",hex_digest,ri->nickname);
-      *msg = "We already have a newer descriptor.";
-      /* This isn't really an error; return success. */
-      routerinfo_free(ri);
-      *desc = end;
-      return verified;
-    }
-    /* 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);
-    if (ri->addr == ri_old->addr && ri->or_port == ri_old->or_port) {
-      ri->last_reachable = ri_old->last_reachable; /* these carry over */
-      ri->testing_since = ri_old->testing_since;
-    }
-    *msg = verified?"Verified server updated":"Unverified server updated. (Have you sent us your key fingerprint?)";
-    routerinfo_free(ri_old);
-    smartlist_del_keeporder(descriptor_list, found);
+  if ((end = strstr(start+6, "\nrouter "))) {
+    ++end; /* Include NL. */
+  } else if ((end = strstr(start+6, "\ndirectory-signature"))) {
+    ++end;
   } else {
-    /* Add at the end. */
-    log_fn(LOG_INFO,"Dirserv adding desc for nickname '%s'",ri->nickname);
-    *msg = verified?"Verified server added":"Unverified server added. (Have you sent us your key fingerprint?)";
+    end = start+strlen(start);
   }
+  desc_len = end-start;
+  desc_tmp = tor_strndup(start, desc_len); /* Is this strndup still needed???*/
 
-  ri->is_verified = verified ||
-                    tor_version_as_new_as(ri->platform,"0.1.0.2-rc");
-  smartlist_add(descriptor_list, ri);
-
-  *desc = end;
-  directory_set_dirty();
-
-  return verified;
+  /* Check: is the descriptor syntactically valid? */
+  ri = router_parse_entry_from_string(desc_tmp, NULL);
+  tor_free(desc_tmp);
+  if (!ri) {
+    log(LOG_WARN, "Couldn't parse descriptor");
+    *msg = "Rejected: Couldn't parse server descriptor.";
+    return -1;
+  }
+  if (router_add_to_routerlist(ri, msg)) {
+    return -1;
+  } else {
+    return ri->is_verified ? 1 : 0;
+  }
 }
 
 /** Remove all descriptors whose nicknames or fingerprints no longer
@@ -431,27 +383,33 @@
 directory_remove_invalid(void)
 {
   int i;
-  int r;
-  routerinfo_t *ent;
+  int changed = 0;
+  smartlist_t *descriptor_list = get_descriptor_list();
+
   if (!descriptor_list)
-    descriptor_list = smartlist_create();
+    return;
 
   for (i = 0; i < smartlist_len(descriptor_list); ++i) {
-    ent = smartlist_get(descriptor_list, i);
-    r = dirserv_router_fingerprint_is_known(ent);
+    routerinfo_t *ent = smartlist_get(descriptor_list, i);
+    int r = dirserv_router_fingerprint_is_known(ent);
     if (r<0) {
       log(LOG_INFO, "Router '%s' is now verified with a key; removing old router with same name and different key.",
           ent->nickname);
       routerinfo_free(ent);
       smartlist_del(descriptor_list, i--);
+      changed = 1;
     } else if (r>0 && !ent->is_verified) {
       log(LOG_INFO, "Router '%s' is now approved.", ent->nickname);
       ent->is_verified = 1;
+      changed = 1;
     } else if (r==0 && ent->is_verified) {
       log(LOG_INFO, "Router '%s' is no longer approved.", ent->nickname);
       ent->is_verified = 0;
+      changed = 1;
     }
   }
+  if (changed)
+    directory_set_dirty();
 }
 
 /** Write a list of unregistered descriptors into a newly allocated
@@ -467,6 +425,7 @@
   char *answer;
   routerinfo_t *ent;
   int min_bw = atoi(question);
+  smartlist_t *descriptor_list = get_descriptor_list();
 
   if (!descriptor_list)
     return tor_strdup("");
@@ -608,7 +567,11 @@
  * been found unreachable for the past several testing periods.
  */
 void
-dirserv_log_unreachable_servers(time_t now) {
+dirserv_log_unreachable_servers(time_t now)
+{
+  smartlist_t *descriptor_list = get_descriptor_list();
+  if (!descriptor_list)
+    return;
 
   SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
   {
@@ -631,7 +594,9 @@
  * (This function can go away when we merge descriptor-list and router-list.)
  */
 void
-dirserv_router_has_begun_reachability_testing(char *digest, time_t now) {
+dirserv_router_has_begun_reachability_testing(char *digest, time_t now)
+{
+  smartlist_t *descriptor_list = get_descriptor_list();
   if (!descriptor_list)
     return;
   SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
@@ -642,30 +607,6 @@
   });
 }
 
-/** Remove any descriptors from the directory that are more than <b>age</b>
- * seconds old.
- */
-void
-dirserv_remove_old_servers(int age)
-{
-  int i;
-  time_t cutoff;
-  routerinfo_t *ent;
-  if (!descriptor_list)
-    descriptor_list = smartlist_create();
-
-  cutoff = time(NULL) - age;
-  for (i = 0; i < smartlist_len(descriptor_list); ++i) {
-    ent = smartlist_get(descriptor_list, i);
-    if (ent->published_on <= cutoff) {
-      /* descriptor_list[i] is too old.  Remove it. */
-      routerinfo_free(ent);
-      smartlist_del(descriptor_list, i--);
-      directory_set_dirty();
-    }
-  }
-}
-
 /* Given a (possibly empty) list of config_line_t, each line of which contains
  * a list of comma-separated version numbers surrounded by optional space,
  * allocate and return a new string containing the version numbers, in order,
@@ -704,12 +645,13 @@
   char *buf = NULL;
   size_t buf_len;
   size_t identity_pkey_len;
+  smartlist_t *descriptor_list = get_descriptor_list();
 
   tor_assert(dir_out);
   *dir_out = NULL;
 
   if (!descriptor_list)
-    descriptor_list = smartlist_create();
+    return -1;
 
   if (list_server_status(descriptor_list, &router_status))
     return -1;
@@ -722,14 +664,13 @@
 
   recommended_versions = format_versions_list(get_options()->RecommendedVersions);
 
-  dirserv_remove_old_servers(ROUTER_MAX_AGE);
   published_on = time(NULL);
   format_iso_time(published, published_on);
 
   buf_len = 2048+strlen(recommended_versions)+
     strlen(router_status);
   SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
-                    buf_len += strlen(ri->signed_descriptor));
+                    buf_len += ri->signed_descriptor_len);
   buf = tor_malloc(buf_len);
   /* We'll be comparing against buf_len throughout the rest of the
      function, though strictly speaking we shouldn't be able to exceed
@@ -997,9 +938,7 @@
   crypto_pk_env_t *private_key = get_identity_key();
   char *identity_pkey; /* Identity key, DER64-encoded. */
   size_t identity_pkey_len;
-
-  if (!descriptor_list)
-    descriptor_list = smartlist_create();
+  smartlist_t *descriptor_list = get_descriptor_list();
 
   if (list_server_status(descriptor_list, &router_status)) {
     goto err;
@@ -1113,6 +1052,12 @@
   struct in_addr in;
   uint32_t addr;
   crypto_pk_env_t *private_key = get_identity_key();
+  smartlist_t *descriptor_list = get_descriptor_list();
+
+  if (!descriptor_list) {
+    log_fn(LOG_WARN, "Couldn't get router list.");
+    goto done;
+  }
 
   if (resolve_my_address(options, &addr, &hostname)<0) {
     log_fn(LOG_WARN, "Couldn't resolve my hostname");
@@ -1285,22 +1230,12 @@
 void
 dirserv_get_routerdescs(smartlist_t *descs_out, const char *key)
 {
-  smartlist_t *complete_list;
-
-  /* This is annoying. Can we unify these? */
-  if (descriptor_list)
-    complete_list = descriptor_list;
-  else {
-    routerlist_t *rlst;
-    router_get_routerlist(&rlst);
-    complete_list = rlst->routers;
-  }
-
+  smartlist_t *complete_list = get_descriptor_list();
   if (!complete_list)
     return;
 
   if (!strcmp(key, "/tor/server/all")) {
-    smartlist_add_all(descs_out, descriptor_list);
+    smartlist_add_all(descs_out, complete_list);
   } else if (!strcmp(key, "/tor/server/authority")) {
     routerinfo_t *ri = router_get_my_routerinfo();
     if (ri)
@@ -1323,7 +1258,7 @@
     smartlist_free(hexdigests);
     /* XXXX should always return own descriptor. or special-case it. or
      * something. */
-    SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
+    SMARTLIST_FOREACH(complete_list, routerinfo_t *, ri,
                       SMARTLIST_FOREACH(digests, const char *, d,
                         if (!memcmp(d,ri->identity_digest,DIGEST_LEN)) {
                           smartlist_add(descs_out,ri);
@@ -1352,6 +1287,7 @@
                         int as_advertised)
 {
   int i;
+  smartlist_t *descriptor_list = get_descriptor_list();
   tor_assert(address);
   tor_assert(digest_rcvd);
   tor_assert(nickname_rcvd);
@@ -1359,6 +1295,8 @@
   if (!descriptor_list)
     return;
 
+  // XXXXNM We should really have a better solution here than dropping
+  // XXXXNM whole routers; otherwise, they come back way too easily.
   for (i = 0; i < smartlist_len(descriptor_list); ++i) {
     routerinfo_t *ri = smartlist_get(descriptor_list, i);
     int drop = 0;
@@ -1399,12 +1337,6 @@
     smartlist_free(fingerprint_list);
     fingerprint_list = NULL;
   }
-  if (descriptor_list) {
-    SMARTLIST_FOREACH(descriptor_list, routerinfo_t *, ri,
-                      routerinfo_free(ri));
-    smartlist_free(descriptor_list);
-    descriptor_list = NULL;
-  }
   clear_cached_dir(&the_directory);
   clear_cached_dir(&the_runningrouters);
   clear_cached_dir(&cached_directory);

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/main.c,v
retrieving revision 1.543
retrieving revision 1.544
diff -u -d -r1.543 -r1.544
--- main.c	26 Aug 2005 18:44:26 -0000	1.543
+++ main.c	26 Aug 2005 20:59:04 -0000	1.544
@@ -692,8 +692,6 @@
     routerlist_remove_old_routers(ROUTER_MAX_AGE);
 
     if (authdir_mode(options)) {
-      /* Dump any old descriptors. */
-      dirserv_remove_old_servers(ROUTER_MAX_AGE);
       dirserv_log_unreachable_servers(now);
       if (!we_are_hibernating()) { /* try to determine reachability */
         router_retry_connections(1);

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.655
retrieving revision 1.656
diff -u -d -r1.655 -r1.656
--- or.h	26 Aug 2005 20:22:32 -0000	1.655
+++ or.h	26 Aug 2005 20:59:04 -0000	1.656
@@ -736,16 +736,17 @@
   addr_policy_t *exit_policy; /**< What streams will this OR permit
                                       * to exit? */
   long uptime; /**< How many seconds the router claims to have been up */
-  /* local info */
-  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? */
-  int is_verified; /**< Has a trusted dirserver validated this OR? */
-
   smartlist_t *declared_family; /**< Nicknames of router which this router
                                  * claims are its family. */
-
   char *contact_info; /**< Declared contact info for this router. */
 
+  /* local info */
+  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? */
+  int is_verified; /**< Has a trusted dirserver validated this OR?
+                    * (For Authdir: Have we validated this OR?)
+                    */
+
   /* The below items are used only by authdirservers right now for
    * reachability testing. */
   time_t last_reachable; /**< When was the last time we could reach this OR? */
@@ -1636,7 +1637,6 @@
 int list_server_status(smartlist_t *routers, char **router_status_out);
 void dirserv_log_unreachable_servers(time_t now);
 void dirserv_router_has_begun_reachability_testing(char *digest, time_t now);
-void dirserv_remove_old_servers(int age);
 int dirserv_dump_directory_to_string(char **dir_out,
                                      crypto_pk_env_t *private_key);
 void directory_set_dirty(void);
@@ -1654,6 +1654,8 @@
                              const char *digest_rcvd,
                              const char *nickname,
                              int as_advertised);
+int dirserv_wants_to_reject_router(routerinfo_t *ri, int *verified,
+                                   const char **msg);
 void dirserv_free_all(void);
 
 /********************************* dns.c ***************************/
@@ -1991,6 +1993,7 @@
 routerinfo_t *routerinfo_copy(const routerinfo_t *router);
 void router_mark_as_down(const char *digest);
 void routerlist_remove_old_routers(int age);
+int router_add_to_routerlist(routerinfo_t *router, const char **msg);
 int router_load_single_router(const char *s, const char **msg);
 int router_load_routerlist_from_directory(const char *s,crypto_pk_env_t *pkey,
                                         int dir_is_recent, int dir_is_cached);

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerlist.c,v
retrieving revision 1.254
retrieving revision 1.255
diff -u -d -r1.254 -r1.255
--- routerlist.c	26 Aug 2005 19:31:51 -0000	1.254
+++ routerlist.c	26 Aug 2005 20:59:04 -0000	1.255
@@ -861,40 +861,59 @@
  * *<b>msg</b> a static string describing the reason for refusing the
  * routerinfo.
  */
-static int
+int
 router_add_to_routerlist(routerinfo_t *router, const char **msg)
 {
   int i;
-  routerinfo_t *r;
   char id_digest[DIGEST_LEN];
+  int authdir = get_options()->AuthoritativeDir;
+  int authdir_verified = 0;
 
   tor_assert(routerlist);
   crypto_pk_get_digest(router->identity_pkey, id_digest);
 
+  if (authdir) {
+    if (dirserv_wants_to_reject_router(router, &authdir_verified, msg))
+      return -1;
+    router->is_verified = authdir_verified;
+    if (tor_version_as_new_as(router->platform,"0.1.0.2-rc"))
+      router->is_verified = 1;
+  }
+
   /* If we have a router with this name, and the identity key is the same,
    * choose the newer one. If the identity key has changed, drop the router.
    */
   for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
-    r = smartlist_get(routerlist->routers, i);
-
-    if (!crypto_pk_cmp_keys(router->identity_pkey, r->identity_pkey)) {
-      if (router->published_on > r->published_on) {
-        log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]",
-               router->nickname, r->nickname, hex_str(id_digest,DIGEST_LEN));
-//XXXRD        /* Remember whether we trust this router as a dirserver. */
-        routerinfo_free(r);
-        smartlist_set(routerlist->routers, i, router);
-        return 0;
-      } else {
+    routerinfo_t *old_router = smartlist_get(routerlist->routers, i);
+    if (!crypto_pk_cmp_keys(router->identity_pkey,old_router->identity_pkey)) {
+      if (router->published_on <= old_router->published_on) {
         log_fn(LOG_DEBUG, "Skipping not-new descriptor for router '%s'",
                router->nickname);
-        /* Update the is_running status to whatever we were told. */
-        r->is_running = router->is_running;
+        if (!authdir)
+          /* Update the is_running status to whatever we were told. */
+          old_router->is_running = router->is_running;
         routerinfo_free(router);
         if (msg) *msg = "Router descriptor was not new.";
         return -1;
+      } else {
+        log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]",
+               router->nickname, old_router->nickname,
+               hex_str(id_digest,DIGEST_LEN));
+        if (router->addr == old_router->addr &&
+            router->or_port == old_router->or_port) {
+          /* these carry over when the address and orport are unchanged.*/
+          router->last_reachable = old_router->last_reachable;
+          router->testing_since = old_router->testing_since;
+        }
+        if (msg)
+          *msg = authdir_verified ? "Verified server updated":
+          "Unverified server updated. (Have you sent us your key finerprint?)";
+        routerinfo_free(old_router);
+        smartlist_set(routerlist->routers, i, router);
+        directory_set_dirty();
+        return 0;
       }
-    } else if (!strcasecmp(router->nickname, r->nickname)) {
+    } else if (!strcasecmp(router->nickname, old_router->nickname)) {
       /* nicknames match, keys don't. */
       if (router->is_verified) {
         /* The new verified router replaces the old one; remove the
@@ -905,14 +924,15 @@
          * make new ones with the new key.
          */
         connection_t *conn;
-        while ((conn = connection_get_by_identity_digest(r->identity_digest,
-                                                         CONN_TYPE_OR))) {
-          log_fn(LOG_INFO,"Closing conn to obsolete router '%s'", r->nickname);
+        while ((conn = connection_get_by_identity_digest(
+                                old_router->identity_digest, CONN_TYPE_OR))) {
+          log_fn(LOG_INFO,"Closing conn to obsolete router '%s'",
+                 old_router->nickname);
           connection_mark_for_close(conn);
         }
-        routerinfo_free(r);
+        routerinfo_free(old_router);
         smartlist_del_keeporder(routerlist->routers, i--);
-      } else if (r->is_verified) {
+      } else if (old_router->is_verified) {
         /* Can't replace a verified router with an unverified one. */
         log_fn(LOG_DEBUG, "Skipping unverified entry for verified router '%s'",
                router->nickname);
@@ -925,16 +945,13 @@
   /* We haven't seen a router with this name before.  Add it to the end of
    * the list. */
   smartlist_add(routerlist->routers, router);
+  directory_set_dirty();
   return 0;
 }
 
 /** Remove any routers from the routerlist that are more than <b>age</b>
  * seconds old.
- *
- * (This function is just like dirserv_remove_old_servers. One day we should
- * merge them.)
  */
-//XXXRD
 void
 routerlist_remove_old_routers(int age)
 {
@@ -956,7 +973,7 @@
   }
 }
 
-/*
+/**
  * Code to parse a single router descriptor and insert it into the
  * routerlist.  Return -1 if the descriptor was ill-formed; 0 if the
  * descriptor was well-formed but could not be added; and 1 if the
@@ -965,6 +982,8 @@
  * If we don't add it and <b>msg</b> is not NULL, then assign to
  * *<b>msg</b> a static string describing the reason for refusing the
  * descriptor.
+ *
+ * This is used only by the controller.
  */
 int
 router_load_single_router(const char *s, const char **msg)
@@ -1350,6 +1369,7 @@
                                  time_t list_time,
                                  const char *s)
 {
+  int authdir = get_options()->AuthoritativeDir;
   int is_running = 1;
   int is_verified = 0;
   int hex_digest_set = 0;
@@ -1421,13 +1441,22 @@
   {
     int nickname_matches = is_verified && !strcasecmp(r->nickname, nickname);
     int digest_matches = !memcmp(digest, r->identity_digest, DIGEST_LEN);
-    if (nickname_matches && digest_matches)
-      r->is_verified = 1;
-    else if (digest_matches)
-      r->is_verified = 0;
+    if (!authdir) {
+      /* If we're not an authoritative directory, update verified status.
+       */
+      if (nickname_matches && digest_matches)
+        r->is_verified = 1;
+      else if (digest_matches)
+        r->is_verified = 0;
+    }
     if (digest_matches)
       if (r->status_set_at < list_time) {
-        r->is_running = is_running;
+        if (!authdir || is_running)
+          /* If we're an authoritative directory, only believe that servers
+           * are down when we hear it ourselves.  Otherwise, believe
+           * what we're told.
+           */
+          r->is_running = is_running;
         r->status_set_at = time(NULL);
       }
   });