[or-cvs] Remaining 008pre1 items done; deferred where more design is...

Nick Mathewson nickm at seul.org
Fri Jun 25 00:29:33 UTC 2004


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv5752/src/or

Modified Files:
	directory.c dirserv.c main.c or.h rephist.c router.c 
	routerlist.c routerparse.c 
Log Message:
Remaining 008pre1 items done; deferred where more design is needed.
More docs and (way more!) testing needed.

Done:
 - Authdirservers down directories from others.
 - Generate and use running-routers lists
 - Cache directories; store across reboots.
 - Refactor directory parsing a bit; note potential trouble spots.



Index: directory.c
===================================================================
RCS file: /home/or/cvsroot/src/or/directory.c,v
retrieving revision 1.109
retrieving revision 1.110
diff -u -d -r1.109 -r1.110
--- directory.c	16 Jun 2004 21:08:29 -0000	1.109
+++ directory.c	25 Jun 2004 00:29:30 -0000	1.110
@@ -352,6 +352,8 @@
     }
 
     if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+      running_routers_t *rrs;
+      routerlist_t *rl;
       /* just update our list of running routers, if this list is new info */
       log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
       if(status_code != 200) {
@@ -361,7 +363,15 @@
         connection_mark_for_close(conn);
         return -1;
       }
-      /* XXX008 hand 'body' to something that parses a running-routers list. */
+      if (!(rrs = router_parse_runningrouters(body))) {
+        log_fn(LOG_WARN, "Can't parse runningrouters list");
+        free(body); free(headers);
+        connection_mark_for_close(conn);
+        return -1;
+      }
+      router_get_routerlist(&rl);
+      routerlist_update_from_runningrouters(rl,rrs);
+      running_routers_free(rrs);
     }
 
     if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {

Index: dirserv.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dirserv.c,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- dirserv.c	21 Jun 2004 04:37:26 -0000	1.54
+++ dirserv.c	25 Jun 2004 00:29:30 -0000	1.55
@@ -16,6 +16,7 @@
 
 /** Do we need to regenerate the directory when someone asks for it? */
 static int the_directory_is_dirty = 1;
+static int runningrouters_is_dirty = 1;
 
 static int list_running_servers(char **nicknames_out);
 static void directory_remove_unrecognized(void);
@@ -406,13 +407,14 @@
 directory_set_dirty()
 {
   the_directory_is_dirty = 1;
+  runningrouters_is_dirty = 1;
 }
 
-/** Load all descriptors from an earlier directory stored in the string
+/** Load all descriptors from a directory stored in the string
  * <b>dir</b>.
  */
 int
-dirserv_init_from_directory_string(const char *dir)
+dirserv_load_from_directory_string(const char *dir)
 {
   const char *cp = dir;
   while(1) {
@@ -525,7 +527,9 @@
            "signed-directory\n"
            "published %s\n"
            "recommended-software %s\n"
-           "running-routers %s\n\n", published, options.RecommendedVersions, cp);
+           "running-routers %s\n\n",
+           published, options.RecommendedVersions, cp);
+
   free(cp);
   i = strlen(s);
   cp = s+i;
@@ -563,7 +567,7 @@
     log_fn(LOG_WARN,"couldn't base64-encode signature");
     return -1;
   }
-
+  
   if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
     goto truncated;
 
@@ -583,6 +587,7 @@
 void dirserv_set_cached_directory(const char *directory, time_t when)
 {
   time_t now;
+  char filename[512];
   if (!options.AuthoritativeDir)
     return;
   now = time(NULL);
@@ -591,6 +596,11 @@
     tor_free(cached_directory);
     cached_directory = tor_strdup(directory);
     cached_directory_len = strlen(cached_directory);
+    cached_directory_published = when;
+    sprintf(filename,"%s/cached-directory", options.DataDirectory);
+    if(write_str_to_file(filename,cached_directory) < 0) {
+      log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
+    }
   }
 }
 
@@ -644,12 +654,70 @@
   return the_directory_len;
 }
 
