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

[or-cvs] r10295: First draft of code to generate votes. needs testing. does n (in tor/trunk: . doc src/or)



Author: nickm
Date: 2007-05-22 14:52:32 -0400 (Tue, 22 May 2007)
New Revision: 10295

Modified:
   tor/trunk/
   tor/trunk/doc/TODO
   tor/trunk/src/or/dirserv.c
   tor/trunk/src/or/or.h
   tor/trunk/src/or/router.c
   tor/trunk/src/or/routerparse.c
Log:
 r12902@catbus:  nickm | 2007-05-22 14:52:29 -0400
 First draft of code to generate votes. needs testing. does not yet upload or serve votes.  Shares most of its code with the old generate_v2_networkstatus.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r12902] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-05-22 17:58:30 UTC (rev 10294)
+++ tor/trunk/doc/TODO	2007-05-22 18:52:32 UTC (rev 10295)
@@ -76,7 +76,7 @@
           - Serve list as needed.
           o Avoid double-checking signatures every time we get a vote.
           - Warn about expired stuff.
-        - Code to generate votes
+        o Code to generate votes
         - Code to generate consensus from a list of votes
         - Add a signature to a consensus.
         - Code to check signatures on a consensus

Modified: tor/trunk/src/or/dirserv.c
===================================================================
--- tor/trunk/src/or/dirserv.c	2007-05-22 17:58:30 UTC (rev 10294)
+++ tor/trunk/src/or/dirserv.c	2007-05-22 18:52:32 UTC (rev 10295)
@@ -1414,6 +1414,10 @@
 /** For authoritative directories: the current (v2) network status. */
 static cached_dir_t *the_v2_networkstatus = NULL;
 
+/** For authoritative directories: out most recent vote for the (v3) network
+ * status */
+static cached_dir_t *the_v3_networkstatus_vote = NULL;
+
 /** Return true iff our opinion of the routers has been stale for long
  * enough that we should generate a new v2 network status doc. */
 static int
@@ -1602,7 +1606,7 @@
                    ipaddr,
                    (int)rs->or_port,
                    (int)rs->dir_port,
-
+                   /* These must stay in alphabetical order. */
                    f_authority?" Authority":"",
                    rs->is_bad_exit?" BadExit":"",
                    rs->is_exit?" Exit":"",
@@ -1641,11 +1645,21 @@
   return 0;
 }
 
+/** DOCDOC */
+static int
+_compare_routerinfo_by_id_digest(const void **a, const void **b)
+{
+  routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
+  return memcmp(first->cache_info.identity_digest,
+                second->cache_info.identity_digest,
+                DIGEST_LEN);
+}
+
 /** For v2 authoritative directories only: replace the contents of
  * <b>the_v2_networkstatus</b> with a newly generated network status
- * object. */
+ * object. DOCDOC v2*/
 static cached_dir_t *
-generate_v2_networkstatus(void)
+generate_networkstatus_opinion(int v2)
 {
 /** Longest status flag name that we generate. */
 #define LONGEST_STATUS_FLAG_NAME_LEN 9
@@ -1671,7 +1685,7 @@
   char digest[DIGEST_LEN];
   struct in_addr in;
   uint32_t addr;
-  crypto_pk_env_t *private_key = get_identity_key();
+  crypto_pk_env_t *private_key;
   routerlist_t *rl = router_get_routerlist();
   time_t now = time(NULL);
   time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
@@ -1680,7 +1694,21 @@
   int listbadexits = options->AuthDirListBadExits;
   int exits_can_be_guards;
   const char *contact;
+  authority_cert_t *cert = NULL;
+  char *version_lines = NULL;
+  smartlist_t *routers = NULL;
 
+  if (v2) {
+    private_key = get_identity_key();
+  } else {
+    private_key = get_my_v3_authority_signing_key();
+    cert = get_my_v3_authority_cert();
+    if (!private_key || !cert) {
+      log_warn(LD_NET, "Didn't find key/certificate to generate v3 vote");
+      goto done;
+    }
+  }
+
   if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
     log_warn(LD_NET, "Couldn't resolve my hostname");
     goto done;
@@ -1699,29 +1727,47 @@
     goto done;
   }
 
