[or-cvs] Implement new version handling code.

Nick Mathewson nickm at seul.org
Wed Sep 21 00:41:08 UTC 2005


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

Modified Files:
	config.c dirserv.c or.h routerlist.c routerparse.c test.c 
Log Message:
Implement new version handling code.

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/config.c,v
retrieving revision 1.422
retrieving revision 1.423
diff -u -d -r1.422 -r1.423
--- config.c	15 Sep 2005 14:39:05 -0000	1.422
+++ config.c	21 Sep 2005 00:41:06 -0000	1.423
@@ -191,6 +191,8 @@
   VAR("UseHelperNodes",      BOOL,     UseHelperNodes,       "0"),
   VAR("User",                STRING,   User,                 NULL),
   VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir,   "0"),
+  /* XXXX 011 change this default on 0.1.1.x */
+  VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "1"),
   VAR("__LeaveStreamsUnattached", BOOL,LeaveStreamsUnattached, "0"),
   { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
 };

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/dirserv.c,v
retrieving revision 1.237
retrieving revision 1.238
diff -u -d -r1.237 -r1.238
--- dirserv.c	20 Sep 2005 03:40:54 -0000	1.237
+++ dirserv.c	21 Sep 2005 00:41:06 -0000	1.238
@@ -1149,6 +1149,7 @@
   smartlist_t *descriptor_list = get_descriptor_list();
   time_t now = time(NULL);
   int naming = options->NamingAuthoritativeDir;
+  int versioning = options->VersioningAuthoritativeDir;
   const char *contact;
 
   if (!descriptor_list) {
@@ -1193,7 +1194,7 @@
                "fingerprint %s\n"
                "contact %s\n"
                "published %s\n"
-               "dir-options%s\n"
+               "dir-options%s%s\n"
                "client-versions %s\n"
                "server-versions %s\n"
                "dir-signing-key\n%s\n",
@@ -1202,6 +1203,7 @@
                contact,
                published,
                naming ? " Names" : "",
+               versioning ? " Versions" : "",
                client_versions,
                server_versions,
                identity_pkey);

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/or.h,v
retrieving revision 1.692
retrieving revision 1.693
diff -u -d -r1.692 -r1.693
--- or.h	18 Sep 2005 04:15:39 -0000	1.692
+++ or.h	21 Sep 2005 00:41:06 -0000	1.693
@@ -816,7 +816,8 @@
   /** What was the digest of the document? */
   char networkstatus_digest[DIGEST_LEN];
 
-  int is_recent; /** Is this recent enough to influence running status? */
+  unsigned int is_recent; /**< Is this recent enough to influence running
+                           * status? */
 
   /* These fields come from the actual network-status document.*/
   time_t published_on; /**< Declared publication date. */
@@ -833,7 +834,10 @@
   char *server_versions; /**< comma-separated list of recommended server
                           * versions. */
 
-  int binds_names:1; /**< True iff this directory server binds names. */
+  unsigned int binds_names:1; /**< True iff this directory server binds names. */
+  unsigned int recommends_versions:1; /**< True iff this directory server
+                                       * recommends client and server software
+                                       * versions. */
 
   smartlist_t *entries; /**< List of router_status_t*.   This list is kept
                          * sorted by identity_digest. */
@@ -1175,6 +1179,8 @@
                            * for version 1 directories? */
   int NamingAuthoritativeDir; /**< Boolean: is this an authoritative directory
                                * that's willing to bind names? */
+  int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative directory
+                                   * that's willing to recommend versions? */
   int ClientOnly; /**< Boolean: should we never evolve into a server role? */
   int NoPublish; /**< Boolean: should we never publish a descriptor? */
   int ConnLimit; /**< Requested maximum number of simultaneous connections. */
@@ -2143,6 +2149,15 @@
   char status_tag[MAX_STATUS_TAG_LEN];
 } tor_version_t;
 
+typedef enum version_status_t {
+  VS_RECOMMENDED=0, /**< This version is listed as recommended. */
+  VS_OLD=1, /**< This version is older than any recommended version. */
+  VS_NEW=2, /**< This version is newer than any recommended version. */
+  VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version
+                       * in its series, and such recommended versions exist. */
+  VS_UNRECOMMENDED=4 /**< This version is not recommended (general case) */
+} version_status_t;
+
 int router_get_router_hash(const char *s, char *digest);
 int router_get_dir_hash(const char *s, char *digest);
 int router_get_runningrouters_hash(const char *s, char *digest);
