[tor-commits] [tor/master] Create a service-side descriptor cache

nickm at torproject.org nickm at torproject.org
Fri Oct 2 11:48:21 UTC 2015


commit 1a75e6da007ddd3207726dc2b1293e22453c81af
Author: Donncha O'Cearbhaill <donncha at donncha.is>
Date:   Wed Jul 29 14:40:29 2015 +0200

    Create a service-side descriptor cache
    
    Adds a service descriptor cache which is indexed by service ID. This
    descriptor cache is used to store service descriptors generated by a
    local rendevous service.
    
    The service-side cach can be queried by calling rend_cache_lookup_entry()
    with the 'service' argument set to 1.
---
 src/or/connection_edge.c |    2 +-
 src/or/control.c         |    2 +-
 src/or/rendcache.c       |   99 +++++++++++++++++++++++++++++++++++++++++++---
 src/or/rendcache.h       |    5 ++-
 src/or/rendclient.c      |   12 +++---
 5 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 729ef8a..defe0ab 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1527,7 +1527,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
     unsigned int refetch_desc = 0;
     rend_cache_entry_t *entry = NULL;
     const int rend_cache_lookup_result =
-      rend_cache_lookup_entry(rend_data->onion_address, -1, &entry);
+      rend_cache_lookup_entry(rend_data->onion_address, -1, &entry, 0);
     if (rend_cache_lookup_result < 0) {
       switch (-rend_cache_lookup_result) {
       case EINVAL:
diff --git a/src/or/control.c b/src/or/control.c
index 220e7e5..d237f8f 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1920,7 +1920,7 @@ getinfo_helper_dir(control_connection_t *control_conn,
       return -1;
     }
 
-    if (!rend_cache_lookup_entry(question, -1, &e)) {
+    if (!rend_cache_lookup_entry(question, -1, &e, 0)) {
       /* Descriptor found in cache */
       *answer = tor_strdup(e->desc);
     } else {
diff --git a/src/or/rendcache.c b/src/or/rendcache.c
index a914722..1c46641 100644
--- a/src/or/rendcache.c
+++ b/src/or/rendcache.c
@@ -17,6 +17,9 @@
  * rend_cache_entry_t. */
 static strmap_t *rend_cache = NULL;
 
+/** Map from service id to rend_cache_entry_t; only for hidden services. */
+static strmap_t *rend_cache_service = NULL;
+
 /** Map from descriptor id to rend_cache_entry_t; only for hidden service
  * directories. */
 static digestmap_t *rend_cache_v2_dir = NULL;
@@ -58,6 +61,7 @@ rend_cache_init(void)
 {
   rend_cache = strmap_new();
   rend_cache_v2_dir = digestmap_new();
+  rend_cache_service = strmap_new();
   rend_cache_failure = strmap_new();
 }
 
@@ -465,21 +469,24 @@ rend_cache_clean_v2_descs_as_dir(time_t now, size_t force_remove)
   } while (bytes_removed < force_remove);
 }
 
-/** Lookup in the client cache the given service ID <b>query</b> for
- * <b>version</b>.
+/** Lookup in the client or service cache the given service ID <b>query</b> for
+ * <b>version</b>. The <b>service</b> argument determines if the lookup should
+ * be from the client cache or the service cache.
  *
  * Return 0 if found and if <b>e</b> is non NULL, set it with the entry
  * found. Else, a negative value is returned and <b>e</b> is untouched.
  * -EINVAL means that <b>query</b> is not a valid service id.
  * -ENOENT means that no entry in the cache was found. */
 int
-rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
+rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e,
+                        int service)
 {
   int ret = 0;
   char key[REND_SERVICE_ID_LEN_BASE32 + 2]; /* <version><query>\0 */
   rend_cache_entry_t *entry = NULL;
   static const int default_version = 2;
 
+  tor_assert(rend_cache_service);
   tor_assert(rend_cache);
   tor_assert(query);
 
@@ -495,15 +502,22 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
     case 2:
       /* Default is version 2. */
     default:
-      tor_snprintf(key, sizeof(key), "%d%s", default_version, query);
-      entry = strmap_get_lc(rend_cache, key);
+      if(service){
+        entry = strmap_get_lc(rend_cache_service, query);
+      } else {
+        tor_snprintf(key, sizeof(key), "%d%s", default_version, query);
+        entry = strmap_get_lc(rend_cache, key);
+      }
       break;
   }
   if (!entry) {
     ret = -ENOENT;
     goto end;
   }
-  tor_assert(entry->parsed && entry->parsed->intro_nodes);
+  /* Check descriptor is parsed only if lookup is from client cache */
+  if(!service){
+    tor_assert(entry->parsed && entry->parsed->intro_nodes);
+  }
 
   if (e) {
     *e = entry;
@@ -665,6 +679,79 @@ rend_cache_store_v2_desc_as_dir(const char *desc)
   return RCS_OKAY;
 }
 
+/** Parse the v2 service descriptor in <b>desc</b> and store it to the
+* local service rend cache. Don't attempt to decrypt the included list of
+* introduction points.
+*
+* If we have a newer descriptor with the same ID, ignore this one.
+* If we have an older descriptor with the same ID, replace it.
+*
+* Return an appropriate rend_cache_store_status_t.
+*/
+rend_cache_store_status_t
+rend_cache_store_v2_desc_as_service(const char *desc)
+{
+  rend_service_descriptor_t *parsed = NULL;
+  char desc_id[DIGEST_LEN];
+  char *intro_content = NULL;
+  size_t intro_size;
+  size_t encoded_size;
+  const char *next_desc;
+  char service_id[REND_SERVICE_ID_LEN_BASE32+1];
+  rend_cache_entry_t *e;
+  rend_cache_store_status_t retval = RCS_BADDESC;
+  tor_assert(rend_cache_service);
+  tor_assert(desc);
+
+  /* Parse the descriptor. */
+  if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
+                                       &intro_size, &encoded_size,
+                                       &next_desc, desc, 0) < 0) {
+    log_warn(LD_REND, "Could not parse descriptor.");
+    goto err;
+  }
+  /* Compute service ID from public key. */
+  if (rend_get_service_id(parsed->pk, service_id)<0) {
+    log_warn(LD_REND, "Couldn't compute service ID.");
+    goto err;
+  }
+  /* We don't care about the introduction points. */
+  tor_free(intro_content);
+
+  /* Do we already have a newer descriptor? Allow new descriptors with a
+     rounded timestamp equal to or newer than the current descriptor */
+  e = (rend_cache_entry_t*) strmap_get_lc(rend_cache_service, service_id);
+  if (e && e->parsed->timestamp > parsed->timestamp) {
+    log_info(LD_REND, "We already have a newer service descriptor for "
+             "service ID %s.", safe_str_client(service_id));
+    goto okay;
+  }
+  if (!e) {
+    e = tor_malloc_zero(sizeof(rend_cache_entry_t));
+    strmap_set_lc(rend_cache_service, service_id, e);
+  } else {
+    rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
+    rend_service_descriptor_free(e->parsed);
+    tor_free(e->desc);
+  }
+  e->parsed = parsed;
+  e->desc = tor_malloc_zero(encoded_size + 1);
+  strlcpy(e->desc, desc, encoded_size + 1);
+  e->len = encoded_size;
+  rend_cache_increment_allocation(rend_cache_entry_allocation(e));
+  log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
+            safe_str_client(service_id), (int)encoded_size);
+  return RCS_OKAY;
+
+ okay:
+  retval = RCS_OKAY;
+
+ err:
+  rend_service_descriptor_free(parsed);
+  tor_free(intro_content);
+  return retval;
+}
+
 /** Parse the v2 service descriptor in <b>desc</b>, decrypt the included list
  * of introduction points with <b>descriptor_cookie</b> (which may also be
  * <b>NULL</b> if decryption is not necessary), and store the descriptor to
diff --git a/src/or/rendcache.h b/src/or/rendcache.h
index 0512058..02eab4b 100644
--- a/src/or/rendcache.h
+++ b/src/or/rendcache.h
@@ -55,7 +55,8 @@ void rend_cache_clean_v2_descs_as_dir(time_t now, size_t min_to_remove);
 void rend_cache_purge(void);
 void rend_cache_free_all(void);
 int rend_cache_lookup_entry(const char *query, int version,
-                            rend_cache_entry_t **entry_out);
+                            rend_cache_entry_t **entry_out,
+                            int service);
 int rend_cache_lookup_v2_desc_as_dir(const char *query, const char **desc);
 /** Return value from rend_cache_store_v2_desc_as_{dir,client}. */
 typedef enum {
@@ -65,6 +66,8 @@ typedef enum {
 } rend_cache_store_status_t;
 
 rend_cache_store_status_t rend_cache_store_v2_desc_as_dir(const char *desc);
+rend_cache_store_status_t rend_cache_store_v2_desc_as_service(
+                                                const char *desc);
 rend_cache_store_status_t rend_cache_store_v2_desc_as_client(const char *desc,
                                                 const char *desc_id_base32,
                                                 const rend_data_t *rend_query,
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index a39e518..01ad614 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -160,7 +160,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
 #endif
 
   r = rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
-                              &entry);
+                              &entry, 0);
   /* An invalid onion address is not possible else we have a big issue. */
   tor_assert(r != -EINVAL);
   if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