-  if (crypto_pk_get_fingerprint(private_key, fingerprint, 0)<0) {
-    log_err(LD_BUG, "Error computing fingerprint");
-    goto done;
+  if (v2) {
+    if (crypto_pk_get_fingerprint(private_key, fingerprint, 0)<0) {
+      log_err(LD_BUG, "Error computing fingerprint");
+      goto done;
+    }
+  } else {
+    base16_encode(fingerprint, sizeof(fingerprint),
+                  cert->cache_info.identity_digest, DIGEST_LEN);
   }
 
   contact = get_options()->ContactInfo;
   if (!contact)
     contact = "(none)";
 
-  len = 2048+strlen(client_versions)+strlen(server_versions);
+  if (versioning) {
+    size_t v_len = 32+strlen(client_versions)+strlen(server_versions);
+    version_lines = tor_malloc(v_len);
+    tor_snprintf(version_lines, v_len,
+                 "client-versions %s\nserver-versions %s\n",
+                 client_versions, server_versions);
+  } else {
+    version_lines = tor_strdup("");
+  }
+
+  len = 4096+strlen(client_versions)+strlen(server_versions);
   len += identity_pkey_len*2;
   len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
+  if (!v2) {
+    len += cert->cache_info.signed_descriptor_len;
+  }
 
   status = tor_malloc(len);
-  tor_snprintf(status, len,
+  if (v2) {
+    tor_snprintf(status, len,
                "network-status-version 2\n"
                "dir-source %s %s %d\n"
                "fingerprint %s\n"
                "contact %s\n"
                "published %s\n"
                "dir-options%s%s%s\n"
-               "%s%s" /* client versions %s */
-               "%s%s%s" /* \nserver versions %s \n */
+               "%s" /* client version line, server version line. */
                "dir-signing-key\n%s\n",
                hostname, ipaddr, (int)options->DirPort,
                fingerprint,
@@ -1730,14 +1776,38 @@
                naming ? " Names" : "",
                listbadexits ? " BadExits" : "",
                versioning ? " Versions" : "",
-               versioning ? "client-versions " : "",
-               versioning ? client_versions : "",
-               versioning ? "\nserver-versions " : "",
-               versioning ? server_versions : "",
-               versioning ? "\n" : "",
+               version_lines,
                identity_pkey);
-  outp = status + strlen(status);
-  endp = status + len;
+    outp = status + strlen(status);
+    endp = status + len;
+  } else {
+    tor_snprintf(status, len,
+                 "network-status-version 3\n"
+                 "vote-status vote\n"
+                 "published %s\n"
+                 "valid-after %s\n"
+                 "valid-until %s\n"
+                 "%s" /* versions */
+                 "known-flags Authority Exit Fast Guard Stable "
+                               "Running Valid V2Dir%s%s\n"
+                 "dir-source %s %s %s %s %d\n"
+                 "contact %s\n",
+                 published,
+                 published, /* XXXX020 should be valid-after*/
+                 published, /* XXXX020 should be valid-until*/
+                 version_lines,
+                 naming ? " Named" : "",
+                 listbadexits ? " BadExit" : "",
+                 options->Nickname, fingerprint, options->Address,
+                    ipaddr, (int)options->DirPort,
+                 contact);
+    outp = status + strlen(status);
+    endp = status + len;
+    tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
+    memcpy(outp, cert->cache_info.signed_descriptor_body,
+           cert->cache_info.signed_descriptor_len);
+    outp += cert->cache_info.signed_descriptor_len;
+  }
 
   /* precompute this part, since we need it to decide what "stable"
    * means. */
@@ -1751,7 +1821,11 @@
    * total_exit_bandwidth is close to total_bandwidth/3. */
   exits_can_be_guards = total_exit_bandwidth >= (total_bandwidth / 3);
 
-  SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
+  routers = smartlist_create();
+  smartlist_add_all(routers, rl->routers);
+  smartlist_sort(routers, _compare_routerinfo_by_id_digest);
+
+  SMARTLIST_FOREACH(routers, routerinfo_t *, ri, {
     if (ri->cache_info.published_on >= cutoff) {
       /* Already set by compute_performance_thresholds. */
       int f_exit = ri->is_exit;
@@ -1808,37 +1882,65 @@
     }
   });
 
-  if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
-                   get_options()->Nickname)<0) {
-    log_warn(LD_BUG, "Unable to write signature line.");
-    goto done;
+  if (v2) {
+    if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
+                     get_options()->Nickname)<0) {
+      log_warn(LD_BUG, "Unable to write signature line.");
+      goto done;
+    }
+    if (router_get_networkstatus_v2_hash(status, digest)<0) {
+      log_warn(LD_BUG, "Unable to hash network status");
+      goto done;
+    }
+    outp += strlen(outp);
+  } else {
+    char hex_digest[HEX_DIGEST_LEN+1];
+    if (tor_snprintf(outp, endp-outp, "directory-signature %s ",
+                     fingerprint)<0) {
+      log_warn(LD_BUG, "Unable to start signature line.");
+      goto done;
+    }
+    if (router_get_networkstatus_v3_hash(status, digest)<0) {
+      log_warn(LD_BUG, "Unable to hash network status vote");
+      goto done;
+    }
+    base16_encode(hex_digest, sizeof(hex_digest), digest, DIGEST_LEN);
+    outp += strlen(outp);
+    if (tor_snprintf(outp, endp-outp, "%s\n", hex_digest)<0) {
+      log_warn(LD_BUG, "Unable to end signature line.");
+      goto done;
+    }
+    outp += strlen(outp);
   }
 