@@ -2162,6 +2177,9 @@
 int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
 addr_policy_t *router_parse_addr_policy_from_string(const char *s,
                                                     int assume_action);
+version_status_t tor_version_is_obsolete(const char *myversion,
+                                         const char *versionlist);
+version_status_t version_status_join(version_status_t a, version_status_t b);
 int tor_version_parse(const char *s, tor_version_t *out);
 int tor_version_as_new_as(const char *platform, const char *cutoff);
 int tor_version_compare(tor_version_t *a, tor_version_t *b);

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerlist.c,v
retrieving revision 1.304
retrieving revision 1.305
diff -u -d -r1.304 -r1.305
--- routerlist.c	18 Sep 2005 04:32:58 -0000	1.304
+++ routerlist.c	21 Sep 2005 00:41:06 -0000	1.305
@@ -1983,7 +1983,10 @@
 void
 routers_update_all_from_networkstatus(void)
 {
+#define SELF_OPINION_INTERVAL 90*60
   static int have_warned_about_unverified_status = 0;
+  static int have_warned_about_old_version = 0;
+  static int have_warned_about_new_version = 0;
   routerinfo_t *me;
   time_t now;
   if (!routerlist || !networkstatus_list ||
@@ -1997,18 +2000,33 @@
   routers_update_status_from_networkstatus(routerlist->routers, 0);
 
   me = router_get_my_routerinfo();
-  if (me) {
-    /* We could be more sophisticated about this whole business.  How many
-     * dirservers list us as named, valid, etc. */
-    smartlist_t *lst = smartlist_create();
-    smartlist_add(lst, me);
-    routers_update_status_from_networkstatus(lst, 1);
-    if (me->is_verified == 0) {
-      log_fn(LOG_WARN, "Many directory servers list us as unverified. Please consider sending your identity fingerprint to the tor-ops.");
-      have_warned_about_unverified_status = 1;
-    } else if (me->is_named == 0) {
-      log_fn(LOG_WARN, "Many directory servers list us as unnamed. Please consider sending your identity fingerprint to the tor-ops.");
-      have_warned_about_unverified_status = 1;
+  if (me && !have_warned_about_unverified_status) {
+    int n_recent = 0, n_listing = 0, n_valid = 0, n_named = 0;
+    routerstatus_t *rs;
+    SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+    {
+      if (ns->received_on + SELF_OPINION_INTERVAL < now)
+        continue;
+      ++n_recent;
+      if (!(rs = networkstatus_find_entry(ns, me->identity_digest)))
+        continue;
+      ++n_listing;
+      if (rs->is_valid)
+        ++n_valid;
+      if (rs->is_named)
+        ++n_named;
+    });
+
+    if (n_recent >= 2 && n_listing >= 2) {
+      if (n_valid <= n_recent/2)  {
+        log_fn(LOG_WARN, "%d/%d recent directory servers list us as invalid. Please consider sending your identity fingerprint to the tor-ops.",
+               n_recent-n_valid, n_recent);
+        have_warned_about_unverified_status = 1;
+      } else if (n_named <= n_recent/2)  {
+        log_fn(LOG_WARN, "%d/%d recent directory servers list us as unnamed. Please consider sending your identity fingerprint to the tor-ops.",
+               n_recent-n_valid, n_recent);
+        have_warned_about_unverified_status = 1;
+      }
     }
   }
 
@@ -2016,6 +2034,47 @@
 
   update_router_descriptor_downloads(time(NULL));
 
+  if (!have_warned_about_old_version) {
+    int n_recent = 0;
+    int n_recommended = 0;
+    int is_server = server_mode(get_options());
+    version_status_t consensus = VS_RECOMMENDED;
+    SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+    {
+      version_status_t vs;
+      if (ns->received_on + SELF_OPINION_INTERVAL < now )
+        // XXXX NM enable this! || !ns->recommends_versions)
+        continue;
+      vs = tor_version_is_obsolete(
+              VERSION, is_server ? ns->server_versions : ns->client_versions);
+      if (vs == VS_RECOMMENDED)
+        ++n_recommended;
+      if (n_recent++ == 0) {
+        consensus = vs;
+      } else if (consensus != vs) {
+        consensus = version_status_join(consensus, vs);
+      }
+    });
+    if (n_recent > 2 && n_recommended < n_recent/2) {
+      if (consensus == VS_NEW || consensus == VS_NEW_IN_SERIES) {
+        if (!have_warned_about_new_version) {
+          log_fn(LOG_NOTICE, "This version of Tor (%s) is newer than any recommended version%s, according to %d/%d recent network statuses.",
+                 VERSION, consensus == VS_NEW_IN_SERIES ? " in its series" : "",
+                 n_recent-n_recommended, n_recent);
+          have_warned_about_new_version = 1;
+        }
+      } else {
+        log_fn(LOG_NOTICE, "This version of Tor (%s) is %s, according to %d/%d recent network statuses.",
+               VERSION, consensus == VS_OLD ? "obsolete" : "not recommended",
+               n_recent-n_recommended, n_recent);
+        have_warned_about_old_version = 1;
+      }
+    } else {
+      log_fn(LOG_NOTICE, "%d/%d recent directories think my version is ok.",
+             n_recommended, n_recent);
+    }
+  }
+
   routerstatus_list_has_changed = 0;
 }
 

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/routerparse.c,v
retrieving revision 1.146
retrieving revision 1.147
diff -u -d -r1.146 -r1.147
--- routerparse.c	20 Sep 2005 19:50:43 -0000	1.146
+++ routerparse.c	21 Sep 2005 00:41:06 -0000	1.147
@@ -166,8 +166,6 @@
                                      crypto_pk_env_t *declared_key,
                                      int check_authority);
 static crypto_pk_env_t *find_dir_signing_key(const char *str);
