diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 738119fa18..80bb7f69f3 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -943,10 +943,6 @@ circuit_free(circuit_t *circ) crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); - if (ocirc->hs_token) { - hs_circuitmap_remove_circuit(ocirc); - } - if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC); @@ -978,6 +974,11 @@ circuit_free(circuit_t *circ) /* Remove from map. */ circuit_set_n_circid_chan(circ, 0, NULL); + /* Clear HS circuitmap token from this circ (if any) */ + if (circ->hs_token) { + hs_circuitmap_remove_circuit(circ); + } + /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(&circ->n_chan_cells); diff --git a/src/or/hs_circuitmap.c b/src/or/hs_circuitmap.c index 32017f1234..ea66fb5194 100644 --- a/src/or/hs_circuitmap.c +++ b/src/or/hs_circuitmap.c @@ -4,8 +4,9 @@ /** * \file hs_circuitmap.c * - * \brief Manage the hidden service circuitmap: A hash table that maps binary - * tokens to introduction and rendezvous circuits. + * \brief Hidden service circuitmap: A hash table that maps binary tokens to + * introduction and rendezvous circuits; it's used both by relays acting as + * intro points and rendezvous points, and also by hidden services themselves. **/ #define HS_CIRCUITMAP_PRIVATE @@ -25,8 +26,8 @@ static struct hs_circuitmap_ht *the_hs_circuitmap = NULL; /* This is a helper function used by the hash table code (HT_). It returns 1 if * two circuits have the same HS token. */ static int -hs_circuits_have_same_token(const or_circuit_t *first_circuit, - const or_circuit_t *second_circuit) +hs_circuits_have_same_token(const circuit_t *first_circuit, + const circuit_t *second_circuit) { const hs_token_t *first_token; const hs_token_t *second_token; @@ -57,7 +58,7 @@ hs_circuits_have_same_token(const or_circuit_t *first_circuit, /* This is a helper function for the hash table code (HT_). It hashes a circuit * HS token into an unsigned int for use as a key by the hash table routines.*/ static inline unsigned int -hs_circuit_hash_token(const or_circuit_t *circuit) +hs_circuit_hash_token(const circuit_t *circuit) { tor_assert(circuit->hs_token); @@ -67,11 +68,11 @@ hs_circuit_hash_token(const or_circuit_t *circuit) /* Register the circuitmap hash table */ HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct - or_circuit_t, // The name of the element struct, + circuit_t, // The name of the element struct, hs_circuitmap_node, // The name of HT_ENTRY member hs_circuit_hash_token, hs_circuits_have_same_token) -HT_GENERATE2(hs_circuitmap_ht, or_circuit_t, hs_circuitmap_node, +HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node, hs_circuit_hash_token, hs_circuits_have_same_token, 0.6, tor_reallocarray, tor_free_) @@ -116,13 +117,13 @@ hs_token_free(hs_token_t *hs_token) } /** Return the circuit from the circuitmap with token search_token. */ -static or_circuit_t * +static circuit_t * get_circuit_with_token(hs_token_t *search_token) { tor_assert(the_hs_circuitmap); /* We use a dummy circuit object for the hash table search routine. */ - or_circuit_t search_circ; + circuit_t search_circ; search_circ.hs_token = search_token; return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ); } @@ -130,7 +131,7 @@ get_circuit_with_token(hs_token_t *search_token) /* Helper function that registers circ with token on the HS circuitmap. This function steals reference of token. */ static void -hs_circuitmap_register_impl(or_circuit_t *circ, hs_token_t *token) +hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token) { tor_assert(circ); tor_assert(token); @@ -145,13 +146,12 @@ hs_circuitmap_register_impl(or_circuit_t *circ, hs_token_t *token) take precedence over old ones, so that HSes and clients and reestablish killed circuits without changing the HS token. */ { - or_circuit_t *found_circ; + circuit_t *found_circ; found_circ = get_circuit_with_token(token); if (found_circ) { hs_circuitmap_remove_circuit(found_circ); - if (!found_circ->base_.marked_for_close) { - circuit_mark_for_close(TO_CIRCUIT(found_circ), - END_CIRC_REASON_FINISHED); + if (!found_circ->marked_for_close) { + circuit_mark_for_close(found_circ, END_CIRC_REASON_FINISHED); } } } @@ -165,7 +165,7 @@ hs_circuitmap_register_impl(or_circuit_t *circ, hs_token_t *token) * circuitmap. Use the HS token as the key to the hash table. If * token is not set, clear the circuit of any HS tokens. */ static void -hs_circuitmap_register_circuit(or_circuit_t *circ, +hs_circuitmap_register_circuit(circuit_t *circ, hs_token_type_t type, size_t token_len, const uint8_t *token) { @@ -178,17 +178,19 @@ hs_circuitmap_register_circuit(or_circuit_t *circ, hs_circuitmap_register_impl(circ, hs_token); } -/* Query circuitmap for circuit with token of size token_len. - * Only returns a circuit with purpose equal to the wanted_circ_purpose - * parameter and if it is NOT marked for close. Return NULL if no such circuit - * is found. */ -static or_circuit_t * -hs_circuitmap_get_circuit(hs_token_type_t type, - size_t token_len, - const uint8_t *token, - uint8_t wanted_circ_purpose) +/* Helper function for hs_circuitmap_get_origin_circuit() and + * hs_circuitmap_get_or_circuit(). Because only circuit_t are indexed in the + * circuitmap, this function returns object type so the specialized functions + * using this helper can upcast it to the right type. + * + * Return NULL if not such circuit is found. */ +static circuit_t * +hs_circuitmap_get_circuit_impl(hs_token_type_t type, + size_t token_len, + const uint8_t *token, + uint8_t wanted_circ_purpose) { - or_circuit_t *found_circ = NULL; + circuit_t *found_circ = NULL; tor_assert(the_hs_circuitmap); @@ -202,87 +204,247 @@ hs_circuitmap_get_circuit(hs_token_type_t type, /* Check that the circuit is useful to us */ if (!found_circ || - found_circ->base_.purpose != wanted_circ_purpose || - found_circ->base_.marked_for_close) { + found_circ->purpose != wanted_circ_purpose || + found_circ->marked_for_close) { return NULL; } return found_circ; } +/* Helper function: Query circuitmap for origin circuit with token of + * size token_len and type. Only returns a circuit with purpose + * equal to the wanted_circ_purpose parameter and if it is NOT marked + * for close. Return NULL if no such circuit is found. */ +static origin_circuit_t * +hs_circuitmap_get_origin_circuit(hs_token_type_t type, + size_t token_len, + const uint8_t *token, + uint8_t wanted_circ_purpose) +{ + circuit_t *circ; + tor_assert(token); + tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose)); + + circ = hs_circuitmap_get_circuit_impl(type, token_len, token, + wanted_circ_purpose); + if (!circ) { + return NULL; + } + + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + return TO_ORIGIN_CIRCUIT(circ); +} + +/* Helper function: Query circuitmap for OR circuit with token of size + * token_len and type. Only returns a circuit with purpose equal + * to the wanted_circ_purpose parameter and if it is NOT marked for + * close. Return NULL if no such circuit is found. */ +static or_circuit_t * +hs_circuitmap_get_or_circuit(hs_token_type_t type, + size_t token_len, + const uint8_t *token, + uint8_t wanted_circ_purpose) +{ + circuit_t *circ; + tor_assert(token); + tor_assert(!CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose)); + + circ = hs_circuitmap_get_circuit_impl(type, token_len, token, + wanted_circ_purpose); + if (!circ) { + return NULL; + } + + tor_assert(CIRCUIT_IS_ORCIRC(circ)); + return TO_OR_CIRCUIT(circ); +} + /************** Public circuitmap API ****************************************/ -/* Public function: Return v3 introduction circuit with auth_key. Return - * NULL if no such circuit is found in the circuitmap. */ -or_circuit_t * -hs_circuitmap_get_intro_circ_v3(const ed25519_public_key_t *auth_key) -{ - tor_assert(auth_key); +/**** Public relay-side getters: */ - return hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V3, - ED25519_PUBKEY_LEN, auth_key->pubkey, - CIRCUIT_PURPOSE_INTRO_POINT); +/* Public function: Return a v3 introduction circuit to this relay with + * auth_key. Return NULL if no such circuit is found in the + * circuitmap. */ +or_circuit_t * +hs_circuitmap_get_intro_circ_v3_relay_side( + const ed25519_public_key_t *auth_key) +{ + return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V3_RELAY_SIDE, + ED25519_PUBKEY_LEN, auth_key->pubkey, + CIRCUIT_PURPOSE_INTRO_POINT); } -/* Public function: Return v2 introduction circuit with digest. Return - * NULL if no such circuit is found in the circuitmap. */ +/* Public function: Return v2 introduction circuit to this relay with + * digest. Return NULL if no such circuit is found in the circuitmap. */ or_circuit_t * -hs_circuitmap_get_intro_circ_v2(const uint8_t *digest) +hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest) { - tor_assert(digest); - - return hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V2, - REND_TOKEN_LEN, digest, - CIRCUIT_PURPOSE_INTRO_POINT); + return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V2_RELAY_SIDE, + REND_TOKEN_LEN, digest, + CIRCUIT_PURPOSE_INTRO_POINT); } -/* Public function: Return rendezvous circuit with rendezvous +/* Public function: Return rendezvous circuit to this relay with rendezvous * cookie. Return NULL if no such circuit is found in the circuitmap. */ or_circuit_t * -hs_circuitmap_get_rend_circ(const uint8_t *cookie) +hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie) { - tor_assert(cookie); - - return hs_circuitmap_get_circuit(HS_TOKEN_REND, - REND_TOKEN_LEN, cookie, - CIRCUIT_PURPOSE_REND_POINT_WAITING); + return hs_circuitmap_get_or_circuit(HS_TOKEN_REND_RELAY_SIDE, + REND_TOKEN_LEN, cookie, + CIRCUIT_PURPOSE_REND_POINT_WAITING); } +/** Public relay-side setters: */ + /* Public function: Register rendezvous circuit with key cookie to the * circuitmap. */ void -hs_circuitmap_register_rend_circ(or_circuit_t *circ, const uint8_t *cookie) +hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ, + const uint8_t *cookie) { - hs_circuitmap_register_circuit(circ, - HS_TOKEN_REND, + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_REND_RELAY_SIDE, REND_TOKEN_LEN, cookie); } - /* Public function: Register v2 intro circuit with key digest to the * circuitmap. */ void -hs_circuitmap_register_intro_circ_v2(or_circuit_t *circ, const uint8_t *digest) +hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ, + const uint8_t *digest) { - hs_circuitmap_register_circuit(circ, - HS_TOKEN_INTRO_V2, + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_INTRO_V2_RELAY_SIDE, REND_TOKEN_LEN, digest); } /* Public function: Register v3 intro circuit with key auth_key to the * circuitmap. */ void -hs_circuitmap_register_intro_circ_v3(or_circuit_t *circ, - const ed25519_public_key_t *auth_key) +hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ, + const ed25519_public_key_t *auth_key) { - hs_circuitmap_register_circuit(circ, - HS_TOKEN_INTRO_V3, + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_INTRO_V3_RELAY_SIDE, ED25519_PUBKEY_LEN, auth_key->pubkey); } -/** Remove this circuit from the HS circuitmap. Clear its HS token, and remove - * it from the hashtable. */ +/**** Public servide-side getters: */ + +/* Public function: Return v3 introduction circuit with auth_key + * originating from this hidden service. Return NULL if no such circuit is + * found in the circuitmap. */ +origin_circuit_t * +hs_circuitmap_get_intro_circ_v3_service_side(const + ed25519_public_key_t *auth_key) +{ + origin_circuit_t *circ = NULL; + + /* Check first for established intro circuits */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE, + ED25519_PUBKEY_LEN, auth_key->pubkey, + CIRCUIT_PURPOSE_S_INTRO); + if (circ) { + return circ; + } + + /* ...if nothing found, check for pending intro circs */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE, + ED25519_PUBKEY_LEN, auth_key->pubkey, + CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + + return circ; +} + +/* Public function: Return v2 introduction circuit originating from this hidden + * service with digest. Return NULL if no such circuit is found in the + * circuitmap. */ +origin_circuit_t * +hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest) +{ + origin_circuit_t *circ = NULL; + + /* Check first for established intro circuits */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE, + REND_TOKEN_LEN, digest, + CIRCUIT_PURPOSE_S_INTRO); + if (circ) { + return circ; + } + + /* ...if nothing found, check for pending intro circs */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE, + REND_TOKEN_LEN, digest, + CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + + return circ; +} + +/* Public function: Return rendezvous circuit originating from this hidden + * service with rendezvous cookie. Return NULL if no such circuit is + * found in the circuitmap. */ +origin_circuit_t * +hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie) +{ + origin_circuit_t *circ = NULL; + + /* Try to check if we have a connecting circuit. */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE, + REND_TOKEN_LEN, cookie, + CIRCUIT_PURPOSE_S_CONNECT_REND); + if (circ) { + return circ; + } + + /* Then try for connected circuit. */ + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE, + REND_TOKEN_LEN, cookie, + CIRCUIT_PURPOSE_S_REND_JOINED); + return circ; +} + +/**** Public servide-side setters: */ + +/* Public function: Register v2 intro circuit with key digest to the + * circuitmap. */ void -hs_circuitmap_remove_circuit(or_circuit_t *circ) +hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ, + const uint8_t *digest) +{ + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_INTRO_V2_SERVICE_SIDE, + REND_TOKEN_LEN, digest); +} + +/* Public function: Register v3 intro circuit with key auth_key to the + * circuitmap. */ +void +hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ, + const ed25519_public_key_t *auth_key) +{ + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_INTRO_V3_SERVICE_SIDE, + ED25519_PUBKEY_LEN, auth_key->pubkey); +} + +/* Public function: Register rendezvous circuit with key cookie to the + * circuitmap. */ +void +hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ, + const uint8_t *cookie) +{ + hs_circuitmap_register_circuit(TO_CIRCUIT(circ), + HS_TOKEN_REND_SERVICE_SIDE, + REND_TOKEN_LEN, cookie); +} + +/**** Misc public functions: */ + +/** Public function: Remove this circuit from the HS circuitmap. Clear its HS + * token, and remove it from the hashtable. */ +void +hs_circuitmap_remove_circuit(circuit_t *circ) { tor_assert(the_hs_circuitmap); @@ -291,14 +453,14 @@ hs_circuitmap_remove_circuit(or_circuit_t *circ) } /* Remove circ from circuitmap */ - or_circuit_t *tmp; + circuit_t *tmp; tmp = HT_REMOVE(hs_circuitmap_ht, the_hs_circuitmap, circ); /* ... and ensure the removal was successful. */ if (tmp) { tor_assert(tmp == circ); } else { log_warn(LD_BUG, "Could not find circuit (%u) in circuitmap.", - circ->p_circ_id); + circ->n_circ_id); } /* Clear token from circ */ @@ -306,7 +468,7 @@ hs_circuitmap_remove_circuit(or_circuit_t *circ) circ->hs_token = NULL; } -/* Initialize the global HS circuitmap. */ +/* Public function: Initialize the global HS circuitmap. */ void hs_circuitmap_init(void) { @@ -316,7 +478,7 @@ hs_circuitmap_init(void) HT_INIT(hs_circuitmap_ht, the_hs_circuitmap); } -/* Free all memory allocated by the global HS circuitmap. */ +/* Public function: Free all memory allocated by the global HS circuitmap. */ void hs_circuitmap_free_all(void) { diff --git a/src/or/hs_circuitmap.h b/src/or/hs_circuitmap.h index 6e0c2d44f2..33d5b64117 100644 --- a/src/or/hs_circuitmap.h +++ b/src/or/hs_circuitmap.h @@ -9,26 +9,52 @@ #ifndef TOR_HS_CIRCUITMAP_H #define TOR_HS_CIRCUITMAP_H -typedef HT_HEAD(hs_circuitmap_ht, or_circuit_t) hs_circuitmap_ht; +typedef HT_HEAD(hs_circuitmap_ht, circuit_t) hs_circuitmap_ht; typedef struct hs_token_s hs_token_t; struct or_circuit_t; +struct origin_circuit_t; /** Public HS circuitmap API: */ -struct or_circuit_t *hs_circuitmap_get_rend_circ(const uint8_t *cookie); -struct or_circuit_t *hs_circuitmap_get_intro_circ_v3( - const ed25519_public_key_t *auth_key); -struct or_circuit_t *hs_circuitmap_get_intro_circ_v2(const uint8_t *digest); +/** Public relay-side API: */ -void hs_circuitmap_register_rend_circ(struct or_circuit_t *circ, - const uint8_t *cookie); -void hs_circuitmap_register_intro_circ_v2(struct or_circuit_t *circ, - const uint8_t *digest); -void hs_circuitmap_register_intro_circ_v3(struct or_circuit_t *circ, +struct or_circuit_t * +hs_circuitmap_get_intro_circ_v3_relay_side(const + ed25519_public_key_t *auth_key); +struct or_circuit_t * +hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest); +struct or_circuit_t * +hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie); + +void hs_circuitmap_register_rend_circ_relay_side(struct or_circuit_t *circ, + const uint8_t *cookie); +void hs_circuitmap_register_intro_circ_v2_relay_side(struct or_circuit_t *circ, + const uint8_t *digest); +void hs_circuitmap_register_intro_circ_v3_relay_side(struct or_circuit_t *circ, const ed25519_public_key_t *auth_key); -void hs_circuitmap_remove_circuit(struct or_circuit_t *circ); +/** Public service-side API: */ + +struct origin_circuit_t * +hs_circuitmap_get_intro_circ_v3_service_side(const + ed25519_public_key_t *auth_key); +struct origin_circuit_t * +hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest); +struct origin_circuit_t * +hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie); + +void hs_circuitmap_register_intro_circ_v2_service_side( + struct origin_circuit_t *circ, + const uint8_t *digest); +void hs_circuitmap_register_intro_circ_v3_service_side( + struct origin_circuit_t *circ, + const ed25519_public_key_t *auth_key); +void hs_circuitmap_register_rend_circ_service_side( + struct origin_circuit_t *circ, + const uint8_t *cookie); + +void hs_circuitmap_remove_circuit(struct circuit_t *circ); void hs_circuitmap_init(void); void hs_circuitmap_free_all(void); @@ -37,12 +63,19 @@ void hs_circuitmap_free_all(void); /** Represents the type of HS token. */ typedef enum { - /** A rendezvous cookie (128bit)*/ - HS_TOKEN_REND, - /** A v2 introduction point pubkey (160bit) */ - HS_TOKEN_INTRO_V2, - /** A v3 introduction point pubkey (256bit) */ - HS_TOKEN_INTRO_V3, + /** A rendezvous cookie on a relay (128bit)*/ + HS_TOKEN_REND_RELAY_SIDE, + /** A v2 introduction point pubkey on a relay (160bit) */ + HS_TOKEN_INTRO_V2_RELAY_SIDE, + /** A v3 introduction point pubkey on a relay (256bit) */ + HS_TOKEN_INTRO_V3_RELAY_SIDE, + + /** A rendezvous cookie on a hidden service (128bit)*/ + HS_TOKEN_REND_SERVICE_SIDE, + /** A v2 introduction point pubkey on a hidden service (160bit) */ + HS_TOKEN_INTRO_V2_SERVICE_SIDE, + /** A v3 introduction point pubkey on a hidden service (256bit) */ + HS_TOKEN_INTRO_V3_SERVICE_SIDE, } hs_token_type_t; /** Represents a token used in the HS protocol. Each such token maps to a diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c index c32d24480a..b3c76db0b0 100644 --- a/src/or/hs_intropoint.c +++ b/src/or/hs_intropoint.c @@ -196,7 +196,7 @@ handle_verified_establish_intro_cell(or_circuit_t *circ, } /* Associate intro point auth key with this circuit. */ - hs_circuitmap_register_intro_circ_v3(circ, &auth_key); + hs_circuitmap_register_intro_circ_v3_relay_side(circ, &auth_key); /* Repurpose this circuit into an intro circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); @@ -462,7 +462,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request, { ed25519_public_key_t auth_key; get_auth_key_from_cell(&auth_key, RELAY_COMMAND_INTRODUCE1, parsed_cell); - service_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + service_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); if (service_circ == NULL) { char b64_key[ED25519_BASE64_LEN + 1]; ed25519_public_to_base64(b64_key, &auth_key); diff --git a/src/or/or.h b/src/or/or.h index f36b12b3f7..a7b3a66561 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3074,6 +3074,13 @@ typedef struct circuit_t { * circuit's queues; used only if CELL_STATS events are enabled and * cleared after being sent to control port. */ smartlist_t *testing_cell_stats; + + /** If set, points to an HS token that this circuit might be carrying. + * Used by the HS circuitmap. */ + hs_token_t *hs_token; + /** Hashtable node: used to look up the circuit by its HS token using the HS + circuitmap. */ + HT_ENTRY(circuit_t) hs_circuitmap_node; } circuit_t; /** Largest number of relay_early cells that we can send on a given @@ -3383,13 +3390,6 @@ typedef struct or_circuit_t { * is not marked for close. */ struct or_circuit_t *rend_splice; - /** If set, points to an HS token that this circuit might be carrying. - * Used by the HS circuitmap. */ - hs_token_t *hs_token; - /** Hashtable node: used to look up the circuit by its HS token using the HS - circuitmap. */ - HT_ENTRY(or_circuit_t) hs_circuitmap_node; - /** Stores KH for the handshake. */ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ diff --git a/src/or/rendmid.c b/src/or/rendmid.c index a7b37c7cc9..23c3deddaa 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -96,7 +96,8 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, /* Close any other intro circuits with the same pk. */ c = NULL; - while ((c = hs_circuitmap_get_intro_circ_v2((const uint8_t *)pk_digest))) { + while ((c = hs_circuitmap_get_intro_circ_v2_relay_side( + (const uint8_t *)pk_digest))) { log_info(LD_REND, "Replacing old circuit for service %s", safe_str(serviceid)); circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED); @@ -111,7 +112,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, /* Now, set up this circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); - hs_circuitmap_register_intro_circ_v2(circ, (uint8_t *)pk_digest); + hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest); log_info(LD_REND, "Established introduction point on circuit %u for service %s", @@ -165,7 +166,8 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, /* The first 20 bytes are all we look at: they have a hash of the service's * PK. */ - intro_circ = hs_circuitmap_get_intro_circ_v2((const uint8_t*)request); + intro_circ = hs_circuitmap_get_intro_circ_v2_relay_side( + (const uint8_t*)request); if (!intro_circ) { log_info(LD_REND, "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; " @@ -242,7 +244,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - if (hs_circuitmap_get_rend_circ(request)) { + if (hs_circuitmap_get_rend_circ_relay_side(request)) { log_warn(LD_PROTOCOL, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; @@ -258,7 +260,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); - hs_circuitmap_register_rend_circ(circ, request); + hs_circuitmap_register_rend_circ_relay_side(circ, request); base16_encode(hexid,9,(char*)request,4); @@ -307,7 +309,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, "Got request for rendezvous from circuit %u to cookie %s.", (unsigned)circ->p_circ_id, hexid); - rend_circ = hs_circuitmap_get_rend_circ(request); + rend_circ = hs_circuitmap_get_rend_circ_relay_side(request); if (!rend_circ) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", @@ -342,7 +344,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); circuit_change_purpose(TO_CIRCUIT(rend_circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); - hs_circuitmap_remove_circuit(circ); + hs_circuitmap_remove_circuit(TO_CIRCUIT(circ)); rend_circ->rend_splice = circ; circ->rend_splice = rend_circ; diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 61d3b43059..14c65abd0f 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -201,68 +201,68 @@ test_rend_token_maps(void *arg) tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.'); /* No maps; nothing there. */ - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1)); - hs_circuitmap_register_rend_circ(c1, tok1); - hs_circuitmap_register_intro_circ_v2(c2, tok2); + hs_circuitmap_register_rend_circ_relay_side(c1, tok1); + hs_circuitmap_register_intro_circ_v2_relay_side(c2, tok2); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok3)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1)); /* Without purpose set, we don't get the circuits */ - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; /* Okay, make sure they show up now. */ - tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); - tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); + tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); /* Two items at the same place with the same token. */ c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; - hs_circuitmap_register_rend_circ(c3, tok2); - tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); - tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + hs_circuitmap_register_rend_circ_relay_side(c3, tok2); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); /* Marking a circuit makes it not get returned any more */ circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); circuit_free(TO_CIRCUIT(c1)); c1 = NULL; /* Freeing a circuit makes it not get returned any more. */ circuit_free(TO_CIRCUIT(c2)); c2 = NULL; - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); /* c3 -- are you still there? */ - tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); /* Change its cookie. This never happens in Tor per se, but hey. */ c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - hs_circuitmap_register_intro_circ_v2(c3, tok3); + hs_circuitmap_register_intro_circ_v2_relay_side(c3, tok3); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); - tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); /* Now replace c3 with c4. */ c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - hs_circuitmap_register_intro_circ_v2(c4, tok3); + hs_circuitmap_register_intro_circ_v2_relay_side(c4, tok3); - tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); + tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); - tt_ptr_op(c3->hs_token, OP_EQ, NULL); - tt_ptr_op(c4->hs_token, OP_NE, NULL); - tt_mem_op(c4->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN); + tt_ptr_op(TO_CIRCUIT(c3)->hs_token, OP_EQ, NULL); + tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_NE, NULL); + tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN); /* Now clear c4's cookie. */ - hs_circuitmap_remove_circuit(c4); - tt_ptr_op(c4->hs_token, OP_EQ, NULL); - tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); + hs_circuitmap_remove_circuit(TO_CIRCUIT(c4)); + tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_EQ, NULL); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3)); done: if (c1) @@ -370,10 +370,88 @@ test_pick_circid(void *arg) UNMOCK(channel_dump_statistics); } +/** Test that the circuit pools of our HS circuitmap are isolated based on + * their token type. */ +static void +test_hs_circuitmap_isolation(void *arg) +{ + or_circuit_t *circ1 = NULL; + origin_circuit_t *circ2 = NULL; + or_circuit_t *circ3 = NULL; + origin_circuit_t *circ4 = NULL; + + (void)arg; + + hs_circuitmap_init(); + + { + const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th"; + + circ1 = or_circuit_new(0, NULL); + circ1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; + + /* check that circuitmap is empty right? */ + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); + + /* Register circ1 with tok1 as relay-side rend circ */ + hs_circuitmap_register_rend_circ_relay_side(circ1, tok1); + + /* check that service-side getters don't work */ + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_service_side(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok1)); + + /* Check that the right getter works. */ + tt_ptr_op(circ1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1)); + } + + { + const uint8_t tok2[REND_TOKEN_LEN] = "you dont know anythi"; + + circ2 = origin_circuit_new(); + circ2->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO; + circ3 = or_circuit_new(0, NULL); + circ3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; + circ4 = origin_circuit_new(); + circ4->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO; + + /* Register circ2 with tok2 as service-side intro v2 circ */ + hs_circuitmap_register_intro_circ_v2_service_side(circ2, tok2); + /* Register circ3 with tok2 again but for different purpose */ + hs_circuitmap_register_intro_circ_v2_relay_side(circ3, tok2); + + /* Check that the getters work */ + tt_ptr_op(circ2, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok2)); + tt_ptr_op(circ3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2)); + + /* Register circ4 with tok2: it should override circ2 */ + hs_circuitmap_register_intro_circ_v2_service_side(circ4, tok2); + + /* check that relay-side getters don't work */ + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2)); + + /* Check that the getter returns circ4; the last circuit registered with + * that token. */ + tt_ptr_op(circ4, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok2)); + } + + done: + if (circ1) + circuit_free(TO_CIRCUIT(circ1)); + if (circ2) + circuit_free(TO_CIRCUIT(circ2)); + if (circ3) + circuit_free(TO_CIRCUIT(circ3)); + if (circ4) + circuit_free(TO_CIRCUIT(circ4)); +} + + struct testcase_t circuitlist_tests[] = { { "maps", test_clist_maps, TT_FORK, NULL, NULL }, { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL }, { "pick_circid", test_pick_circid, TT_FORK, NULL, NULL }, + { "hs_circuitmap_isolation", test_hs_circuitmap_isolation, + TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 6e68e2c867..5caa550dd4 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -532,7 +532,7 @@ test_intro_point_registration(void *arg) tt_assert(the_hs_circuitmap); tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap)); /* Do a circuitmap query in any case */ - returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); tt_ptr_op(returned_intro_circ, ==, NULL); } @@ -548,7 +548,7 @@ test_intro_point_registration(void *arg) tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap)); get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, establish_intro_cell); - returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + returned_intro_circ = hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key); tt_ptr_op(intro_circ, ==, returned_intro_circ); } @@ -569,7 +569,8 @@ test_intro_point_registration(void *arg) /* Check that the new element is our legacy intro circuit. */ retval = crypto_pk_get_digest(legacy_auth_key, key_digest); tt_int_op(retval, ==, 0); - returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest); + returned_intro_circ = + hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest); tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ); } @@ -790,7 +791,7 @@ test_received_introduce1_handling(void *arg) const uint8_t *cell_auth_key = trn_cell_introduce1_getconstarray_auth_key(cell); memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN); - hs_circuitmap_register_intro_circ_v3(service_circ, &auth_key); + hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key); ret = hs_intro_received_introduce1(circ, request, request_len); circuit_free(TO_CIRCUIT(circ)); circuit_free(TO_CIRCUIT(service_circ)); @@ -819,7 +820,7 @@ test_received_introduce1_handling(void *arg) /* Register the circuit in the map for the auth key of the cell. */ uint8_t token[REND_TOKEN_LEN]; memcpy(token, legacy_key_id, sizeof(token)); - hs_circuitmap_register_intro_circ_v2(service_circ, token); + hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token); ret = hs_intro_received_introduce1(circ, request, request_len); circuit_free(TO_CIRCUIT(circ)); circuit_free(TO_CIRCUIT(service_circ));