+static char *runningrouters_string=NULL;
+static size_t runningrouters_len=0;
+
+/** Replace the current running-routers list with a newly generated one. */
+static int generate_runningrouters(crypto_pk_env_t *private_key)
+{
+  char *s, *cp;
+  char digest[DIGEST_LEN];
+  char signature[PK_BYTES];
+  int i, len;
+  char published[33];
+  time_t published_on;
+
+  len = 1024+MAX_NICKNAME_LEN*smartlist_len(descriptor_list);
+  s = tor_malloc_zero(len);
+  if (list_running_servers(&cp))
+    return -1;
+  published_on = time(NULL);
+  strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
+  sprintf(s, "network-status\n"
+             "published %s\n"
+             "running-routers %s\n"
+             "directory-signature %s\n"
+             "-----BEGIN SIGNATURE-----\n",
+             published, cp, options.Nickname);
+  free(cp);
+  if (router_get_runningrouters_hash(s,digest)) {
+    log_fn(LOG_WARN,"couldn't compute digest");
+    return -1;
+  }
+  if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
+    log_fn(LOG_WARN,"couldn't sign digest");
+    return -1;
+  }
+
+  i = strlen(s);
+  cp = s+i;
+  if (base64_encode(cp, len-i, signature, 128) < 0) {
+    log_fn(LOG_WARN,"couldn't base64-encode signature");
+    return -1;
+  }
+  if (strlcat(s, "-----END SIGNATURE-----\n", len) >= len) {
+    return -1;
+  }
+
+  tor_free(runningrouters_string);
+  runningrouters_string = s;
+  runningrouters_len = strlen(s);
+  runningrouters_is_dirty = 0;
+  return 0;
+}
+
 /** Set *<b>rr</b> to the most recently generated encoded signed
  * running-routers list, generating a new one as necessary. */
 size_t dirserv_get_runningrouters(const char **rr)
 {
-  /* XXX008 fill in this function */
-  return 0;
+  if (runningrouters_is_dirty) {
+    if(generate_runningrouters(get_identity_key())) {
+      log_fn(LOG_ERR, "Couldn't generate running-routers list?");
+      return -1;
+    }
+  }
+  *rr = runningrouters_string;
+  return runningrouters_len;
 }
 
 /*

Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.284
retrieving revision 1.285
diff -u -d -r1.284 -r1.285
--- main.c	21 Jun 2004 04:37:26 -0000	1.284
+++ main.c	25 Jun 2004 00:29:30 -0000	1.285
@@ -451,9 +451,8 @@
       router_rebuild_descriptor();
       router_upload_dir_desc_to_dirservers();
     }
-    if(!options.DirPort) {
-      /* NOTE directory servers do not currently fetch directories.
-       * Hope this doesn't bite us later. */
+    if(!options.DirPort || !options.AuthoritativeDir) {
+      /* XXXX should directories do this next part too? */
       routerlist_remove_old_routers(); /* purge obsolete entries */
       directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
     } else {
@@ -461,6 +460,8 @@
       dirserv_remove_old_servers();
       /* dirservers try to reconnect too, in case connections have failed */
       router_retry_connections();
+      /* fetch another directory, in case it knows something we don't */
+      directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
     }
     /* Force an upload of our descriptors every DirFetchPostPeriod seconds. */
     rend_services_upload(1);

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.370
retrieving revision 1.371
diff -u -d -r1.370 -r1.371
--- or.h	21 Jun 2004 04:37:26 -0000	1.370
+++ or.h	25 Jun 2004 00:29:31 -0000	1.371
@@ -595,10 +595,17 @@
    * published?
    */
   time_t published_on;
+  time_t running_routers_updated_on;
   /** Which router is claimed to have signed it? */
   char *signing_router;
 } routerlist_t;
 
+/* DOCDOC */
+typedef struct running_routers_t {
+  time_t published_on;
+  smartlist_t *running_routers;
+} running_routers_t;
+
 /** Holds accounting information for a single step in the layered encryption
  * performed by a circuit.  Used only at the client edge of a circuit. */
 struct crypt_path_t {
@@ -1130,7 +1137,7 @@
 int dirserv_router_fingerprint_is_known(const routerinfo_t *router);
 void dirserv_free_fingerprint_list();
 int dirserv_add_descriptor(const char **desc);
-int dirserv_init_from_directory_string(const char *dir);
+int dirserv_load_from_directory_string(const char *dir);
 void dirserv_free_descriptors();
 void dirserv_remove_old_servers(void);
 int dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
@@ -1352,11 +1359,15 @@
 #define ADDR_POLICY_UNKNOWN 1
 int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port);
 int router_exit_policy_rejects_all(routerinfo_t *router);