-/* static */ int is_obsolete_version(const char *myversion,
-                                     const char *versionlist);
 static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
 
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
@@ -258,14 +256,17 @@
  * Otherwise return 0.
  * (versionlist is a comma-separated list of version strings,
  * optionally prefixed with "Tor".  Versions that can't be parsed are
- * ignored.) */
-/* static */ int
-is_obsolete_version(const char *myversion, const char *versionlist) {
+ * ignored.)
+ *
+ * DOCDOC interface changed */
+version_status_t
+tor_version_is_obsolete(const char *myversion, const char *versionlist)
+{
   const char *vl;
   tor_version_t mine, other;
-  int found_newer = 0, found_newer_in_series = 0, found_any_in_series = 0,
-    r, ret, same;
-  static int warned_too_new=0;
+  int found_newer = 0, found_older = 0, found_newer_in_series = 0,
+    found_any_in_series = 0, r, same;
+  version_status_t ret = VS_UNRECOMMENDED;
   smartlist_t *version_sl;
 
   vl = versionlist;
@@ -292,54 +293,28 @@
         found_any_in_series = 1;
       r = tor_version_compare(&mine, &other);
       if (r==0) {
-        ret = 0;
+        ret = VS_RECOMMENDED;
         goto done;
       } else if (r<0) {
         found_newer = 1;
         if (same)
           found_newer_in_series = 1;
+      } else if (r>0) {
+        found_older = 1;
       }
     }
   });
 
   /* We didn't find the listed version. Is it new or old? */
-
-  if (found_any_in_series) {
-    if (!found_newer_in_series) {
-      /* We belong to a series with recommended members, and we are newer than
-       * any recommended member. We're probably okay. */
-      if (!warned_too_new) {
-        log(LOG_WARN, "This version of Tor (%s) is newer than any in the same series on the recommended list (%s).",
-            myversion, versionlist);
-        warned_too_new = 1;
-      }
-      ret = 0;
-    } else {
-      /* We found a newer one in the same series; we're obsolete. */
-      ret = 1;
-    }
+  if (found_any_in_series && !found_newer_in_series) {
+    ret = VS_NEW_IN_SERIES;
+  } else if (found_newer && !found_older) {
+    ret = VS_OLD;
+  } else if (found_older && !found_newer) {
+    ret = VS_NEW;
   } else {
-    if (found_newer) {
-      /* We belong to a series with no recommended members, and
-       * a newer series is recommended. We're obsolete. */
-      ret = 1;
-    } else {
-      /* We belong to a series with no recommended members, and it's
-       * newer than any recommended series. We're probably okay. */
-      if (!warned_too_new) {
-        log(LOG_WARN, "This version of Tor (%s) is newer than any on the recommended list (%s).",
-            myversion, versionlist);
-        warned_too_new = 1;
-      }
-      ret = 0;
-    }
+    ret = VS_UNRECOMMENDED;
   }
-  /*
-  log_fn(LOG_DEBUG,
-         "Decided that %s is %sobsolete relative to %s: %d, %d, %d\n",
-         myversion, ret?"":"not ", versionlist, found_newer,
-         found_any_in_series, found_newer_in_series);
-  */
 
  done:
   SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
@@ -347,29 +322,25 @@
   return ret;
 }
 