@@ -906,7 +906,7 @@ rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
     return;
   }
   /* Before fetching, check if we already have a usable descriptor here. */
-  if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) == 0 &&
+  if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e, 0) == 0 &&
       rend_client_any_intro_points_usable(e)) {
     log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
                       "already have a usable descriptor here. Not fetching.");
@@ -987,7 +987,7 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro,
   rend_cache_entry_t *ent;
   connection_t *conn;
 
-  r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent);
+  r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent, 0);
   if (r < 0) {
     /* Either invalid onion address or cache entry not found. */
     switch (-r) {
@@ -1213,7 +1213,7 @@ rend_client_desc_trynow(const char *query)
       continue;
     assert_connection_ok(base_conn, now);
     if (rend_cache_lookup_entry(rend_data->onion_address, -1,
-                                &entry) == 0 &&
+                                &entry, 0) == 0 &&
         rend_client_any_intro_points_usable(entry)) {
       /* either this fetch worked, or it failed but there was a
        * valid entry from before which we should reuse */
@@ -1256,7 +1256,7 @@ rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
   if (*rend_data->onion_address != '\0') {
     /* Ignore return value; we find an entry, or we don't. */
     (void) rend_cache_lookup_entry(rend_data->onion_address, -1,
-                                   &cache_entry);
+                                   &cache_entry, 0);
     have_onion = 1;
   }
 
@@ -1295,7 +1295,7 @@ rend_client_get_random_intro(const rend_data_t *rend_query)
   extend_info_t *result;
   rend_cache_entry_t *entry;
 
-  ret = rend_cache_lookup_entry(rend_query->onion_address, -1, &entry);
+  ret = rend_cache_lookup_entry(rend_query->onion_address, -1, &entry, 0);
   if (ret < 0 || !rend_client_any_intro_points_usable(entry)) {
     log_warn(LD_REND,
              "Query '%s' didn't have valid rend desc in cache. Failing.",





More information about the tor-commits mailing list