Browse Source

r15965@catbus: nickm | 2007-10-19 13:32:11 -0400
Client-side implementation for proposal 122.


svn:r12051

Nick Mathewson 17 years ago
parent
commit
7bb202fd19
7 changed files with 91 additions and 12 deletions
  1. 3 0
      ChangeLog
  2. 2 2
      doc/TODO
  3. 1 1
      doc/spec/proposals/122-unnamed-flag.txt
  4. 39 4
      src/or/networkstatus.c
  5. 8 0
      src/or/or.h
  6. 2 0
      src/or/routerlist.c
  7. 36 5
      src/or/routerparse.c

+ 3 - 0
ChangeLog

@@ -16,6 +16,9 @@ Changes in version 0.2.0.9-alpha - 2007-10-??
       that it shouldn't be considered to exist at all anymore. Now we
       clear all the flags for routers that fall out of the networkstatus
       consensus. Fixes bug 529.
+    - If the consensus list a router as "Unnamed", the name is assigned
+      to a different router: do not identify the router by that name.
+      (Partially implements proposal 122.)
 
   o Minor features (v3 directory protocol):
     - Allow tor-gencert to generate a new certificate without replacing the

+ 2 - 2
doc/TODO

@@ -93,11 +93,11 @@ Things we'd like to do in 0.2.0.x:
     - 105: Version negotiation for the Tor protocol
     . 111: Prioritize local traffic over relayed.
       - Merge into tor-spec.txt.
-    - 122: Network status entries need an Unnamed flag
+    . 122: Network status entries need an Unnamed flag
       - Merge into dir-spec.txt
       - Implement voting side
       - Implement consensus side
-      - Implement client side
+      o Implement client side
 
   - Refactoring:
     . Make cells get buffered on circuit, not on the or_conn.

+ 1 - 1
doc/spec/proposals/122-unnamed-flag.txt

@@ -4,7 +4,7 @@ Version: $Revision$
 Last-Modified: $Date$
 Author: Roger Dingledine
 Created: 04-Oct-2007
-Status: Open
+Status: Accepted
 
 1. Overview:
 

+ 39 - 4
src/or/networkstatus.c

@@ -25,8 +25,11 @@ static smartlist_t *networkstatus_v2_list = NULL;
  * time we called download_status_map_update_from_v2_networkstatus() */
 static int networkstatus_v2_list_has_changed = 0;
 
-/** Map from lowercase nickname to digest of named server, if any. */
+/** Map from lowercase nickname to identity digest of named server, if any. */
 static strmap_t *named_server_map = NULL;
+/** Map from lowercase nickname to (void*)1 for all names that are listed
+ * as unnamed for some server in the consensus. */
+static strmap_t *unnamed_server_map = NULL;
 
 /** Most recently received and validated v3 consensus network status. */
 static networkstatus_vote_t *current_consensus = NULL;
