Browse Source

r14623@tombo: nickm | 2007-11-01 22:25:18 -0400
More tweaks from karsten, with some cleanup and commentary.


svn:r12319

Nick Mathewson 17 years ago
parent
commit
832ef9562f
8 changed files with 80 additions and 55 deletions
  1. 5 0
      doc/tor.1.in
  2. 4 0
      src/config/torrc.complete.in
  3. 0 1
      src/or/config.c
  4. 1 0
      src/or/main.c
  5. 6 7
      src/or/or.h
  6. 27 40
      src/or/rendcommon.c
  7. 8 2
      src/or/rendservice.c
  8. 29 5
      src/or/routerparse.c

+ 5 - 0
doc/tor.1.in

@@ -1107,6 +1107,11 @@ if you're using a Tor controller that handles hidserv publishing for you.
 (Default: 1)
 (Default: 1)
 .LP
 .LP
 .TP
 .TP
+\fBHiddenServiceVersion \fR\fIversion\fR,\fIversion\fR,\fI...\fP
+A list of rendezvous service descriptor versions to publish for the hidden
+service. Possible version numbers are 0 and 2. (Default: 0, 2)
+.LP
+.TP
 \fBRendPostPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP
 \fBRendPostPeriod \fR\fIN\fR \fBseconds\fR|\fBminutes\fR|\fBhours\fR|\fBdays\fR|\fBweeks\fP
 Every time the specified period elapses, Tor uploads any rendezvous
 Every time the specified period elapses, Tor uploads any rendezvous
 service descriptors to the directory servers.  This information is also
 service descriptors to the directory servers.  This information is also

+ 4 - 0
src/config/torrc.complete.in

@@ -521,6 +521,10 @@
 ## hidden service. In normal use there is no reason to set this.
 ## hidden service. In normal use there is no reason to set this.
 #HiddenServiceExcludeNodes nickname,nickname,...
 #HiddenServiceExcludeNodes nickname,nickname,...
 
 
+## Publish the given rendezvous service descriptor versions for the
+## hidden service.
+#HiddenServiceVersion 0,2
+
 ## Every time the specified period elapses, Tor uploads any ren-
 ## Every time the specified period elapses, Tor uploads any ren-
 ## dezvous service descriptors to the directory servers.  This
 ## dezvous service descriptors to the directory servers.  This
 ## information is also uploaded whenever it changes. 
 ## information is also uploaded whenever it changes. 

+ 0 - 1
src/or/config.c

@@ -192,7 +192,6 @@ static config_var_t _option_vars[] = {
   VAR("HiddenServiceNodes",  LINELIST_S, RendConfigLines,    NULL),
   VAR("HiddenServiceNodes",  LINELIST_S, RendConfigLines,    NULL),
   VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
   VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines,    NULL),
   VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
   VAR("HiddenServicePort",   LINELIST_S, RendConfigLines,    NULL),
-  /*DOCDOC in tor manpage*/
   VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines,    NULL),
   VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines,    NULL),
   V(HSAuthoritativeDir,          BOOL,     "0"),
   V(HSAuthoritativeDir,          BOOL,     "0"),
   V(HSAuthorityRecordStats,      BOOL,     "0"),
   V(HSAuthorityRecordStats,      BOOL,     "0"),

+ 1 - 0
src/or/main.c

@@ -973,6 +973,7 @@ run_scheduled_events(time_t now)
      * and the rend cache. */
      * and the rend cache. */
     rep_history_clean(now - options->RephistTrackTime);
     rep_history_clean(now - options->RephistTrackTime);
     rend_cache_clean();
     rend_cache_clean();
+    rend_cache_clean_v2_descs_as_dir();
     /* XXX020 we only clean this stuff if DirPort is set?! -RD */
     /* XXX020 we only clean this stuff if DirPort is set?! -RD */
   }
   }
 
 

+ 6 - 7
src/or/or.h