-  if (router_get_networkstatus_v2_hash(status, digest)<0) {
-    log_warn(LD_BUG, "Unable to hash network status");
-    goto done;
-  }
-
   note_crypto_pk_op(SIGN_DIR);
   if (router_append_dirobj_signature(outp,endp-outp,digest,private_key)<0) {
     log_warn(LD_BUG, "Unable to sign router status.");
     goto done;
   }
 
-  if (the_v2_networkstatus)
-    cached_dir_decref(the_v2_networkstatus);
-  the_v2_networkstatus = new_cached_dir(status, now);
-  status = NULL; /* So it doesn't get double-freed. */
-  the_v2_networkstatus_is_dirty = 0;
-  router_set_networkstatus(the_v2_networkstatus->dir,
-                           now, NS_GENERATED, NULL);
-  r = the_v2_networkstatus;
+  {
+    cached_dir_t **ns_ptr =
+      v2 ? &the_v2_networkstatus : &the_v3_networkstatus_vote;
+    if (*ns_ptr)
+      cached_dir_decref(*ns_ptr);
+    *ns_ptr = new_cached_dir(status, now);
+    status = NULL; /* So it doesn't get double-freed. */
+    if (v2)
+      the_v2_networkstatus_is_dirty = 0;
+    router_set_networkstatus((*ns_ptr)->dir, now, NS_GENERATED, NULL);
+    r = *ns_ptr;
+  }
+
  done:
   tor_free(client_versions);
   tor_free(server_versions);
+  tor_free(version_lines);
   tor_free(status);
   tor_free(hostname);
   tor_free(identity_pkey);
+  if (routers)
+    smartlist_free(routers);
   return r;
 }
 
@@ -1855,7 +1957,7 @@
     cached_v2_networkstatus = digestmap_new();
 
   if (should_generate_v2_networkstatus())