+void running_routers_free(running_routers_t *rr);
+void routerlist_update_from_runningrouters(routerlist_t *list,
+                                           running_routers_t *rr);
 
 /********************************* routerparse.c ************************/
 
 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);
 int router_parse_list_from_string(const char **s,
                                        routerlist_t **dest,
                                        int n_good_nicknames,
@@ -1364,6 +1375,7 @@
 int router_parse_routerlist_from_directory(const char *s,
                                            routerlist_t **dest,
                                            crypto_pk_env_t *pkey);
+running_routers_t *router_parse_runningrouters(const char *str);
 routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
 int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
 struct exit_policy_t *router_parse_exit_policy_from_string(const char *s);

Index: rephist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/rephist.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- rephist.c	18 May 2004 15:35:21 -0000	1.9
+++ rephist.c	25 Jun 2004 00:29:31 -0000	1.10
@@ -248,6 +248,45 @@
   }
 }
 
+#if 0
+void write_rep_history(const char *filename)
+{
+  FILE *f = NULL;
+  char *tmpfile;
+  int completed = 0;
+  or_history_t *or_history;
+  link_history_t *link_history;
+  strmap_iter_t *lhist_it;
+  strmap_iter_t *orhist_it;
+  void *or_history_p, *link_history_p;
+  const char *name1;
+
+  tmpfile = tor_malloc(strlen(filename)+5);
+  strcpy(tmpfile, filename);
+  strcat(tmpfile, "_tmp");
+
+  f = fopen(tmpfile, "w");
+  if (!f) goto done;
+  for (orhist_it = strmap_iter_init(history_map); !strmap_iter_done(orhist_it);
+       orhist_it = strmap_iter_next(history_map,orhist_it)) {
+    strmap_iter_get(orhist_it, &name1, &or_history_p);
+    or_history = (or_history_t*) or_history_p;
+    fprintf(f, "link %s connected:u%ld failed:%uld uptime:%uld",
+            name1, or_history->since1,
+  }
+
+
+ done:
+  if (f)
+    fclose(f);
+  if (completed)
+    replace_file(filename, tmpfile);
+  else
+    unlink(tmpfile);
+  tor_free(tmpfile);
+}
+#endif
+
 /*
   Local Variables:
   mode:c

Index: router.c
===================================================================
RCS file: /home/or/cvsroot/src/or/router.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -d -r1.50 -r1.51
--- router.c	21 Jun 2004 04:40:24 -0000	1.50
+++ router.c	25 Jun 2004 00:29:31 -0000	1.51
@@ -284,12 +284,14 @@
   if(!cp) {
     log_fn(LOG_INFO,"Cached directory %s not present. Ok.",keydir);
   } else {
-    if(dirserv_init_from_directory_string(cp) < 0) {
+    if(options.AuthoritativeDir && dirserv_load_from_directory_string(cp) < 0){
       log_fn(LOG_ERR, "Cached directory %s is corrupt", keydir);
       free(cp);
       return -1;
     }
-    free(cp);
+    /* set time to 1 so it will be replaced on first download.
+     */
+    dirserv_set_cached_directory(cp, 1);
   }
   /* success */
   return 0;

Index: routerlist.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerlist.c,v
retrieving revision 1.86
retrieving revision 1.87
diff -u -d -r1.86 -r1.87
--- routerlist.c	21 Jun 2004 04:37:27 -0000	1.86
+++ routerlist.c	25 Jun 2004 00:29:31 -0000	1.87
@@ -477,7 +477,11 @@
     log_fn(LOG_WARN, "Error resolving routerlist");
     return -1;
   }
+  /* Remember the directory, if we're nonauthoritative.*/
   dirserv_set_cached_directory(s, routerlist->published_on);
+  /* Learn about the descriptors in the directory, if we're authoritative */
+  if (options.AuthoritativeDir)
+    dirserv_load_from_directory_string(s);
   return 0;
 }
 
@@ -621,6 +625,50 @@
     == ADDR_POLICY_REJECTED;
 }
 