-#if 0
-/* Return 0 if myversion is supported; else warn and return -1. */
-int
-check_software_version_against_directory(const char *directory)
+/** DOCDOC */
+version_status_t
+version_status_join(version_status_t a, version_status_t b)
 {
-  char *v;
-  v = get_recommended_software_from_directory(directory);
-  if (!v) {
-    log_fn(LOG_WARN, "No recommended-versions string found in directory");
-    return -1;
-  }
-  if (!is_obsolete_version(VERSION, v)) {
-    tor_free(v);
-    return 0;
-  }
-  log(LOG_WARN,
-     "You are running Tor version %s, which will not work with this network.\n"
-     "Please use %s%s.",
-      VERSION, strchr(v,',') ? "one of " : "", v);
-  tor_free(v);
-  return -1;
+  if (a == b)
+    return a;
+  else if (a == VS_UNRECOMMENDED || b == VS_UNRECOMMENDED)
+    return VS_UNRECOMMENDED;
+  else if (a == VS_RECOMMENDED)
+    return b;
+  else if (b == VS_RECOMMENDED)
+    return a;
+  /* Okay.  Neither is 'recommended' or 'unrecommended', and they differ. */
+  else if (a == VS_OLD || b == VS_OLD)
+    return VS_UNRECOMMENDED;
+  /* One is VS_NEW, the other is VS_NEW_IN_SERIES */
+  else
+    return VS_NEW_IN_SERIES;
 }