@@ -1785,6 +1785,11 @@ typedef struct origin_circuit_t {
    * rendezvous service ID, but different descriptor versions.
    * rendezvous service ID, but different descriptor versions.
    * XXXX020 I believe this is a bitmap, but the doc doesn't say so. If so,
    * XXXX020 I believe this is a bitmap, but the doc doesn't say so. If so,
    *  why?  A circuit can't be using two different rendezvous decriptors. -NM
    *  why?  A circuit can't be using two different rendezvous decriptors. -NM
+   * Yes, it is a bitmap. The reason is that it might turn out that a version
+   * 3 _can_ use the same introduction point as version 2; only version 0
+   * is incompatible. Would it be clearer to switch to a single version number
+   * for now and switch back to a bitmap, when the above becomes true? -KL
+   * Yes.  "YAGNI." -NM
    */
    */
   uint8_t rend_desc_version;
   uint8_t rend_desc_version;
 
 
@@ -3485,14 +3490,8 @@ typedef struct rend_cache_entry_t {
 } rend_cache_entry_t;
 } rend_cache_entry_t;
 
 
 void rend_cache_init(void);
 void rend_cache_init(void);
-/*XXXX020 clean *and* clean_up *and* clean_v2_dir? Rename some. */
-/*XXXX020 Call clean_up and clean_v2_dir from somewhere; nothing calls them
- * now. */
-/* Those functions were called from the (removed) replication functionality.
- * We need to call them from somewhere periodically; main()? -KL */
 void rend_cache_clean(void);
 void rend_cache_clean(void);
