From 025610612d78fe0a0ec95dd88c3d44e4bf643603 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 29 Mar 2016 15:08:04 -0400 Subject: prop224: Directory cache support This implements the proposal 224 directory descriptor cache store and lookup functionalities. Furthermore, it merges the OOM call for the HSDir cache with current protocol v2 and the new upcoming v3. Add hs_cache.{c|h} with store/lookup API. Closes #18572 Signed-off-by: David Goulet Signed-off-by: George Kadianakis --- src/or/hs_cache.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 src/or/hs_cache.c (limited to 'src/or/hs_cache.c') diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c new file mode 100644 index 0000000000..c2e2914e5a --- /dev/null +++ b/src/or/hs_cache.c @@ -0,0 +1,364 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_cache.c + * \brief Handle hidden service descriptor caches. + **/ + +#include "hs_cache.h" + +#include "or.h" +#include "config.h" +#include "hs_common.h" +#include "hs_descriptor.h" +#include "rendcache.h" + +/* Directory descriptor cache. Map indexed by blinded key. */ +static digest256map_t *hs_cache_v3_dir; + +/* Remove a given descriptor from our cache. */ +static void +remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc) +{ + tor_assert(desc); + digest256map_remove(hs_cache_v3_dir, desc->key); +} + +/* Store a given descriptor in our cache. */ +static void +store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc) +{ + tor_assert(desc); + digest256map_set(hs_cache_v3_dir, desc->key, desc); +} + +/* Query our cache and return the entry or NULL if not found. */ +static hs_cache_dir_descriptor_t * +lookup_v3_desc_as_dir(const uint8_t *key) +{ + tor_assert(key); + return digest256map_get(hs_cache_v3_dir, key); +} + +/* Free a directory descriptor object. */ +static void +cache_dir_desc_free(hs_cache_dir_descriptor_t *desc) +{ + if (desc == NULL) { + return; + } + hs_desc_plaintext_data_free(desc->plaintext_data); + tor_free(desc->encoded_desc); + tor_free(desc); +} + +/* Create a new directory cache descriptor object from a encoded descriptor. + * On success, return the heap-allocated cache object, otherwise return NULL if + * we can't decode the descriptor. */ +static hs_cache_dir_descriptor_t * +cache_dir_desc_new(const char *desc) +{ + hs_cache_dir_descriptor_t *dir_desc; + + tor_assert(desc); + + dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t)); + dir_desc->plaintext_data = + tor_malloc_zero(sizeof(hs_desc_plaintext_data_t)); + dir_desc->encoded_desc = tor_strdup(desc); + + if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) { + log_debug(LD_DIR, "Unable to decode descriptor. Rejecting."); + goto err; + } + + /* The blinded pubkey is the indexed key. */ + dir_desc->key = dir_desc->plaintext_data->blinded_kp.pubkey.pubkey; + dir_desc->created_ts = time(NULL); + return dir_desc; + +err: + cache_dir_desc_free(dir_desc); + return NULL; +} + +/* Return the size of a cache entry in bytes. */ +static size_t +cache_get_entry_size(const hs_cache_dir_descriptor_t *entry) +{ + return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data) + + strlen(entry->encoded_desc)); +} + +/* Try to store a valid version 3 descriptor in the directory cache. Return 0 + * on success else a negative value is returned indicating that we have a + * newer version in our cache. On error, caller is responsible to free the + * given descriptor desc. */ +static int +cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc) +{ + hs_cache_dir_descriptor_t *cache_entry; + + tor_assert(desc); + + /* Verify if we have an entry in the cache for that key and if yes, check + * if we should replace it? */ + cache_entry = lookup_v3_desc_as_dir(desc->key); + if (cache_entry != NULL) { + /* Only replace descriptor if revision-counter is greater than the one + * in our cache */ + if (cache_entry->plaintext_data->revision_counter >= + desc->plaintext_data->revision_counter) { + log_info(LD_REND, "Descriptor revision counter in our cache is " + "greater or equal than the one we received. " + "Rejecting!"); + goto err; + } + /* We now know that the descriptor we just received is a new one so + * remove the entry we currently have from our cache so we can then + * store the new one. */ + remove_v3_desc_as_dir(cache_entry); + cache_dir_desc_free(cache_entry); + rend_cache_decrement_allocation(cache_get_entry_size(cache_entry)); + } + /* Store the descriptor we just got. We are sure here that either we + * don't have the entry or we have a newer descriptor and the old one + * has been removed from the cache. */ + store_v3_desc_as_dir(desc); + + /* Update our total cache size with this entry for the OOM. This uses the + * old HS protocol cache subsystem for which we are tied with. */ + rend_cache_increment_allocation(cache_get_entry_size(desc)); + + /* XXX: Update HS statistics. We should have specific stats for v3. */ + + return 0; + + err: + return -1; +} + +/* Using the query which is the blinded key for a descriptor version 3, lookup + * in our directory cache the entry. If found, 1 is returned and desc_out is + * populated with a newly allocated string being the encoded descriptor. If + * not found, 0 is returned and desc_out is untouched. On error, a negative + * value is returned and desc_out is untouched. */ +static int +cache_lookup_v3_as_dir(const char *query, char **desc_out) +{ + int found = 0; + ed25519_public_key_t blinded_key; + const hs_cache_dir_descriptor_t *entry; + + tor_assert(query); + + /* Decode blinded key using the given query value. */ + if (ed25519_public_from_base64(&blinded_key, query) < 0) { + log_info(LD_REND, "Unable to decode the v3 HSDir query %s.", + safe_str_client(query)); + goto err; + } + + entry = lookup_v3_desc_as_dir(blinded_key.pubkey); + if (entry != NULL) { + found = 1; + if (desc_out) { + *desc_out = tor_strdup(entry->encoded_desc); + } + } + + return found; + +err: + return -1; +} + +/* Clean the v3 cache by removing any entry that has expired using the + * global_cutoff value. If global_cutoff is 0, the cleaning + * process will use the lifetime found in the plaintext data section. Return + * the number of bytes cleaned. */ +static size_t +cache_clean_v3_as_dir(time_t now, time_t global_cutoff) +{ + size_t bytes_removed = 0; + + /* Code flow error if this ever happens. */ + tor_assert(global_cutoff >= 0); + + if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */ + return 0; + } + + DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key, + hs_cache_dir_descriptor_t *, entry) { + size_t entry_size; + time_t cutoff = global_cutoff; + if (!cutoff) { + /* Cutoff is the lifetime of the entry found in the descriptor. */ + cutoff = now - entry->plaintext_data->lifetime_sec; + } + + /* If the entry has been created _after_ the cutoff, not expired so + * continue to the next entry in our v3 cache. */ + if (entry->created_ts > cutoff) { + continue; + } + /* Here, our entry has expired, remove and free. */ + MAP_DEL_CURRENT(key); + entry_size = cache_get_entry_size(entry); + bytes_removed += entry_size; + /* Entry is not in the cache anymore, destroy it. */ + cache_dir_desc_free(entry); + /* Update our cache entry allocation size for the OOM. */ + rend_cache_decrement_allocation(entry_size); + /* Logging. */ + { + char key_b64[BASE64_DIGEST256_LEN + 1]; + base64_encode(key_b64, sizeof(key_b64), (const char *) key, + DIGEST256_LEN, 0); + log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache", + safe_str_client(key_b64)); + } + } DIGEST256MAP_FOREACH_END; + + return bytes_removed; +} + +/* Given an encoded descriptor, store it in the directory cache depending on + * which version it is. Return a negative value on error. On success, 0 is + * returned. */ +int +hs_cache_store_as_dir(const char *desc) +{ + hs_cache_dir_descriptor_t *dir_desc = NULL; + + tor_assert(desc); + + /* Create a new cache object. This can fail if the descriptor plaintext data + * is unparseable which in this case a log message will be triggered. */ + dir_desc = cache_dir_desc_new(desc); + if (dir_desc == NULL) { + goto err; + } + + /* Call the right function against the descriptor version. At this point, + * we are sure that the descriptor's version is supported else the + * decoding would have failed. */ + switch (dir_desc->plaintext_data->version) { + case 3: + default: + if (cache_store_v3_as_dir(dir_desc) < 0) { + goto err; + } + break; + } + return 0; + + err: + cache_dir_desc_free(dir_desc); + return -1; +} + +/* Using the query, lookup in our directory cache the entry. If found, 1 is + * returned and desc_out is populated with a newly allocated string being + * the encoded descriptor. If not found, 0 is returned and desc_out is + * untouched. On error, a negative value is returned and desc_out is + * untouched. */ +int +hs_cache_lookup_as_dir(uint32_t version, const char *query, + char **desc_out) +{ + int found; + + tor_assert(query); + /* This should never be called with an unsupported version. */ + tor_assert(hs_desc_is_supported_version(version)); + + switch (version) { + case 3: + default: + found = cache_lookup_v3_as_dir(query, desc_out); + break; + } + + return found; +} + +/* Clean all directory caches using the current time now. */ +void +hs_cache_clean_as_dir(time_t now) +{ + time_t cutoff; + + /* Start with v2 cache cleaning. */ + cutoff = now - rend_cache_max_entry_lifetime(); + rend_cache_clean_v2_descs_as_dir(cutoff); + + /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function + * to compute the cutoff by itself using the lifetime value. */ + cache_clean_v3_as_dir(now, 0); +} + +/* Do a round of OOM cleanup on all directory caches. Return the amount of + * removed bytes. It is possible that the returned value is lower than + * min_remove_bytes if the caches get emptied out so the caller should be + * aware of this. */ +size_t +hs_cache_handle_oom(time_t now, size_t min_remove_bytes) +{ + time_t k; + size_t bytes_removed = 0; + + /* Our OOM handler called with 0 bytes to remove is a code flow error. */ + tor_assert(min_remove_bytes != 0); + + /* The algorithm is as follow. K is the oldest expected descriptor age. + * + * 1) Deallocate all entries from v2 cache that are older than K hours. + * 1.1) If the amount of remove bytes has been reached, stop. + * 2) Deallocate all entries from v3 cache that are older than K hours + * 2.1) If the amount of remove bytes has been reached, stop. + * 3) Set K = K - RendPostPeriod and repeat process until K is < 0. + * + * This ends up being O(Kn). + */ + + /* Set K to the oldest expected age in seconds which is the maximum + * lifetime of a cache entry. We'll use the v2 lifetime because it's much + * bigger than the v3 thus leading to cleaning older descriptors. */ + k = rend_cache_max_entry_lifetime(); + + do { + time_t cutoff; + + /* If K becomes negative, it means we've empty the caches so stop and + * return what we were able to cleanup. */ + if (k < 0) { + break; + } + /* Compute a cutoff value with K and the current time. */ + cutoff = now - k; + + /* Start by cleaning the v2 cache with that cutoff. */ + bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff); + + if (bytes_removed < min_remove_bytes) { + /* We haven't remove enough bytes so clean v3 cache. */ + bytes_removed += cache_clean_v3_as_dir(now, cutoff); + /* Decrement K by a post period to shorten the cutoff. */ + k -= get_options()->RendPostPeriod; + } + } while (bytes_removed < min_remove_bytes); + + return bytes_removed; +} + +/* Initialize the hidden service cache subsystem. */ +void +hs_cache_init(void) +{ + /* Calling this twice is very wrong code flow. */ + tor_assert(!hs_cache_v3_dir); + hs_cache_v3_dir = digest256map_new(); +} -- cgit v1.2.3-54-g00ecf From 1aeaba4906d9f0d8901f3ef928f2cbcd049f1140 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 10 Aug 2016 16:40:06 -0400 Subject: test: Add prop224 directory cache unit tests Signed-off-by: David Goulet Signed-off-by: George Kadianakis --- src/or/hs_cache.c | 5 +- src/or/hs_cache.h | 6 + src/test/include.am | 1 + src/test/test.c | 1 + src/test/test.h | 1 + src/test/test_hs_cache.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 src/test/test_hs_cache.c (limited to 'src/or/hs_cache.c') diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index c2e2914e5a..40730bd435 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -6,6 +6,9 @@ * \brief Handle hidden service descriptor caches. **/ +/* For unit tests.*/ +#define HS_CACHE_PRIVATE + #include "hs_cache.h" #include "or.h" @@ -178,7 +181,7 @@ err: * global_cutoff value. If global_cutoff is 0, the cleaning * process will use the lifetime found in the plaintext data section. Return * the number of bytes cleaned. */ -static size_t +STATIC size_t cache_clean_v3_as_dir(time_t now, time_t global_cutoff) { size_t bytes_removed = 0; diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h index 3432d61b14..f0573175d3 100644 --- a/src/or/hs_cache.h +++ b/src/or/hs_cache.h @@ -50,4 +50,10 @@ int hs_cache_store_as_dir(const char *desc); int hs_cache_lookup_as_dir(uint32_t version, const char *query, char **desc_out); +#ifdef HS_CACHE_PRIVATE + +STATIC size_t cache_clean_v3_as_dir(time_t now, time_t global_cutoff); + +#endif /* HS_CACHE_PRIVATE */ + #endif /* TOR_HS_CACHE_H */ diff --git a/src/test/include.am b/src/test/include.am index 79e4239c34..f3d0015499 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -96,6 +96,7 @@ src_test_test_SOURCES = \ src/test/test_extorport.c \ src/test/test_hs.c \ src/test/test_handles.c \ + src/test/test_hs_cache.c \ src/test/test_hs_descriptor.c \ src/test/test_introduce.c \ src/test/test_keypin.c \ diff --git a/src/test/test.c b/src/test/test.c index a81fbc88db..2d3f07e03c 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1205,6 +1205,7 @@ struct testgroup_t testgroups[] = { { "guardfraction/", guardfraction_tests }, { "extorport/", extorport_tests }, { "hs/", hs_tests }, + { "hs_cache/", hs_cache }, { "hs_descriptor/", hs_descriptor }, { "introduce/", introduce_tests }, { "keypin/", keypin_tests }, diff --git a/src/test/test.h b/src/test/test.h index 98b85b31da..764b8b638c 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -195,6 +195,7 @@ extern struct testcase_t entrynodes_tests[]; extern struct testcase_t guardfraction_tests[]; extern struct testcase_t extorport_tests[]; extern struct testcase_t hs_tests[]; +extern struct testcase_t hs_cache[]; extern struct testcase_t hs_descriptor[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t keypin_tests[]; diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c new file mode 100644 index 0000000000..ee202254e6 --- /dev/null +++ b/src/test/test_hs_cache.c @@ -0,0 +1,293 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_cache.c + * \brief Test hidden service caches. + */ + +#define HS_CACHE_PRIVATE + +#include "ed25519_cert.h" +#include "hs_cache.h" +#include "rendcache.h" +#include "test.h" + +/* Build an intro point using a blinded key and an address. */ +static hs_desc_intro_point_t * +helper_build_intro_point(const ed25519_keypair_t *blinded_kp, + const char *addr) +{ + int ret; + ed25519_keypair_t auth_kp; + hs_desc_intro_point_t *intro_point = NULL; + hs_desc_intro_point_t *ip = tor_malloc_zero(sizeof(*ip)); + ip->link_specifiers = smartlist_new(); + + { + hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls)); + ls->u.ap.port = 9001; + int family = tor_addr_parse(&ls->u.ap.addr, addr); + switch (family) { + case AF_INET: + ls->type = LS_IPV4; + break; + case AF_INET6: + ls->type = LS_IPV6; + break; + default: + /* Stop the test, not suppose to have an error. */ + tt_int_op(family, OP_EQ, AF_INET); + } + smartlist_add(ip->link_specifiers, ls); + } + + ret = ed25519_keypair_generate(&auth_kp, 0); + tt_int_op(ret, ==, 0); + ip->auth_key_cert = tor_cert_create(blinded_kp, CERT_TYPE_HS_IP_AUTH, + &auth_kp.pubkey, time(NULL), + HS_DESC_CERT_LIFETIME, + CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(ip->auth_key_cert); + + ret = curve25519_keypair_generate(&ip->enc_key.curve25519, 0); + tt_int_op(ret, ==, 0); + ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519; + intro_point = ip; +done: + return intro_point; +} + +/* Return a valid hs_descriptor_t object. */ +static hs_descriptor_t * +helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime, + ed25519_keypair_t *blinded_kp) +{ + int ret; + hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc)); + + desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX; + ret = ed25519_keypair_generate(&desc->plaintext_data.signing_kp, 0); + tt_int_op(ret, ==, 0); + if (blinded_kp) { + memcpy(&desc->plaintext_data.blinded_kp, blinded_kp, + sizeof(ed25519_keypair_t)); + } else { + ret = ed25519_keypair_generate(&desc->plaintext_data.blinded_kp, 0); + tt_int_op(ret, ==, 0); + } + + desc->plaintext_data.signing_key_cert = + tor_cert_create(&desc->plaintext_data.blinded_kp, + CERT_TYPE_HS_DESC_SIGN, + &desc->plaintext_data.signing_kp.pubkey, time(NULL), + 3600, CERT_FLAG_INCLUDE_SIGNING_KEY); + tt_assert(desc->plaintext_data.signing_key_cert); + desc->plaintext_data.revision_counter = revision_counter; + desc->plaintext_data.lifetime_sec = lifetime; + + /* Setup encrypted data section. */ + desc->encrypted_data.create2_ntor = 1; + desc->encrypted_data.auth_types = smartlist_new(); + smartlist_add(desc->encrypted_data.auth_types, strdup("ed25519")); + desc->encrypted_data.intro_points = smartlist_new(); + /* Add an intro point. */ + smartlist_add(desc->encrypted_data.intro_points, + helper_build_intro_point(&desc->plaintext_data.blinded_kp, + "1.2.3.4")); + + descp = desc; +done: + return descp; +} + +/* Static variable used to encoded the HSDir query. */ +static char query_b64[256]; + +/* Build an HSDir query using a ed25519 keypair. */ +static const char * +helper_get_hsdir_query(const hs_descriptor_t *desc) +{ + ed25519_public_to_base64(query_b64, + &desc->plaintext_data.blinded_kp.pubkey); + return query_b64; +} + +static void +init_test(void) +{ + /* Always needed. Initialize the subsystem. */ + hs_cache_init(); + /* We need the v2 cache since our OOM and cache cleanup does poke at it. */ + rend_cache_init(); +} + +static void +test_directory(void *arg) +{ + int ret; + size_t oom_size; + char *desc_out, *desc1_str; + hs_descriptor_t *desc1; + + (void) arg; + + init_test(); + /* Generate a valid descriptor with normal values. */ + desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* Very first basic test, should be able to be stored, survive a + * clean, found with a lookup and then cleaned by our OOM. */ + { + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + /* Re-add, it should fail since we already have it. */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, -1); + /* Try to clean now which should be fine, there is at worst few seconds + * between the store and this call. */ + hs_cache_clean_as_dir(time(NULL)); + /* We should find it in our cache. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); + tt_int_op(ret, OP_EQ, 1); + tt_str_op(desc_out, OP_EQ, desc1_str); + tor_free(desc_out); + /* Tell our OOM to run and to at least remove a byte which will result in + * removing the descriptor from our cache. */ + oom_size = hs_cache_handle_oom(time(NULL), 1); + tt_int_op(oom_size, >=, 1); + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL); + tt_int_op(ret, OP_EQ, 0); + } + + /* Store two descriptors and remove the expiring one only. */ + { + hs_descriptor_t *desc_zero_lifetime = helper_build_hs_desc(1, 0, NULL); + tt_assert(desc_zero_lifetime); + char *desc_zero_lifetime_str; + ret = hs_desc_encode_descriptor(desc_zero_lifetime, + &desc_zero_lifetime_str); + tt_int_op(ret, OP_EQ, 0); + + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc_zero_lifetime_str); + tt_int_op(ret, OP_EQ, 0); + /* This one should clear out our zero lifetime desc. */ + hs_cache_clean_as_dir(time(NULL)); + /* We should find desc1 in our cache. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); + tt_int_op(ret, OP_EQ, 1); + tt_str_op(desc_out, OP_EQ, desc1_str); + tor_free(desc_out); + /* We should NOT find our zero lifetime desc in our cache. */ + ret = hs_cache_lookup_as_dir(3, + helper_get_hsdir_query(desc_zero_lifetime), + NULL); + tt_int_op(ret, OP_EQ, 0); + /* Cleanup our entire cache. */ + oom_size = hs_cache_handle_oom(time(NULL), 1); + tt_int_op(oom_size, >=, 1); + } + + /* Throw junk at it. */ + { + ret = hs_cache_store_as_dir("blah"); + tt_int_op(ret, OP_EQ, -1); + /* Poor attempt at tricking the decoding. */ + ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK"); + tt_int_op(ret, OP_EQ, -1); + /* Undecodable base64 query. */ + ret = hs_cache_lookup_as_dir(3, "blah", NULL); + tt_int_op(ret, OP_EQ, -1); + /* Decodable base64 query but wrong ed25519 size. */ + ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL); + tt_int_op(ret, OP_EQ, -1); + } + + /* Test descriptor replacement with revision counter. */ + { + char *new_desc_str; + + /* Add a descriptor. */ + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); + tt_int_op(ret, OP_EQ, 1); + tor_free(desc_out); + /* Bump revision counter. */ + desc1->plaintext_data.revision_counter++; + ret = hs_desc_encode_descriptor(desc1, &new_desc_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(new_desc_str); + tt_int_op(ret, OP_EQ, 0); + /* Look it up, it should have been replaced. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); + tt_int_op(ret, OP_EQ, 1); + tt_str_op(desc_out, OP_EQ, new_desc_str); + tor_free(desc_out); + tor_free(new_desc_str); + } + + done: + ; +} + +static void +test_clean_as_dir(void *arg) +{ + size_t ret; + char *desc1_str = NULL; + time_t now = time(NULL); + hs_descriptor_t *desc1 = NULL; + + (void) arg; + + init_test(); + + /* Generate a valid descriptor with values. */ + desc1 = helper_build_hs_desc(42, 3 * 60 * 60, NULL); + tt_assert(desc1); + ret = hs_desc_encode_descriptor(desc1, &desc1_str); + tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); + + /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */ + ret = cache_clean_v3_as_dir(now, 0); + tt_int_op(ret, ==, 0); + /* Should be present after clean up. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL); + tt_int_op(ret, OP_EQ, 1); + /* Set a cutoff 100 seconds in the past. It should not remove the entry + * since the entry is still recent enough. */ + ret = cache_clean_v3_as_dir(now, now - 100); + tt_int_op(ret, ==, 0); + /* Should be present after clean up. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL); + tt_int_op(ret, OP_EQ, 1); + /* Set a cutoff of 100 seconds in the future. It should remove the entry + * that we've just added since it's not too old for the cutoff. */ + ret = cache_clean_v3_as_dir(now, now + 100); + tt_int_op(ret, >, 0); + /* Shouldn't be present after clean up. */ + ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL); + tt_int_op(ret, OP_EQ, 0); + + done: + hs_descriptor_free(desc1); + tor_free(desc1_str); +} + +struct testcase_t hs_cache[] = { + /* Encoding tests. */ + { "directory", test_directory, TT_FORK, + NULL, NULL }, + { "clean_as_dir", test_clean_as_dir, TT_FORK, + NULL, NULL }, + + END_OF_TESTCASES +}; -- cgit v1.2.3-54-g00ecf From 45a72356cbf085f02d92edcbd9f5a3ed129216cc Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 11 Aug 2016 15:21:54 -0400 Subject: prop224: Directory support for v3 descriptor publishing Closes #19205 Signed-off-by: David Goulet Signed-off-by: George Kadianakis --- src/or/directory.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/or/directory.h | 3 ++ src/or/hs_cache.c | 4 +-- src/or/hs_common.h | 2 ++ src/test/test_dir.c | 62 +++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 2 deletions(-) (limited to 'src/or/hs_cache.c') diff --git a/src/or/directory.c b/src/or/directory.c index 49efeefbc9..8abdc454e8 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -16,6 +16,7 @@ #include "dirvote.h" #include "entrynodes.h" #include "geoip.h" +#include "hs_cache.h" #include "hs_common.h" #include "main.h" #include "microdesc.h" @@ -3443,6 +3444,90 @@ handle_get_robots(dir_connection_t *conn, const get_handler_args_t *args) return 0; } +/* Given the url from a POST request, try to extract the version number + * using the provided prefix. The version should be after the prefix and + * ending with the seperator "/". For instance: + * /tor/hs/3/publish + * + * On success, end_pos points to the position right after the version + * was found. On error, it is set to NULL. + * + * Return version on success else negative value. */ +STATIC int +parse_hs_version_from_post(const char *url, const char *prefix, + const char **end_pos) +{ + int ok; + unsigned long version; + const char *start; + char *end = NULL; + + tor_assert(url); + tor_assert(prefix); + tor_assert(end_pos); + + /* Check if the prefix does start the url. */ + if (strcmpstart(url, prefix)) { + goto err; + } + /* Move pointer to the end of the prefix string. */ + start = url + strlen(prefix); + /* Try this to be the HS version and if we are still at the separator, next + * will be move to the right value. */ + version = tor_parse_long(start, 10, 0, INT_MAX, &ok, &end); + if (!ok) { + goto err; + } + + *end_pos = end; + return (int) version; + err: + *end_pos = NULL; + return -1; +} + +/* Handle the POST request for a hidden service descripror. The request is in + * url, the body of the request is in body. Return 200 on success + * else return 400 indicating a bad request. */ +static int +handle_post_hs_descriptor(const char *url, const char *body) +{ + int version; + const char *end_pos; + + tor_assert(url); + tor_assert(body); + + version = parse_hs_version_from_post(url, "/tor/hs/", &end_pos); + if (version < 0) { + goto err; + } + + /* We have a valid version number, now make sure it's a publish request. Use + * the end position just after the version and check for the command. */ + if (strcmpstart(end_pos, "/publish")) { + goto err; + } + + switch (version) { + case HS_VERSION_THREE: + if (hs_cache_store_as_dir(body) < 0) { + goto err; + } + log_info(LD_REND, "Publish request for HS descriptor handled " + "successfully."); + break; + default: + /* Unsupported version, return a bad request. */ + goto err; + } + + return 200; + err: + /* Bad request. */ + return 400; +} + /** Helper function: called when a dirserver gets a complete HTTP POST * request. Look for an uploaded server descriptor or rendezvous * service descriptor. On finding one, process it and write a @@ -3487,6 +3572,20 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers, goto done; } + /* Handle HS descriptor publish request. */ + /* XXX: This should be disabled with a consensus param until we want to + * the prop224 be deployed and thus use. */ + if (connection_dir_is_encrypted(conn) && !strcmpstart(url, "/tor/hs/")) { + const char *msg = "HS descriptor stored successfully."; + /* We most probably have a publish request for an HS descriptor. */ + int code = handle_post_hs_descriptor(url, body); + if (code != 200) { + msg = "Invalid HS descriptor. Rejected."; + } + write_http_status_line(conn, code, msg); + goto done; + } + if (!authdir_mode(options)) { /* we just provide cached directories; we don't want to * receive anything. */ diff --git a/src/or/directory.h b/src/or/directory.h index f04e7ab315..a6c33d7f39 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -160,6 +160,9 @@ STATIC void find_dl_min_and_max_delay(download_status_t *dls, int *min, int *max); STATIC int next_random_exponential_delay(int delay, int max_delay); +STATIC int parse_hs_version_from_post(const char *url, const char *prefix, + const char **end_pos); + #endif #endif diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index 40730bd435..9b68045e89 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -249,7 +249,7 @@ hs_cache_store_as_dir(const char *desc) * we are sure that the descriptor's version is supported else the * decoding would have failed. */ switch (dir_desc->plaintext_data->version) { - case 3: + case HS_VERSION_THREE: default: if (cache_store_v3_as_dir(dir_desc) < 0) { goto err; @@ -279,7 +279,7 @@ hs_cache_lookup_as_dir(uint32_t version, const char *query, tor_assert(hs_desc_is_supported_version(version)); switch (version) { - case 3: + case HS_VERSION_THREE: default: found = cache_lookup_v3_as_dir(query, desc_out); break; diff --git a/src/or/hs_common.h b/src/or/hs_common.h index a3edf618a7..824e5405f2 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -14,6 +14,8 @@ /* Protocol version 2. Use this instead of hardcoding "2" in the code base, * this adds a clearer semantic to the value when used. */ #define HS_VERSION_TWO 2 +/* Version 3 of the protocol (prop224). */ +#define HS_VERSION_THREE 3 void rend_data_free(rend_data_t *data); rend_data_t *rend_data_dup(const rend_data_t *data); diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 51a5ecad76..4a2538b5dc 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -5345,6 +5345,67 @@ test_dir_find_dl_schedule(void* data) mock_options = NULL; } +static void +test_dir_post_parsing(void *arg) +{ + (void) arg; + + /* Test the version parsing from an HS descriptor publish request. */ + { + const char *end; + const char *prefix = "/tor/hs/"; + int version = parse_hs_version_from_post("/tor/hs//publish", prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + version = parse_hs_version_from_post("/tor/hs/a/publish", prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + version = parse_hs_version_from_post("/tor/hs/3/publish", prefix, &end); + tt_int_op(version, OP_EQ, 3); + tt_str_op(end, OP_EQ, "/publish"); + version = parse_hs_version_from_post("/tor/hs/42/publish", prefix, &end); + tt_int_op(version, OP_EQ, 42); + tt_str_op(end, OP_EQ, "/publish"); + version = parse_hs_version_from_post("/tor/hs/18163/publish", prefix, &end); + tt_int_op(version, OP_EQ, 18163); + tt_str_op(end, OP_EQ, "/publish"); + version = parse_hs_version_from_post("JUNKJUNKJUNK", prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + version = parse_hs_version_from_post("/tor/hs/3/publish", "blah", &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + /* Missing the '/' at the end of the prefix. */ + version = parse_hs_version_from_post("/tor/hs/3/publish", "/tor/hs", &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + version = parse_hs_version_from_post("/random/blah/tor/hs/3/publish", + prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + version = parse_hs_version_from_post("/tor/hs/3/publish/random/junk", + prefix, &end); + tt_int_op(version, OP_EQ, 3); + tt_str_op(end, OP_EQ, "/publish/random/junk"); + version = parse_hs_version_from_post("/tor/hs/-1/publish", prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + /* INT_MAX */ + version = parse_hs_version_from_post("/tor/hs/2147483647/publish", + prefix, &end); + tt_int_op(version, OP_EQ, INT_MAX); + tt_str_op(end, OP_EQ, "/publish"); + /* INT_MAX + 1*/ + version = parse_hs_version_from_post("/tor/hs/2147483648/publish", + prefix, &end); + tt_int_op(version, OP_EQ, -1); + tt_ptr_op(end, OP_EQ, NULL); + } + + done: + ; +} + #define DIR_LEGACY(name) \ { #name, test_dir_ ## name , TT_FORK, NULL, NULL } @@ -5378,6 +5439,7 @@ struct testcase_t dir_tests[] = { DIR(fmt_control_ns, 0), DIR(dirserv_set_routerstatus_testing, 0), DIR(http_handling, 0), + DIR(post_parsing, 0), DIR(purpose_needs_anonymity, 0), DIR(fetch_type, 0), DIR(packages, 0), -- cgit v1.2.3-54-g00ecf From d795ed5871010b8ad6d216f5f4381e4191cb147c Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 25 Aug 2016 01:44:34 +0300 Subject: Make check-spaces happy :) Signed-off-by: David Goulet Signed-off-by: George Kadianakis --- src/or/directory.c | 8 ++++---- src/or/hs_cache.c | 5 +++-- src/or/hs_cache.h | 1 + src/or/hs_common.c | 3 ++- src/or/hs_common.h | 1 + src/or/hs_descriptor.c | 24 +++++++++++++----------- src/or/hs_descriptor.h | 1 + src/or/parsecommon.c | 5 +---- src/or/parsecommon.h | 2 +- src/or/rendclient.c | 2 +- src/or/rendcommon.c | 1 + src/test/test_hs.c | 3 ++- src/test/test_hs_cache.c | 8 ++++---- src/test/test_hs_descriptor.c | 17 ++++++++++------- 14 files changed, 45 insertions(+), 36 deletions(-) (limited to 'src/or/hs_cache.c') diff --git a/src/or/directory.c b/src/or/directory.c index 8afb241520..29022fab4f 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -2350,10 +2350,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn) conn->identity_digest, \ reason) ) #define SEND_HS_DESC_FAILED_CONTENT() ( \ - control_event_hs_descriptor_content(rend_data_get_address(conn->rend_data), \ - conn->requested_resource, \ - conn->identity_digest, \ - NULL) ) + control_event_hs_descriptor_content(rend_data_get_address(conn->rend_data), \ + conn->requested_resource, \ + conn->identity_digest, \ + NULL) ) tor_assert(conn->rend_data); log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d " "(%s))", diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index 9b68045e89..6d33201469 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -81,7 +81,7 @@ cache_dir_desc_new(const char *desc) dir_desc->created_ts = time(NULL); return dir_desc; -err: + err: cache_dir_desc_free(dir_desc); return NULL; } @@ -173,7 +173,7 @@ cache_lookup_v3_as_dir(const char *query, char **desc_out) return found; -err: + err: return -1; } @@ -365,3 +365,4 @@ hs_cache_init(void) tor_assert(!hs_cache_v3_dir); hs_cache_v3_dir = digest256map_new(); } + diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h index f0573175d3..466c33db09 100644 --- a/src/or/hs_cache.h +++ b/src/or/hs_cache.h @@ -57,3 +57,4 @@ STATIC size_t cache_clean_v3_as_dir(time_t now, time_t global_cutoff); #endif /* HS_CACHE_PRIVATE */ #endif /* TOR_HS_CACHE_H */ + diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 2166005e71..c78af531a7 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -127,7 +127,7 @@ compute_desc_id(rend_data_t *rend_data) tor_assert(0); } -end: + end: return ret; } @@ -262,3 +262,4 @@ rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out) tor_assert(0); } } + diff --git a/src/or/hs_common.h b/src/or/hs_common.h index 824e5405f2..1d3a15df5a 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -34,3 +34,4 @@ const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data, size_t *len_out); #endif /* TOR_HS_COMMON_H */ + diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c index 9714d52f8c..a87a8605ec 100644 --- a/src/or/hs_descriptor.c +++ b/src/or/hs_descriptor.c @@ -167,7 +167,7 @@ encode_cert(const tor_cert_t *cert, char **cert_str_out) /* Success! */ ret = 0; -err: + err: tor_free(ed_cert_b64); return ret; } @@ -821,7 +821,7 @@ desc_encode_v3(const hs_descriptor_t *desc, char **encoded_out) /* Success! */ ret = 0; -err: + err: SMARTLIST_FOREACH(lines, char *, l, tor_free(l)); smartlist_free(lines); return ret; @@ -1177,14 +1177,14 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) *decrypted_out = (char *) decrypted; goto done; -err: + err: if (decrypted) { tor_free(decrypted); } *decrypted_out = NULL; result_len = 0; -done: + done: memwipe(secret_key, 0, sizeof(secret_key)); memwipe(secret_iv, 0, sizeof(secret_iv)); return result_len; @@ -1326,9 +1326,9 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start) return ip; } -/* Given a descriptor string at data, decode all possible introduction points - * that we can find. Add the introduction point object to desc_enc as we find - * them. Return 0 on success. +/* Given a descriptor string at data, decode all possible introduction + * points that we can find. Add the introduction point object to desc_enc as we + * find them. Return 0 on success. * * On error, a negative value is returned. It is possible that some intro * point object have been added to the desc_enc, they should be considered @@ -1455,7 +1455,7 @@ desc_sig_is_valid(const char *b64_sig, const ed25519_keypair_t *signing_kp, /* Valid signature! All is good. */ ret = 1; -err: + err: return ret; } @@ -1557,7 +1557,8 @@ desc_decode_plaintext_v3(smartlist_t *tokens, } return 0; -err: + + err: return -1; } @@ -1778,7 +1779,7 @@ hs_desc_decode_plaintext(const char *encoded, /* Success. Descriptor has been populated with the data. */ ret = 0; -err: + err: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); @@ -1885,7 +1886,7 @@ hs_desc_encode_descriptor(const hs_descriptor_t *desc, char **encoded_out) return 0; -err: + err: *encoded_out = NULL; return ret; } @@ -1930,3 +1931,4 @@ hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data) return (sizeof(*data) + sizeof(*data->signing_key_cert) + data->encrypted_blob_size); } + diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h index 1213597984..b48079e219 100644 --- a/src/or/hs_descriptor.h +++ b/src/or/hs_descriptor.h @@ -235,3 +235,4 @@ STATIC int desc_sig_is_valid(const char *b64_sig, #endif /* HS_DESCRIPTOR_PRIVATE */ #endif /* TOR_HS_DESCRIPTOR_H */ + diff --git a/src/or/parsecommon.c b/src/or/parsecommon.c index 72e69e8ea3..6622d7d671 100644 --- a/src/or/parsecommon.c +++ b/src/or/parsecommon.c @@ -146,7 +146,6 @@ tokenize_string(memarea_t *area, return 0; } - /** Helper: parse space-separated arguments from the string s ending at * eol, and store them in the args field of tok. Store the * number of parsed elements into the n_args field of tok. Allocate @@ -243,8 +242,6 @@ token_check_object(memarea_t *area, const char *kwd, return tok; } - - /** Helper function: read the next token from *s, advance *s to the end of the * token, and return the parsed token. Parse *s according to the list * of tokens in table. @@ -408,7 +405,6 @@ get_next_token(memarea_t *area, #undef STRNDUP } - /** Find the first token in s whose keyword is keyword; fail * with an assert if no such keyword is found. */ @@ -451,3 +447,4 @@ find_all_by_keyword(smartlist_t *s, directory_keyword k) }); return out; } + diff --git a/src/or/parsecommon.h b/src/or/parsecommon.h index f87e62de98..be7cba47d1 100644 --- a/src/or/parsecommon.h +++ b/src/or/parsecommon.h @@ -6,7 +6,6 @@ * \brief Header file for parsecommon.c **/ - #ifndef TOR_PARSECOMMON_H #define TOR_PARSECOMMON_H @@ -304,3 +303,4 @@ directory_token_t *find_opt_by_keyword(smartlist_t *s, smartlist_t * find_all_by_keyword(smartlist_t *s, directory_keyword k); #endif /* TOR_PARSECOMMON_H */ + diff --git a/src/or/rendclient.c b/src/or/rendclient.c index ad47ca6242..0bfc1a1805 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -151,7 +151,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, tor_assert(introcirc->rend_data); tor_assert(rendcirc->rend_data); tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data), - rend_data_get_address(rendcirc->rend_data))); + rend_data_get_address(rendcirc->rend_data))); #ifndef NON_ANONYMOUS_MODE_ENABLED tor_assert(!(introcirc->build_state->onehop_tunnel)); tor_assert(!(rendcirc->build_state->onehop_tunnel)); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index e6a7bbc28c..125aa0f5ef 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -978,3 +978,4 @@ rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, match: return 1; } + diff --git a/src/test/test_hs.c b/src/test/test_hs.c index a09e99ffc0..3bf4e6db98 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -350,7 +350,8 @@ test_hs_rend_data(void *arg) tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address); tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch, sizeof(client_dup_v2->desc_id_fetch)); - tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ, client_v2->descriptor_cookie, + tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ, + client_v2->descriptor_cookie, sizeof(client_dup_v2->descriptor_cookie)); tt_assert(client_dup->hsdirs_fp); diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index ab4d2b94de..33887aedd9 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -58,7 +58,7 @@ helper_build_intro_point(const ed25519_keypair_t *blinded_kp, tt_int_op(ret, ==, 0); ip->enc_key_type = HS_DESC_KEY_TYPE_CURVE25519; intro_point = ip; -done: + done: return intro_point; } @@ -101,7 +101,7 @@ helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime, "1.2.3.4")); descp = desc; -done: + done: return descp; } @@ -257,8 +257,8 @@ test_clean_as_dir(void *arg) tt_assert(desc1); ret = hs_desc_encode_descriptor(desc1, &desc1_str); tt_int_op(ret, OP_EQ, 0); - ret = hs_cache_store_as_dir(desc1_str); - tt_int_op(ret, OP_EQ, 0); + ret = hs_cache_store_as_dir(desc1_str); + tt_int_op(ret, OP_EQ, 0); /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */ ret = cache_clean_v3_as_dir(now, 0); diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index d9030c1fc5..086d755bd3 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -29,7 +29,8 @@ helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now, hs_desc_link_specifier_t *ls = tor_malloc_zero(sizeof(*ls)); if (legacy) { ls->type = LS_LEGACY_ID; - memcpy(ls->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8", DIGEST_LEN); + memcpy(ls->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8", + DIGEST_LEN); } else { ls->u.ap.port = 9001; int family = tor_addr_parse(&ls->u.ap.addr, addr); @@ -106,16 +107,16 @@ helper_build_hs_desc(unsigned int no_ip) if (!no_ip) { /* Add four intro points. */ smartlist_add(desc->encrypted_data.intro_points, - helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, + helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, "1.2.3.4", 0)); smartlist_add(desc->encrypted_data.intro_points, - helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, + helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, "[2600::1]", 0)); smartlist_add(desc->encrypted_data.intro_points, - helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, + helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, "3.2.1.4", 1)); smartlist_add(desc->encrypted_data.intro_points, - helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, + helper_build_intro_point(&desc->plaintext_data.blinded_kp, now, "", 1)); } @@ -171,7 +172,7 @@ helper_compare_hs_desc(const hs_descriptor_t *desc1, tt_assert(desc2->encrypted_data.intro_points); tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==, smartlist_len(desc2->encrypted_data.intro_points)); - for (int i = 0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) { + for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) { hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data .intro_points, i), *ip2 = smartlist_get(desc2->encrypted_data @@ -948,7 +949,8 @@ test_decode_plaintext(void *arg) "-----BEGIN %s-----\n" \ "UNICORN\n" \ "-----END MESSAGE-----\n" \ - "signature m20WJH5agqvwhq7QeuEZ1mYyPWQDO+eJOZUjLhAiKu8DbL17DsDfJE6kXbWyHimbNj2we0enV3cCOOAsmPOaAw\n" + "signature m20WJH5agqvwhq7QeuEZ1mYyPWQDO+eJOZUjLhAiKu8DbL17DsDfJE6kXbWy" \ + "HimbNj2we0enV3cCOOAsmPOaAw\n" /* Invalid version. */ { @@ -1125,3 +1127,4 @@ struct testcase_t hs_descriptor[] = { END_OF_TESTCASES }; + -- cgit v1.2.3-54-g00ecf From 3f29688bdff3d6aa0b47ee7080995f44dbb579de Mon Sep 17 00:00:00 2001 From: David Goulet Date: Thu, 15 Sep 2016 14:13:18 -0400 Subject: prop224: Use a const pointer for the cache lookup entry Signed-off-by: David Goulet --- src/or/directory.c | 4 +--- src/or/hs_cache.c | 16 ++++++++-------- src/or/hs_cache.h | 2 +- src/test/test_hs_cache.c | 7 ++----- 4 files changed, 12 insertions(+), 17 deletions(-) (limited to 'src/or/hs_cache.c') diff --git a/src/or/directory.c b/src/or/directory.c index a3aa276df7..75fc103577 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -3400,7 +3400,7 @@ handle_get_hs_descriptor_v3(dir_connection_t *conn, const get_handler_args_t *args) { int retval; - char *desc_str = NULL; + const char *desc_str = NULL; const char *pubkey_str = NULL; const char *url = args->url; @@ -3434,8 +3434,6 @@ handle_get_hs_descriptor_v3(dir_connection_t *conn, connection_write_to_buf(desc_str, strlen(desc_str), TO_CONN(conn)); done: - tor_free(desc_str); - return 0; } diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index 6d33201469..ec98b47f84 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -142,13 +142,13 @@ cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc) return -1; } -/* Using the query which is the blinded key for a descriptor version 3, lookup - * in our directory cache the entry. If found, 1 is returned and desc_out is - * populated with a newly allocated string being the encoded descriptor. If - * not found, 0 is returned and desc_out is untouched. On error, a negative - * value is returned and desc_out is untouched. */ +/* Using the query which is the base64 encoded blinded key of a version 3 + * descriptor, lookup in our directory cache the entry. If found, 1 is + * returned and desc_out is populated with a newly allocated string being the + * encoded descriptor. If not found, 0 is returned and desc_out is untouched. + * On error, a negative value is returned and desc_out is untouched. */ static int -cache_lookup_v3_as_dir(const char *query, char **desc_out) +cache_lookup_v3_as_dir(const char *query, const char **desc_out) { int found = 0; ed25519_public_key_t blinded_key; @@ -167,7 +167,7 @@ cache_lookup_v3_as_dir(const char *query, char **desc_out) if (entry != NULL) { found = 1; if (desc_out) { - *desc_out = tor_strdup(entry->encoded_desc); + *desc_out = entry->encoded_desc; } } @@ -270,7 +270,7 @@ hs_cache_store_as_dir(const char *desc) * untouched. */ int hs_cache_lookup_as_dir(uint32_t version, const char *query, - char **desc_out) + const char **desc_out) { int found; diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h index 466c33db09..88f84c1270 100644 --- a/src/or/hs_cache.h +++ b/src/or/hs_cache.h @@ -48,7 +48,7 @@ size_t hs_cache_handle_oom(time_t now, size_t min_remove_bytes); * right function. */ int hs_cache_store_as_dir(const char *desc); int hs_cache_lookup_as_dir(uint32_t version, const char *query, - char **desc_out); + const char **desc_out); #ifdef HS_CACHE_PRIVATE diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index f3776acb7c..e3a3fda8bb 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -131,7 +131,8 @@ test_directory(void *arg) { int ret; size_t oom_size; - char *desc_out, *desc1_str; + char *desc1_str; + const char *desc_out; hs_descriptor_t *desc1; (void) arg; @@ -158,7 +159,6 @@ test_directory(void *arg) ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); tt_int_op(ret, OP_EQ, 1); tt_str_op(desc_out, OP_EQ, desc1_str); - tor_free(desc_out); /* Tell our OOM to run and to at least remove a byte which will result in * removing the descriptor from our cache. */ oom_size = hs_cache_handle_oom(time(NULL), 1); @@ -186,7 +186,6 @@ test_directory(void *arg) ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); tt_int_op(ret, OP_EQ, 1); tt_str_op(desc_out, OP_EQ, desc1_str); - tor_free(desc_out); /* We should NOT find our zero lifetime desc in our cache. */ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc_zero_lifetime), @@ -221,7 +220,6 @@ test_directory(void *arg) tt_int_op(ret, OP_EQ, 0); ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); tt_int_op(ret, OP_EQ, 1); - tor_free(desc_out); /* Bump revision counter. */ desc1->plaintext_data.revision_counter++; ret = hs_desc_encode_descriptor(desc1, &new_desc_str); @@ -232,7 +230,6 @@ test_directory(void *arg) ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out); tt_int_op(ret, OP_EQ, 1); tt_str_op(desc_out, OP_EQ, new_desc_str); - tor_free(desc_out); tor_free(new_desc_str); } -- cgit v1.2.3-54-g00ecf From 1eed6edf36d57c5f80a13a6884afda798fa2abcd Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 16 Sep 2016 16:39:01 -0400 Subject: prop224: Add a cache free all function Signed-off-by: David Goulet --- src/or/hs_cache.c | 16 ++++++++++++++++ src/or/hs_cache.h | 1 + src/or/main.c | 1 + 3 files changed, 18 insertions(+) (limited to 'src/or/hs_cache.c') diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c index ec98b47f84..868f936422 100644 --- a/src/or/hs_cache.c +++ b/src/or/hs_cache.c @@ -56,6 +56,15 @@ cache_dir_desc_free(hs_cache_dir_descriptor_t *desc) tor_free(desc); } +/* Helper function: Use by the free all function using the digest256map + * interface to cache entries. */ +static void +cache_dir_desc_free_(void *ptr) +{ + hs_cache_dir_descriptor_t *desc = ptr; + cache_dir_desc_free(desc); +} + /* Create a new directory cache descriptor object from a encoded descriptor. * On success, return the heap-allocated cache object, otherwise return NULL if * we can't decode the descriptor. */ @@ -366,3 +375,10 @@ hs_cache_init(void) hs_cache_v3_dir = digest256map_new(); } +/* Cleanup the hidden service cache subsystem. */ +void +hs_cache_free_all(void) +{ + tor_assert(hs_cache_v3_dir); + digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_); +} diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h index 88f84c1270..01abb8002f 100644 --- a/src/or/hs_cache.h +++ b/src/or/hs_cache.h @@ -40,6 +40,7 @@ typedef struct hs_cache_dir_descriptor_t { /* Public API */ void hs_cache_init(void); +void hs_cache_free_all(void); void hs_cache_clean_as_dir(time_t now); size_t hs_cache_handle_oom(time_t now, size_t min_remove_bytes); diff --git a/src/or/main.c b/src/or/main.c index 9defdf051a..6876236446 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2958,6 +2958,7 @@ tor_free_all(int postfork) rend_service_free_all(); rend_cache_free_all(); rend_service_authorization_free_all(); + hs_cache_free_all(); rep_hist_free_all(); dns_free_all(); clear_pending_onions(); -- cgit v1.2.3-54-g00ecf