@@ -579,6 +582,7 @@ router_get_consensus_status_by_nickname(const char *nickname,
   routerstatus_t *best=NULL;
   smartlist_t *matches=NULL;
   const char *named_id=NULL;
+  int any_unnamed=0;
 
   if (!current_consensus || !nickname)
     return NULL;
@@ -597,6 +601,10 @@ router_get_consensus_status_by_nickname(const char *nickname,
   if (named_id)
     return networkstatus_vote_find_entry(current_consensus, named_id);
 
+  if (unnamed_server_map &&
+      strmap_get_lc(named_server_map, nickname))
+    return NULL; /* XXXX020 should we warn? */
+
   /*XXXX020 is this behavior really what we want? */
   matches = smartlist_create();
   SMARTLIST_FOREACH(current_consensus->routerstatus_list,
@@ -604,16 +612,22 @@ router_get_consensus_status_by_nickname(const char *nickname,
     {
       if (!strcasecmp(lrs->nickname, nickname)) {
         if (lrs->is_named) {
+          /* XXXX020 this should never happen. */
           smartlist_free(matches);
           return lrs;
         } else {
+          if (lrs->is_unnamed)
+            smartlist_free(matches); /* nor should this. */
           smartlist_add(matches, lrs);
           best = lrs;
         }
       }
     });
 
-  if (smartlist_len(matches)>1 && warn_if_unnamed) {
+  if (any_unnamed) {
+    /* XXXX020 should we warn? */
+    return NULL;
+  } else if (smartlist_len(matches)>1 && warn_if_unnamed) {
     int any_unwarned=0;
     SMARTLIST_FOREACH(matches, routerstatus_t *, lrs,
       {
@@ -654,6 +668,13 @@ networkstatus_get_router_digest_by_nickname(const char *nickname)
   return strmap_get_lc(named_server_map, nickname);
 }
 
+/** DOCDOC */
+int
+networkstatus_nickname_is_unnamed(const char *nickname)
+{
+  return strmap_get_lc(named_server_map, nickname) != NULL;
+}
+
 /** How frequently do directory authorities re-download fresh networkstatus
  * documents? */
 #define AUTHORITY_NS_CACHE_INTERVAL (5*60)
@@ -1061,6 +1082,11 @@ routers_update_all_from_networkstatus(time_t now)
       log_info(LD_GENERAL, "The latest consensus does not list us."
                "Are you misconfigured?");
       have_warned_about_invalid_status = 1;
+    } else if (rs->is_unnamed) {
+      /* XXXX020 this isn't a useful warning. */
+      log_info(LD_GENERAL,  "The directory have assigned the nickname "
+               "you're using to a different identity.");
+      have_warned_about_invalid_status = 1;
     } else if (!rs->is_named) {
       /*XXXX020 this isn't a correct warning. */
       log_info(LD_GENERAL,  "The directory authorities do not recognize "
@@ -1150,11 +1176,17 @@ routerstatus_list_update_named_server_map(void)
   if (named_server_map)
     strmap_free(named_server_map, _tor_free);
   named_server_map = strmap_new();
+  if (unnamed_server_map)
+    strmap_free(unnamed_server_map, NULL);
+  named_server_map = strmap_new();
   SMARTLIST_FOREACH(current_consensus->routerstatus_list, routerstatus_t *, rs,
     {
       if (rs->is_named) {
-        strmap_set(named_server_map, rs->nickname,
-                   tor_memdup(rs->identity_digest, DIGEST_LEN));
+        strmap_set_lc(named_server_map, rs->nickname,
+                      tor_memdup(rs->identity_digest, DIGEST_LEN));
+      }
+      if (rs->is_unnamed) {
+        strmap_set_lc(unnamed_server_map, rs->nickname, (void*)1);
       }
     });
 }
@@ -1348,5 +1380,8 @@ networkstatus_free_all(void)
   if (named_server_map) {
     strmap_free(named_server_map, _tor_free);
   }
+  if (unnamed_server_map) {
+    strmap_free(unnamed_server_map, NULL);
+  }
 }
 

+ 8 - 0
src/or/or.h

@@ -1221,6 +1221,8 @@ typedef struct routerstatus_t {
   unsigned int is_fast:1; /**< True iff this router has good bandwidth. */
   unsigned int is_running:1; /**< True iff this router is up. */
   unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */
+  unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another
+                              * router. */
   unsigned int is_valid:1; /**< True iff this router is validated. */
   unsigned int is_v2_dir:1; /**< True iff this router can serve directory
                              * information with v2 of the directory
@@ -1349,6 +1351,11 @@ typedef struct networkstatus_vote_t {
   time_t valid_until; /**< Time after which this vote or consensus should not
                        * be used. */
 
+  /** Consensus only: what method was used to produce this consensus? */
+  int consensus_method;
+  /** Vote only: what methods is this voter willing to use? */
+  smartlist_t *supported_methods;
+
   /** How long does this vote/consensus claim that authorities take to
    * distribute their votes to one another? */
   int vote_seconds;
@@ -3091,6 +3098,7 @@ routerstatus_t *router_get_consensus_status_by_descriptor_digest(
 routerstatus_t *router_get_consensus_status_by_nickname(const char *nickname,
                                                        int warn_if_unnamed);
 const char *networkstatus_get_router_digest_by_nickname(const char *nickname);
+int networkstatus_nickname_is_unnamed(const char *nickname);
 void networkstatus_consensus_download_failed(int status_code);
 int should_delay_dir_fetches(or_options_t *options);
 void update_networkstatus_downloads(time_t now);

+ 2 - 0
src/or/routerlist.c

@@ -1701,6 +1701,8 @@ router_get_by_nickname(const char *nickname, int warn_if_unnamed)
   if ((named_digest = networkstatus_get_router_digest_by_nickname(nickname))) {
     return rimap_get(routerlist->identity_map, named_digest);
   }
+  if (networkstatus_nickname_is_unnamed(nickname))
+    return NULL;
 
   /* If we reach this point, there's no canonical value for the nickname. */
 

+ 36 - 5
src/or/routerparse.c

@@ -1534,12 +1534,17 @@ find_start_of_next_routerstatus(const char *s)
  * router status.  Return NULL and advance *<b>s</b> on error.
  *
  * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
- * routerstatus but use <b>vote_rs</b> instead
+ * routerstatus but use <b>vote_rs</b> instead.
+ *
+ * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
+ * consensus, and we should parse it according to the method used to
+ * make that consensus.
  **/
 static routerstatus_t *
 routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens,
                                      networkstatus_vote_t *vote,
-                                     vote_routerstatus_t *vote_rs)
+                                     vote_routerstatus_t *vote_rs,
+                                     int consensus_method)
 {
   const char *eos;
   routerstatus_t *rs = NULL;
@@ -1645,6 +1650,11 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens,
         rs->is_bad_directory = 1;
       else if (!strcmp(tok->args[i], "Authority"))
         rs->is_authority = 1;
+      else if (!strcmp(tok->args[i], "Unnamed") &&
+               consensus_method >= 2) {
+        /* Unnamed is computed right by consensus method 2 and later. */
+        rs->is_unnamed = 1;
+      }
     }
   }
   if ((tok = find_first_by_keyword(tokens, K_V))) {
@@ -1830,7 +1840,7 @@ networkstatus_v2_parse_from_string(const char *s)
   smartlist_clear(tokens);
   while (!strcmpstart(s, "r ")) {
     routerstatus_t *rs;
-    if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL)))
+    if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL, 0)))
       smartlist_add(ns->entries, rs);
   }
   smartlist_sort(ns->entries, _compare_routerstatus_entries);