+/* DODCDOC */
+void running_routers_free(running_routers_t *rr)
+{
+  tor_assert(rr);
+  if (rr->running_routers) {
+    SMARTLIST_FOREACH(rr->running_routers, char *, s, tor_free(s));
+    smartlist_free(rr->running_routers);
+  }
+  tor_free(rr);
+}
+
+/* DOCDOC*/
+void routerlist_update_from_runningrouters(routerlist_t *list,
+                                           running_routers_t *rr)
+{
+  int n_routers, n_names, i, j, running;
+  routerinfo_t *router;
+  const char *name;
+  if (!routerlist)
+    return;
+  if (routerlist->published_on >= rr->published_on)
+    return;
+  if (routerlist->running_routers_updated_on >= rr->published_on)
+    return;
+
+  n_routers = smartlist_len(list->routers);
+  n_names = smartlist_len(rr->running_routers);
+  for (i=0; i<n_routers; ++i) {
+    running = 0;
+    router = smartlist_get(list->routers, i);
+    for (j=0; j<n_names; ++j) {
+      name = smartlist_get(rr->running_routers, j);
+      if (!strcmp(name, router->nickname)) {
+        running=1;
+        break;
+      }
+    }
+    router->is_running = 1; /* arma: is this correct? */
+  }
+  routerlist->running_routers_updated_on = rr->published_on;
+  /* XXXX008 Should there also be a list of which are down, so that we
+   * don't mark merely unknown routers as down? */
+}
+
 /*
   Local Variables:
   mode:c

Index: routerparse.c
===================================================================
RCS file: /home/or/cvsroot/src/or/routerparse.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- routerparse.c	21 Jun 2004 04:37:27 -0000	1.6
+++ routerparse.c	25 Jun 2004 00:29:31 -0000	1.7
@@ -41,6 +41,7 @@
   K_PORTS,
   K_DIRCACHEPORT,
   K_CONTACT,
+  K_NETWORK_STATUS,
   _UNRECOGNIZED,
   _ERR,
   _EOF,
@@ -88,7 +89,7 @@
 typedef enum {
   ANY = 0,    /**< Appears in router descriptor or in directory sections. */
   DIR_ONLY,   /**< Appears only in directory. */
-  RTR_ONLY,   /**< Appears only in router descriptor. */
+  RTR_ONLY,   /**< Appears only in router descriptor or runningrouters */
 } where_syntax;
 
 /** Table mapping keywords to token value and to argument rules. */
@@ -113,6 +114,7 @@
   { "opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK,  ANY },
   { "dircacheport",        K_DIRCACHEPORT,        ARGS,    NO_OBJ,  RTR_ONLY },
   { "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ,  ANY },
+  { "network-status",      K_NETWORK_STATUS,      NO_ARGS, NO_OBJ,  DIR_ONLY },
   { NULL, -1 }
 };
 
@@ -128,6 +130,10 @@
 static int tokenize_string(const char *start, const char *end,
                            smartlist_t *out, int is_dir);
 static directory_token_t *get_next_token(const char **s, where_syntax where);
+static int check_directory_signature(const char *digest,
+                                     directory_token_t *tok,
+                                     crypto_pk_env_t *pkey);
+
 
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
  * <b>s</b>.  Return 0 on success, nonzero on failure.
@@ -147,6 +153,13 @@
                               "router ","router-signature");
 }
 
+/** DOCDOC */
+int router_get_runningrouters_hash(const char *s, char *digest)
+{
+  return router_get_hash_impl(s,digest,
+                              "network-status ","directory-signature");
+}
+
 /** Parse a date of the format "YYYY-MM-DD hh:mm:ss" and store the result into
  * *<b>t</b>.
  */
@@ -273,13 +286,12 @@
 				       crypto_pk_env_t *pkey)
 {
   directory_token_t *tok;
-  char digest[20];
-  char signed_digest[128];
+  char digest[DIGEST_LEN];
   routerlist_t *new_dir = NULL;
   char *versions = NULL;
-  time_t published_on;
-  char *good_nickname_lst[1024];
   int n_good_nicknames = 0;
+  char *good_nickname_lst[1024]; /* XXXX008 correct this limit. */
+  time_t published_on;
   int i, r;
   const char *end;
   smartlist_t *tokens = NULL;
@@ -373,6 +385,108 @@
       (tok->tp != K_DIRECTORY_SIGNATURE)) {
     log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
   }