-#endif
 
 /** Read a signed directory from <b>str</b>.  If it's well-formed, return 0.
  * Otherwise, return -1.  If we're a directory cache, cache it.
@@ -1164,25 +1135,31 @@
     goto err;
   }
 
-  if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS)) || tok->n_args<1) {
-    log_fn(LOG_WARN, "Missing client-versions");
-    goto err;
+  if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) {
+    for (i=0; i < tok->n_args; ++i) {
+      if (!strcmp(tok->args[i], "Names"))
+        ns->binds_names = 1;
+      if (!strcmp(tok->args[i], "Versions"))
+        ns->recommends_versions = 1;
+    }
   }
-  ns->client_versions = tok->args[0];
 
-  if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS)) || tok->n_args<1) {
-    log_fn(LOG_WARN, "Missing client-versions");
-    goto err;
-  }
-  ns->client_versions = tok->args[0];
-  tok->args[0] = NULL;
+  if (ns->recommends_versions || 1) { //XXXX NM re-enable conditional.
+    if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS)) ||
+        tok->n_args<1) {
+      log_fn(LOG_WARN, "Missing client-versions");
+    }
+    ns->client_versions = tok->args[0];
+    tok->args[0] = NULL;
 
-  if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) || tok->n_args<1) {
-    log_fn(LOG_WARN, "Missing server-versions");
-    goto err;
+    if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) ||
+        tok->n_args<1) {
+      log_fn(LOG_WARN, "Missing server-versions on versioning directory");
+      goto err;
+    }
+    ns->server_versions = tok->args[0];
+    tok->args[0] = NULL;
   }
-  ns->server_versions = tok->args[0];
-  tok->args[0] = NULL;
 
   if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
     log_fn(LOG_WARN, "Missing published time on directory.");
@@ -1193,13 +1170,6 @@
      goto err;
   }
 
-  if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) {
-    for (i=0; i < tok->n_args; ++i) {
-      if (!strcmp(tok->args[i], "Names"))
-        ns->binds_names = 1;
-    }
-  }
-
   ns->entries = smartlist_create();
   s = eos;
   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));

Index: test.c
===================================================================
RCS file: /home/or/cvsroot/tor/src/or/test.c,v
retrieving revision 1.203
retrieving revision 1.204
diff -u -d -r1.203 -r1.204
--- test.c	18 Sep 2005 02:22:21 -0000	1.203
+++ test.c	21 Sep 2005 00:41:06 -0000	1.204
@@ -32,7 +32,6 @@
 void add_fingerprint_to_dir(const char *nickname, const char *fp,
                             smartlist_t *list);
 void get_platform_str(char *platform, size_t len);
-int is_obsolete_version(const char *myversion, const char *start);
 size_t read_escaped_data(const char *data, size_t len, int translate_newlines,
                          char **out);
 or_options_t *options_new(void);
@@ -1368,28 +1367,35 @@
   test_eq(IS_NOT_CVS, ver1.cvs);
   test_streq("", ver1.status_tag);
 
-  /* make sure is_obsolete_version() works */
-  test_eq(1, is_obsolete_version("0.0.1", "Tor 0.0.2"));
-  test_eq(1, is_obsolete_version("0.0.1", "0.0.2, Tor 0.0.3"));
-  test_eq(1, is_obsolete_version("0.0.1", "0.0.2,Tor 0.0.3"));
-  test_eq(1, is_obsolete_version("0.0.1", "0.0.3,BetterTor 0.0.1"));
-  test_eq(0, is_obsolete_version("0.0.2", "Tor 0.0.2,Tor 0.0.3"));
-  test_eq(0, is_obsolete_version("0.0.2", "Tor 0.0.2pre1,Tor 0.0.3"));
-  test_eq(1, is_obsolete_version("0.0.2", "Tor 0.0.2.1,Tor 0.0.3"));
-  test_eq(0, is_obsolete_version("0.1.0", "Tor 0.0.2,Tor 0.0.3"));
-  test_eq(0, is_obsolete_version("0.0.7rc2", "0.0.7,Tor 0.0.7rc2,Tor 0.0.8"));
-  test_eq(0, is_obsolete_version("0.0.5", "0.0.5-cvs"));
-  test_eq(0, is_obsolete_version("0.0.5.1-cvs", "0.0.5"));
+  /* make sure tor_version_is_obsolete() works */
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.1", "Tor 0.0.2"));
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.1", "0.0.2, Tor 0.0.3"));
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.1", "0.0.2,Tor 0.0.3"));
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.1", "0.0.3,BetterTor 0.0.1"));
+  test_eq(VS_RECOMMENDED,tor_version_is_obsolete("0.0.2", "Tor 0.0.2,Tor 0.0.3"));
+  test_eq(VS_NEW_IN_SERIES,
+          tor_version_is_obsolete("0.0.2", "Tor 0.0.2pre1,Tor 0.0.3"));
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.2", "Tor 0.0.2.1,Tor 0.0.3"));
+  test_eq(VS_NEW, tor_version_is_obsolete("0.1.0", "Tor 0.0.2,Tor 0.0.3"));
+  test_eq(VS_RECOMMENDED,
+          tor_version_is_obsolete("0.0.7rc2", "0.0.7,Tor 0.0.7rc2,Tor 0.0.8"));
+  test_eq(VS_OLD, tor_version_is_obsolete("0.0.5.0", "0.0.5.1-cvs"));
+  test_eq(VS_NEW_IN_SERIES, tor_version_is_obsolete("0.0.5.1-cvs", "0.0.5"));
   /* Not on list, but newer than any in same series. */
-  test_eq(0, is_obsolete_version("0.1.0.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
+  test_eq(VS_NEW_IN_SERIES,
+       tor_version_is_obsolete("0.1.0.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
   /* Series newer than any on list. */
-  test_eq(0, is_obsolete_version("0.1.1.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
+  test_eq(VS_NEW,
+       tor_version_is_obsolete("0.1.2.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
   /* Series older than any on list. */
-  test_eq(1, is_obsolete_version("0.0.1.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
+  test_eq(VS_OLD,
+       tor_version_is_obsolete("0.0.1.3", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
   /* Not on list, not newer than any on same series. */
-  test_eq(1, is_obsolete_version("0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
+  test_eq(VS_UNRECOMMENDED,
+       tor_version_is_obsolete("0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
   /* On list, not newer than any on same series. */
-  test_eq(1, is_obsolete_version("0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
+  test_eq(VS_UNRECOMMENDED,
+       tor_version_is_obsolete("0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0"));
 
   test_eq(0, tor_version_as_new_as("Tor 0.0.5", "0.0.9pre1-cvs"));
   test_eq(1, tor_version_as_new_as(



More information about the tor-commits mailing list