@@ -1936,6 +1946,26 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
     tok = find_first_by_keyword(tokens, K_PUBLISHED);
     if (parse_iso_time(tok->args[0], &ns->published))
       goto err;
+
+    ns->supported_methods = smartlist_create();
+    tok = find_first_by_keyword(tokens, K_CONSENSUS_METHODS);
+    if (tok) {
+      for (i=0; i < tok->n_args; ++i)
+        smartlist_add(ns->supported_methods, tok->args[i]);
+      tok->n_args = 0; /* Prevent double free. */
+    } else {
+      smartlist_add(ns->supported_methods, tor_strdup("1"));
+    }
+  } else {
+    tok = find_first_by_keyword(tokens, K_CONSENSUS_METHOD);
+    if (tok) {
+      ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
+                                                 &ok, NULL);
+      if (!ok)
+        goto err;
+    } else {
+      ns->consensus_method = 1;
+    }
   }
 
   tok = find_first_by_keyword(tokens, K_VALID_AFTER);
@@ -2086,7 +2116,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
   while (!strcmpstart(s, "r ")) {
     if (is_vote) {
       vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
-      if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs))
+      if (routerstatus_parse_entry_from_string(&s, tokens, ns, rs, 0))
         smartlist_add(ns->routerstatus_list, rs);
       else {
         tor_free(rs->version);
@@ -2094,7 +2124,8 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
       }
     } else {
       routerstatus_t *rs;
-      if ((rs =routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL)))
+      if ((rs = routerstatus_parse_entry_from_string(&s, tokens, NULL, NULL,
+                                                     ns->consensus_method)))
         smartlist_add(ns->routerstatus_list, rs);
     }
   }