diff options
-rw-r--r-- | src/or/hs_circuit.c | 17 | ||||
-rw-r--r-- | src/or/hs_service.c | 8 | ||||
-rw-r--r-- | src/or/hs_service.h | 7 |
3 files changed, 32 insertions, 0 deletions
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index ee43406c0d..d9e96c6330 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -794,6 +794,7 @@ hs_circ_handle_introduce2(const hs_service_t *service, const uint8_t *payload, size_t payload_len) { int ret = -1; + time_t elapsed; hs_cell_introduce2_data_t data; tor_assert(service); @@ -817,6 +818,22 @@ hs_circ_handle_introduce2(const hs_service_t *service, goto done; } + /* Check whether we've seen this REND_COOKIE before to detect repeats. */ + if (replaycache_add_test_and_elapsed( + service->state.replay_cache_rend_cookie, + data.rendezvous_cookie, sizeof(data.rendezvous_cookie), + &elapsed)) { + /* A Tor client will send a new INTRODUCE1 cell with the same REND_COOKIE + * as its previous one if its intro circ times out while in state + * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT. If we received the first + * INTRODUCE1 cell (the intro-point relay converts it into an INTRODUCE2 + * cell), we are already trying to connect to that rend point (and may + * have already succeeded); drop this cell. */ + log_info(LD_REND, "We received an INTRODUCE2 cell with same REND_COOKIE " + "field %ld seconds ago. Dropping cell.", elapsed); + goto done; + } + /* At this point, we just confirmed that the full INTRODUCE2 cell is valid * so increment our counter that we've seen one on this intro point. */ ip->introduce2_count++; diff --git a/src/or/hs_service.c b/src/or/hs_service.c index 48724e45cf..567ca0be03 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -2080,6 +2080,9 @@ hs_service_new(const or_options_t *options) set_service_default_config(&service->config, options); /* Set the default service version. */ service->config.version = HS_SERVICE_DEFAULT_VERSION; + /* Allocate the CLIENT_PK replay cache in service state. */ + service->state.replay_cache_rend_cookie = + replaycache_new(REND_REPLAY_TIME_INTERVAL, REND_REPLAY_TIME_INTERVAL); return service; } @@ -2101,6 +2104,11 @@ hs_service_free(hs_service_t *service) /* Free service configuration. */ service_clear_config(&service->config); + /* Free replay cache from state. */ + if (service->state.replay_cache_rend_cookie) { + replaycache_free(service->state.replay_cache_rend_cookie); + } + /* Wipe service keys. */ memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk)); diff --git a/src/or/hs_service.h b/src/or/hs_service.h index f12094a927..8776a4412c 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -181,6 +181,13 @@ typedef struct hs_service_state_t { /* Indicate that the service has entered the overlap period. We use this * flag to check for descriptor rotation. */ unsigned int in_overlap_period : 1; + + /* Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell to detect + * repeats. Clients may send INTRODUCE1 cells for the same rendezvous point + * through two or more different introduction points; when they do, this + * keeps us from launching multiple simultaneous attempts to connect to the + * same rend point. */ + replaycache_t *replay_cache_rend_cookie; } hs_service_state_t; /* Representation of a service running on this tor instance. */ |