-    generate_v2_networkstatus();
+    generate_networkstatus_opinion(1);
 
   if (!strcmp(key,"authority")) {
     if (authdir_mode_v2(get_options())) {
@@ -1910,7 +2012,7 @@
   SMARTLIST_FOREACH(fingerprints, const char *, fp,
     {
       if (router_digest_is_me(fp) && should_generate_v2_networkstatus())
-        generate_v2_networkstatus();
+        generate_networkstatus_opinion(1);
       cached = digestmap_get(cached_v2_networkstatus, fp);
       if (cached) {
         smartlist_add(result, cached);

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-05-22 17:58:30 UTC (rev 10294)
+++ tor/trunk/src/or/or.h	2007-05-22 18:52:32 UTC (rev 10295)
@@ -2994,6 +2994,8 @@
 void set_identity_key(crypto_pk_env_t *k);
 crypto_pk_env_t *get_identity_key(void);
 int identity_key_is_set(void);
+authority_cert_t *get_my_v3_authority_cert(void);
+crypto_pk_env_t *get_my_v3_authority_signing_key(void);
 void dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last);
 void rotate_onion_key(void);
 crypto_pk_env_t *init_key_from_file(const char *fname);
@@ -3258,6 +3260,7 @@
 int router_get_dir_hash(const char *s, char *digest);
 int router_get_runningrouters_hash(const char *s, char *digest);
 int router_get_networkstatus_v2_hash(const char *s, char *digest);
+int router_get_networkstatus_v3_hash(const char *s, char *digest);
 int router_get_extrainfo_hash(const char *s, char *digest);
 int router_append_dirobj_signature(char *buf, size_t buf_len,
                                    const char *digest,

Modified: tor/trunk/src/or/router.c
===================================================================
--- tor/trunk/src/or/router.c	2007-05-22 17:58:30 UTC (rev 10294)
+++ tor/trunk/src/or/router.c	2007-05-22 18:52:32 UTC (rev 10295)
@@ -122,6 +122,20 @@
   return identitykey != NULL;
 }
 
+/** DOCDOC */
+authority_cert_t *
+get_my_v3_authority_cert(void)
+{
+  return authority_key_certificate;
+}
+
+/** DOCDOC */
+crypto_pk_env_t *
+get_my_v3_authority_signing_key(void)
+{
+  return authority_signing_key;
+}
+
 /** Replace the previous onion key with the current onion key, and generate
  * a new previous onion key.  Immediately after calling this function,
  * the OR should:

Modified: tor/trunk/src/or/routerparse.c
===================================================================
--- tor/trunk/src/or/routerparse.c	2007-05-22 17:58:30 UTC (rev 10294)
+++ tor/trunk/src/or/routerparse.c	2007-05-22 18:52:32 UTC (rev 10295)
@@ -352,7 +352,8 @@
 static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
 
 static int router_get_hash_impl(const char *s, char *digest,
-                                const char *start_str, const char *end_str);
+                                const char *start_str, const char *end_str,
+                                char end_char);
 static void token_free(directory_token_t *tok);
 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
 static directory_token_t *find_first_by_keyword(smartlist_t *s,
@@ -377,7 +378,7 @@
 router_get_dir_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
-                              "signed-directory","\ndirectory-signature");
+                              "signed-directory","\ndirectory-signature",'\n');
 }
 
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
@@ -387,7 +388,7 @@
 router_get_router_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
-                              "router ","\nrouter-signature");
+                              "router ","\nrouter-signature", '\n');
 }
 
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
@@ -397,7 +398,7 @@
 router_get_runningrouters_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
-                              "network-status","\ndirectory-signature");
+                              "network-status","\ndirectory-signature", '\n');
 }
 
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
@@ -406,15 +407,26 @@
 router_get_networkstatus_v2_hash(const char *s, char *digest)
 {
   return router_get_hash_impl(s,digest,
-                            "network-status-version","\ndirectory-signature");
+                              "network-status-version","\ndirectory-signature",
+                              '\n');
 }
 
+/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
+ * string in <b>s</b>.  Return 0 on success, -1 on failure. */
+int
+router_get_networkstatus_v3_hash(const char *s, char *digest)
+{
+  return router_get_hash_impl(s,digest,
+                              "network-status-version","\ndirectory-signature",
+                              ' ');
+}
+
 /** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo
  * string in <b>s</b>.  Return 0 on success, -1 on failure. */
 int
 router_get_extrainfo_hash(const char *s, char *digest)
 {
-  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature");
+  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n');
 }
 
 /** Helper: used to generate signatures for routers, directories and
@@ -1317,7 +1329,7 @@
     goto err;
   }
   if (router_get_hash_impl(s, digest, "dir-key-certificate-version",
-                           "\ndir-key-certification") < 0)
+                           "\ndir-key-certification", '\n') < 0)
     goto err;
   tok = smartlist_get(tokens, 0);
   if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
@@ -2215,8 +2227,8 @@
 }
 
 /** Compute the SHA-1 digest of the substring of <b>s</b> taken from the first
- * occurrence of <b>start_str</b> through the first newline after the first
- * subsequent occurrence of <b>end_str</b>; store the 20-byte result in
+ * occurrence of <b>start_str</b> through the first instance of c after the
+ * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
  * <b>digest</b>; return 0 on success.
  *
  * If no such substring exists, return -1.
@@ -2224,7 +2236,7 @@
 static int
 router_get_hash_impl(const char *s, char *digest,
                      const char *start_str,
-                     const char *end_str)
+                     const char *end_str, char end_c)
 {
   char *start, *end;
   start = strstr(s, start_str);
@@ -2243,7 +2255,7 @@
     log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str);
     return -1;
   }
-  end = strchr(end+strlen(end_str), '\n');
+  end = strchr(end+strlen(end_str), end_c);
   if (!end) {
     log_warn(LD_DIR,"couldn't find EOL");
     return -1;