commit 1a75e6da007ddd3207726dc2b1293e22453c81af Author: Donncha O'Cearbhaill donncha@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.",
tor-commits@lists.torproject.org