mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
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.
This commit is contained in:
@@ -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:
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+93
-6
@@ -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
|
||||
|
||||
+4
-1
@@ -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,
|
||||
|
||||
+6
-6
@@ -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.",
|
||||
|
||||
Reference in New Issue
Block a user