-void rend_cache_clean_up(void);
-void rend_cache_clean_v2_dir(void);
+void rend_cache_clean_v2_descs_as_dir(void);
 void rend_cache_free_all(void);
 void rend_cache_free_all(void);
 int rend_valid_service_id(const char *query);
 int rend_valid_service_id(const char *query);
 int rend_cache_lookup_desc(const char *query, int version, const char **desc,
 int rend_cache_lookup_desc(const char *query, int version, const char **desc,

+ 27 - 40
src/or/rendcommon.c

@@ -22,6 +22,8 @@ rend_cmp_service_ids(const char *one, const char *two)
 /** Helper: Release the storage held by the intro key in <b>_ent</b>.
 /** Helper: Release the storage held by the intro key in <b>_ent</b>.
  */
  */
 /*XXXX020 there's also one of these in rendservice.c */
 /*XXXX020 there's also one of these in rendservice.c */
+/* Right. But the only alternative to that (which I know) would be to
+ * write it to or.h. Should I do that? -KL */
 static void
 static void
 intro_key_free(void *_ent)
 intro_key_free(void *_ent)
 {
 {
@@ -436,7 +438,6 @@ rend_encode_v2_descriptors(smartlist_t *desc_strs_out,
     /* Add signature. */
     /* Add signature. */
     strlcpy(desc_str + written, "signature\n", desc_len - written);
     strlcpy(desc_str + written, "signature\n", desc_len - written);
     written += strlen(desc_str + written);
     written += strlen(desc_str + written);
-    desc_str[written] = '\0'; /* XXXX020 strlcpy always nul-terminates. */
     if (crypto_digest(desc_digest, desc_str, written) < 0) {
     if (crypto_digest(desc_digest, desc_str, written) < 0) {
       log_warn(LD_BUG, "could not create digest.");
       log_warn(LD_BUG, "could not create digest.");
       tor_free(desc_str);
       tor_free(desc_str);
@@ -674,25 +675,26 @@ rend_cache_clean(void)
   }
   }
 }
 }
 
 
-/** Remove all old entries on v2 hidden service directories. */
+/** Remove all old v2 descriptors and those for which this hidden service
+ * directory is not responsible for any more. */
 void
 void
-rend_cache_clean_v2_dir(void)
+rend_cache_clean_v2_descs_as_dir(void)
 {
 {
   digestmap_iter_t *iter;
   digestmap_iter_t *iter;
-  const char *key;
-  void *val;
-  rend_cache_entry_t *ent;
-  time_t cutoff;
-  cutoff = time(NULL) - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
+  smartlist_t *hs_dirs = hid_serv_create_routing_table();
+  time_t cutoff = time(NULL) - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
   for (iter = digestmap_iter_init(rend_cache_v2_dir);
   for (iter = digestmap_iter_init(rend_cache_v2_dir);
        !digestmap_iter_done(iter); ) {
        !digestmap_iter_done(iter); ) {
+    const char *key;
+    void *val;
+    rend_cache_entry_t *ent;
     digestmap_iter_get(iter, &key, &val);
     digestmap_iter_get(iter, &key, &val);
     ent = val;
     ent = val;
-    if (ent->parsed->timestamp < cutoff) {
+    if (ent->parsed->timestamp < cutoff ||
+        !hid_serv_responsible_for_desc_id(key, hs_dirs)) {
       char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
       char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
       base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
       base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
-      log_info(LD_REND, "Removing descriptor with ID '%s' from cache, "
-                        "because it is too old!",
+      log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
                key_base32);
                key_base32);
       iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
       iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
       _rend_cache_entry_free(ent);
       _rend_cache_entry_free(ent);
@@ -700,6 +702,7 @@ rend_cache_clean_v2_dir(void)
       iter = digestmap_iter_next(rend_cache_v2_dir, iter);
       iter = digestmap_iter_next(rend_cache_v2_dir, iter);
     }
     }
   }
   }
+  smartlist_free(hs_dirs);
 }
 }
 
 
 /** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
 /** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
@@ -733,35 +736,6 @@ rend_id_is_in_interval(const char *a, const char *b, const char *c)
   return 1;
   return 1;
 }
 }
 
 
-/** Clean up all values for which this node as hidden service directory is
- * not responsible */
-void
-rend_cache_clean_up(void)
-{
-  digestmap_iter_t *iter;
-  smartlist_t *hs_dirs = hid_serv_create_routing_table();
-  for (iter = digestmap_iter_init(rend_cache_v2_dir);
-       !digestmap_iter_done(iter); ) {
-    const char *key;
-    void *val;
-    rend_cache_entry_t *ent;
-    digestmap_iter_get(iter, &key, &val);
-    ent = val;
-    if (!hid_serv_responsible_for_desc_id(key, hs_dirs)) {
-      char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
-      base32_encode(key_base32, sizeof(key_base32),
-                    key, DIGEST_LEN);
-      log_info(LD_REND, "Removing descriptor with ID '%s' from cache, "
-                        "because we are not reponsible for it!", key_base32);
-      iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
-      _rend_cache_entry_free(ent);
-    } else {
-      iter = digestmap_iter_next(rend_cache_v2_dir, iter);
-    }
-  }
-  smartlist_free(hs_dirs);
-}
-
 /** Return true iff <b>query</b> is a syntactically valid service ID (as
 /** Return true iff <b>query</b> is a syntactically valid service ID (as
  * generated by rend_get_service_id).  */
  * generated by rend_get_service_id).  */
 int
 int
@@ -1067,6 +1041,19 @@ rend_cache_store_v2_desc_as_client(const char *desc,
 {
 {
   /*XXXX this seems to have a bit of duplicate code with
   /*XXXX this seems to have a bit of duplicate code with
    * rend_cache_store_v2_desc_as_dir().  Fix that. */
    * rend_cache_store_v2_desc_as_dir().  Fix that. */
+  /* Though having similar elements, both functions were separated on
+   * purpose:
+   * - dirs don't care about encoded/encrypted introduction points, clients
+   *   do.
+   * - dirs store descriptors in a separate cache by descriptor ID, whereas
+   *   clients store them by service ID; both caches are different data
+   *   structures and have different access methods.
+   * - dirs store a descriptor only if they are responsible for its ID,
+   *   clients do so in every way (because they have requested it before).
+   * - dirs can process multiple concatenated descriptors which is required
+   *   for replication, whereas clients only accept a single descriptor.
+   * Thus, combining both methods would result in a lot of if statements
+   * which probably would not improve, but worsen code readability. -KL */
   rend_service_descriptor_t *parsed = NULL;
   rend_service_descriptor_t *parsed = NULL;
   char desc_id[DIGEST_LEN];
   char desc_id[DIGEST_LEN];
   char *intro_content = NULL;
   char *intro_content = NULL;

+ 8 - 2
src/or/rendservice.c

@@ -62,6 +62,11 @@ typedef struct rend_service_t {
   time_t next_upload_time;
   time_t next_upload_time;
   /* XXXX020 A service never actually has both descriptor versions; perhaps
   /* XXXX020 A service never actually has both descriptor versions; perhaps
    * this should be an int rather than in intmax. */
    * this should be an int rather than in intmax. */
+  /* A service can never publish v0 and v2 descriptors, but maybe it can
+   * publish v2 and v3 descriptors in the future. As with origin_circuit_t:
+   * Would it be clearer to switch to a single version number for now and
+   * switch back to a bitmap, when the above becomes true? -KL */
+  /* Yes. s/when/if/.  "YAGNI" -NM. */
   int descriptor_versions; /**< bitmask of rendezvous descriptor versions
   int descriptor_versions; /**< bitmask of rendezvous descriptor versions
                             * that will be published. "0" means "default." */
                             * that will be published. "0" means "default." */
 } rend_service_t;
 } rend_service_t;
@@ -138,7 +143,8 @@ add_service(rend_service_t *service)
   if (!service->intro_exclude_nodes)
   if (!service->intro_exclude_nodes)
     service->intro_exclude_nodes = tor_strdup("");
     service->intro_exclude_nodes = tor_strdup("");
   if (service->descriptor_versions == 0)
   if (service->descriptor_versions == 0)
-    service->descriptor_versions = 1; /* Default is v0 only. */
+    service->descriptor_versions = 1 + (1<<2); /**< Default is v0 and v2 in
+                                                * parallel. */
   service->intro_keys = strmap_new();
   service->intro_keys = strmap_new();
 
 
   /* If the service is configured to publish unversioned (v0) and versioned
   /* If the service is configured to publish unversioned (v0) and versioned
@@ -1210,7 +1216,7 @@ rend_services_introduce(void)
         log_info(LD_REND,"Giving up on %s as intro point for %s.",
         log_info(LD_REND,"Giving up on %s as intro point for %s.",
                  intro, service->service_id);
                  intro, service->service_id);
         tor_free(intro);
         tor_free(intro);
-        /* XXXX020 We could also remove the intro key here... */
+        /* XXXXX020 we could also remove the intro key here. */
         smartlist_del(service->intro_nodes,j--);
         smartlist_del(service->intro_nodes,j--);
         changed = 1;
         changed = 1;
         service->desc_is_dirty = now;
         service->desc_is_dirty = now;

+ 29 - 5
src/or/routerparse.c

@@ -3257,9 +3257,11 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
   tor_assert(tok);
   tor_assert(tok);
   tor_assert(tok->n_args == 1);
   tor_assert(tok->n_args == 1);
   result->version = atoi(tok->args[0]);
   result->version = atoi(tok->args[0]);
-  if (result->version < 2) { /*XXXX020 what if > 2? */
-                             /* Good question: should higher versions
-                              * be rejected by directories? -KL */
+  if (result->version != 2) {
+    /* If it's <2, it shouldn't be under this format.  If the number
+     * is greater than 2, we bumped it because we broke backward
+     * compatibility.  See how version numbers in our other formats
+     * work. */
     log_warn(LD_REND, "Wrong descriptor version: %d", result->version);
     log_warn(LD_REND, "Wrong descriptor version: %d", result->version);
     goto err;
     goto err;
   }
   }
@@ -3300,6 +3302,15 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
   for (i = 0; i < smartlist_len(versions); i++) {
   for (i = 0; i < smartlist_len(versions); i++) {
     /* XXXX020 validate the numbers here. */
     /* XXXX020 validate the numbers here. */
+    /* As above, validating these numbers on a hidden service directory
+     * might require an extension to new valid numbers at some time. But
+     * this would require making a distinction of hidden service direcoties
+     * which accept the old valid numbers and those which accept the new
+     * valid numbers. -KL */
+    /* As above, increased version numbers are for
+     * non-backward-compatible changes.  This code doesn't know how to
+     * parse a v3 descriptor, because a v3 descriptor is by definitition not 
+     * compatible with this code.  */
     version = atoi(smartlist_get(versions, i));
     version = atoi(smartlist_get(versions, i));
     result->protocols |= 1 << version;
     result->protocols |= 1 << version;
   }
   }
@@ -3308,7 +3319,11 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
   /* Parse encrypted introduction points. Don't verify. */
   /* Parse encrypted introduction points. Don't verify. */
   tok = find_first_by_keyword(tokens, R_INTRODUCTION_POINTS);
   tok = find_first_by_keyword(tokens, R_INTRODUCTION_POINTS);
   tor_assert(tok);
   tor_assert(tok);
-  /* XXXX020 make sure it's "BEGIN MESSAGE", not "BEGIN SOMETHINGELSE" */
+  if (strcmp(tok->object_type, "MESSAGE")) {
+    log_warn(LD_DIR, "Bad object type: introduction points should be of "
+             "type MESSAGE");
+    goto err;
+  }
   *intro_points_encrypted_out = tok->object_body;
   *intro_points_encrypted_out = tok->object_body;
   *intro_points_encrypted_size_out = tok->object_size;
   *intro_points_encrypted_size_out = tok->object_size;
   tok->object_body = NULL; /* Prevent free. */
   tok->object_body = NULL; /* Prevent free. */
@@ -3446,8 +3461,14 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
     info->addr = ntohl(ip.s_addr);
     info->addr = ntohl(ip.s_addr);
     /* Parse onion port. */
     /* Parse onion port. */
     tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT);
     tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT);
-    /* XXXX020 validate range. */
     info->port = (uint16_t) atoi(tok->args[0]);
     info->port = (uint16_t) atoi(tok->args[0]);
+    /* XXXX020 this next check fails with ports like 65537. */
+    if (!info->port) {
+      log_warn(LD_REND, "Introduction point onion port is out of range: %d",
+               info->port);
+      tor_free(info);
+      goto err;
+    }
     /* Parse onion key. */
     /* Parse onion key. */
     tok = find_first_by_keyword(tokens, R_IPO_ONION_KEY);
     tok = find_first_by_keyword(tokens, R_IPO_ONION_KEY);
     info->onion_key = tok->key;
     info->onion_key = tok->key;
@@ -3461,6 +3482,9 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
   }
   }
   /* Write extend infos to descriptor. */
   /* Write extend infos to descriptor. */
   /* XXXX020 what if intro_points (&tc) are already set? */
   /* XXXX020 what if intro_points (&tc) are already set? */
+  /* This function is not intended to be invoced multiple times for
+   * the same descriptor. Should this be asserted? -KL */
+  /* Yes. -NM */
   parsed->n_intro_points = smartlist_len(intropoints);
   parsed->n_intro_points = smartlist_len(intropoints);
   parsed->intro_point_extend_info =
   parsed->intro_point_extend_info =
     tor_malloc_zero(sizeof(extend_info_t *) * parsed->n_intro_points);
     tor_malloc_zero(sizeof(extend_info_t *) * parsed->n_intro_points);