#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
#include "feature/hs/hs_cache.h"
+#include "feature/hs/hs_ident.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/routerlist.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
+#include "lib/crypt_ops/crypto_format.h"
#include "feature/dircache/cached_dir_st.h"
#include "feature/dircommon/dir_connection_st.h"
write_http_response_header(conn, strlen(desc_str), NO_METHOD, 0);
connection_buf_add(desc_str, strlen(desc_str), TO_CONN(conn));
+ /* We have successfully written the descriptor on the connection outbuf so
+ * save this query identifier into the dir_connection_t in order
+ * to associate it to the descriptor when closing. */
+ {
+ /* Decode blinded key. This is certain to work else
+ * hs_cache_lookup_as_dir() would have failed. */
+ ed25519_public_key_t blinded_key;
+ ed25519_public_from_base64(&blinded_key, pubkey_str);
+ conn->hs_ident = hs_ident_server_dir_conn_new(&blinded_key);
+ }
+
done:
return 0;
}
/* Hidden service connection identifier for dir connections: Used by HS
client-side code to fetch HS descriptors, and by the service-side code to
- upload descriptors. */
+ upload descriptors. Also used by the HSDir, setting only the blinded key,
+ in order to locate back the descriptor in the cache once the dir stream is
+ closed. */
struct hs_ident_dir_conn_t *hs_ident;
/** If this is a one-hop connection, tracks the state of the directory guard
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
+#include "feature/hs/hs_cache.h"
#include "feature/stats/geoip_stats.h"
#include "lib/compress/compress.h"
connection_dir_client_request_failed(dir_conn);
}
+ /* If we are an HSDir, mark the corresponding descriptor as downloaded. This
+ * is needed for the OOM cache cleanup.
+ *
+ * This is done when the direction connection is closed in order to raise the
+ * attack cost of filling the cache with bogus descriptors. That attacker
+ * would need to increase that downloaded counter for the attack to be
+ * successful which is expensive. */
+ if (conn->purpose == DIR_PURPOSE_SERVER && dir_conn->hs_ident) {
+ hs_cache_mark_dowloaded_as_dir(dir_conn->hs_ident);
+ }
+
connection_dir_client_refetch_hsdesc_if_needed(dir_conn);
}
return found;
}
+/** Using the given directory identifier, lookup the descriptor in our cache
+ * and if present, increment the downloaded counter. This is done when the
+ * directory connection fetching this descriptor is closed. */
+void
+hs_cache_mark_dowloaded_as_dir(const hs_ident_dir_conn_t *ident)
+{
+ hs_cache_dir_descriptor_t *entry;
+
+ tor_assert(ident);
+
+ entry = lookup_v3_desc_as_dir(ident->blinded_pk.pubkey);
+ if (entry) {
+ entry->n_downloaded++;
+ }
+}
+
/** Clean all directory caches using the current time now. */
void
hs_cache_clean_as_dir(time_t now)
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_descriptor.h"
+#include "feature/hs/hs_ident.h"
#include "feature/rend/rendcommon.h"
#include "feature/nodelist/torcert.h"
/** Encoded descriptor which is basically in text form. It's a NUL terminated
* string thus safe to strlen(). */
char *encoded_desc;
+ /** How many times this descriptor has been downloaded. We use this as an
+ * heuristic for the OOM cache cleaning. It is very large so we avoid an kind
+ * of possible wrapping. */
+ uint64_t n_downloaded;
} hs_cache_dir_descriptor_t;
/* Public API */
int hs_cache_store_as_dir(const char *desc);
int hs_cache_lookup_as_dir(uint32_t version, const char *query,
const char **desc_out);
+void hs_cache_mark_dowloaded_as_dir(const hs_ident_dir_conn_t *ident);
const hs_descriptor_t *
hs_cache_lookup_as_client(const struct ed25519_public_key_t *key);
tor_free(ident);
}
+/** Return a newly allocated HS directory connection identifier that is meant
+ * for the server side (HSDir). Only the blinded key is known by the HSDir. */
+hs_ident_dir_conn_t *
+hs_ident_server_dir_conn_new(const ed25519_public_key_t *blinded_pk)
+{
+ hs_ident_dir_conn_t *ident = tor_malloc_zero(sizeof(*ident));
+ ed25519_pubkey_copy(&ident->blinded_pk, blinded_pk);
+ return ident;
+}
+
/** Initialized the allocated ident object with identity_pk and blinded_pk.
* None of them can be NULL since a valid directory connection identifier must
* have all fields set. */
void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
const ed25519_public_key_t *blinded_pk,
hs_ident_dir_conn_t *ident);
+hs_ident_dir_conn_t *hs_ident_server_dir_conn_new(
+ const ed25519_public_key_t *blinded_pk);
/* Edge connection identifier API. */
hs_ident_edge_conn_t *hs_ident_edge_conn_new(