+  if (check_directory_signature(digest, smartlist_get(tokens,0), pkey)<0) {
+    goto err;
+  }
+
+  if (*dest)
+    routerlist_free(*dest);
+  *dest = new_dir;
+
+  r = 0;
+  goto done;
+ err:
+  r = -1;
+  if (new_dir)
+    routerlist_free(new_dir);
+  tor_free(versions);
+  for (i = 0; i < n_good_nicknames; ++i) {
+    tor_free(good_nickname_lst[i]);
+  }
+ done:
+  if (tokens) {
+    SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
+    smartlist_free(tokens);
+  }
+  return r;
+}
+
+running_routers_t *
+router_parse_runningrouters(const char *str)
+{
+  char digest[DIGEST_LEN];
+  running_routers_t *new_list = NULL;
+  directory_token_t *tok;
+  time_t published_on;
+  int i;
+
+  smartlist_t *tokens = NULL;
+
+  if (router_get_runningrouters_hash(str, digest)) {
+    log_fn(LOG_WARN, "Unable to compute digest of directory");
+    goto err;
+  }
+  tokens = smartlist_create();
+  if (tokenize_string(str,str+strlen(str),tokens,1)) {
+    log_fn(LOG_WARN, "Error tokenizing directory"); goto err;
+  }
+  if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
+    log_fn(LOG_WARN, "Unrecognized keyword in \"%s\"; can't parse directory.",
+           tok->args[0]);
+    goto err;
+  }
+  tok = smartlist_get(tokens,0);
+  if (tok->tp != K_NETWORK_STATUS) {
+    log_fn(LOG_WARN, "Network-status starts with wrong token");
+    goto err;
+  }
+
+  if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
+    log_fn(LOG_WARN, "Missing published time on directory.");
+    goto err;
+  }
+  tor_assert(tok->n_args == 1);
+  if (parse_time(tok->args[0], &published_on) < 0) {
+     goto err;
+  }
+
+  if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
+    log_fn(LOG_WARN, "Missing running-routers line from directory.");
+    goto err;
+  }
+
+  new_list = tor_malloc_zero(sizeof(running_routers_t));
+  new_list->published_on = published_on;
+  new_list->running_routers = smartlist_create();
+  for (i=0;i<tok->n_args;++i) {
+    smartlist_add(new_list->running_routers, tok->args[i]);
+  }
+
+  if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
+    log_fn(LOG_WARN, "Missing signature on directory");
+    goto err;
+  }
+  if (check_directory_signature(digest, tok, NULL)<0) {
+    goto err;
+  }
+
+  goto done;
+ err:
+  running_routers_free(new_list);
+  new_list = NULL;
+ done:
+  if (tokens) {
+    SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
+    smartlist_free(tokens);
+  }
+  return new_list;
+}
+
+static int check_directory_signature(const char *digest,
+                                      directory_token_t *tok,
+                                      crypto_pk_env_t *pkey)
+{
+  char signed_digest[PK_BYTES];
   if (tok->n_args == 1) {
     routerinfo_t *r = router_get_by_nickname(tok->args[0]);
     log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
@@ -383,53 +497,38 @@
     } else if (!r) {
       log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
              tok->args[0]);
-      goto err;
+      return -1;
     } else if (r && !r->is_trusted_dir) {
       log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
              tok->args[0]);
-      goto err;
+      return -1;
     }
+  } else if (tok->n_args > 1) {
+    log_fn(LOG_WARN, "Too many arguments to directory-signature");
+    return -1;
   }
   if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
     log_fn(LOG_WARN, "Bad object type or length on directory signature");
-    goto err;
+    return -1;
   }
   if (pkey) {
     if (crypto_pk_public_checksig(pkey, tok->object_body, 128, signed_digest)
         != 20) {
       log_fn(LOG_WARN, "Error reading directory: invalid signature.");
-      goto err;
+      return -1;
     }
     log(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
-
     if (memcmp(digest, signed_digest, 20)) {
       log_fn(LOG_WARN, "Error reading directory: signature does not match.");
-      goto err;
+      return -1;
     }
+  } else {
+    /* XXXX008 freak out, unless testing. */
   }
-
-  if (*dest)
-    routerlist_free(*dest);
-  *dest = new_dir;
-
-  r = 0;
-  goto done;
- err:
-  r = -1;
-  if (new_dir)
-    routerlist_free(new_dir);
-  tor_free(versions);
-  for (i = 0; i < n_good_nicknames; ++i) {
-    tor_free(good_nickname_lst[i]);
-  }
- done:
-  if (tokens) {
-    SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
-    smartlist_free(tokens);
-  }
-  return r;
+  return 0;
 }
 
+
 /** Given a string *<b>s</b> containing a concatenated
  * sequence of router descriptors, parses them and stores the result
  * in *<b>dest</b>.  If good_nickname_lst is provided, then routers whose



More information about the tor-commits mailing list