diff options
author | David Goulet <dgoulet@torproject.org> | 2017-03-07 14:33:03 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-08-08 20:29:33 -0400 |
commit | 79e8d113d5ebfbc5ccf76f5db7bc0259a29520fc (patch) | |
tree | 51fe87267864641b0855d2ded4c7164517b876bd /src/or | |
parent | d765cf30b51dfcd58756b6b3d24a14ac2c47f3e8 (diff) | |
download | tor-79e8d113d5ebfbc5ccf76f5db7bc0259a29520fc.tar.gz tor-79e8d113d5ebfbc5ccf76f5db7bc0259a29520fc.zip |
prop224: Handle service INTRO_ESTABLISHED cell
Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/hs_cell.c | 22 | ||||
-rw-r--r-- | src/or/hs_cell.h | 3 | ||||
-rw-r--r-- | src/or/hs_circuit.c | 42 | ||||
-rw-r--r-- | src/or/hs_circuit.h | 5 | ||||
-rw-r--r-- | src/or/hs_service.c | 99 | ||||
-rw-r--r-- | src/or/hs_service.h | 3 | ||||
-rw-r--r-- | src/or/rendcommon.c | 2 |
7 files changed, 168 insertions, 8 deletions
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c index e15f4e3e55..0d34ef5965 100644 --- a/src/or/hs_cell.c +++ b/src/or/hs_cell.c @@ -161,3 +161,25 @@ hs_cell_build_establish_intro(const char *circ_nonce, return cell_len; } +/* Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we + * are successful at parsing it, return the length of the parsed cell else a + * negative value on error. */ +ssize_t +hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len) +{ + ssize_t ret; + trn_cell_intro_established_t *cell = NULL; + + tor_assert(payload); + + /* Try to parse the payload into a cell making sure we do actually have a + * valid cell. */ + ret = trn_cell_intro_established_parse(&cell, payload, payload_len); + if (ret >= 0) { + /* On success, we do not keep the cell, we just notify the caller that it + * was successfully parsed. */ + trn_cell_intro_established_free(cell); + } + return ret; +} + diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h index 9cc6109ebf..8e34028896 100644 --- a/src/or/hs_cell.h +++ b/src/or/hs_cell.h @@ -15,5 +15,8 @@ ssize_t hs_cell_build_establish_intro(const char *circ_nonce, const hs_service_intro_point_t *ip, uint8_t *cell_out); +ssize_t hs_cell_parse_intro_established(const uint8_t *payload, + size_t payload_len); + #endif /* TOR_HS_CELL_H */ diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index 01fd864839..51c07c0ba7 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -428,6 +428,46 @@ hs_circ_service_intro_has_opened(hs_service_t *service, return ret; } +/* Handle an INTRO_ESTABLISHED cell payload of length payload_len arriving on + * the given introduction circuit circ. The service is only used for logging + * purposes. Return 0 on success else a negative value. */ +int +hs_circ_handle_intro_established(const hs_service_t *service, + const hs_service_intro_point_t *ip, + origin_circuit_t *circ, + const uint8_t *payload, size_t payload_len) +{ + int ret = -1; + + tor_assert(service); + tor_assert(ip); + tor_assert(circ); + tor_assert(payload); + + /* Try to parse the payload into a cell making sure we do actually have a + * valid cell. For a legacy node, it's an empty payload so as long as we + * have the cell, we are good. */ + if (!ip->base.is_only_legacy && + hs_cell_parse_intro_established(payload, payload_len) < 0) { + log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on " + "circuit %u for service %s", + TO_CIRCUIT(circ)->n_circ_id, + safe_str_client(service->onion_address)); + goto done; + } + + /* Switch the purpose to a fully working intro point. */ + circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_S_INTRO); + /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully used the + * circuit so update our pathbias subsystem. */ + pathbias_mark_use_success(circ); + /* Success. */ + ret = 0; + + done: + return ret; +} + /* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key * exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to * serve as a rendezvous end-to-end circuit between the client and the @@ -435,7 +475,7 @@ hs_circ_service_intro_has_opened(hs_service_t *service, * and the other side is the client. * * Return 0 if the operation went well; in case of error return -1. */ - int +int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ, const uint8_t *ntor_key_seed, size_t seed_len, int is_service_side) diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h index 35eab75695..bc29781d8f 100644 --- a/src/or/hs_circuit.h +++ b/src/or/hs_circuit.h @@ -28,6 +28,11 @@ int hs_circ_launch_intro_point(hs_service_t *service, void hs_circ_send_establish_intro(const hs_service_t *service, hs_service_intro_point_t *ip, origin_circuit_t *circ); +int hs_circ_handle_intro_established(const hs_service_t *service, + const hs_service_intro_point_t *ip, + origin_circuit_t *circ, + const uint8_t *payload, + size_t payload_len); /* e2e circuit API. */ diff --git a/src/or/hs_service.c b/src/or/hs_service.c index 4cd808133c..5edfdd5b31 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -1725,14 +1725,8 @@ service_intro_circ_has_opened(origin_circuit_t *circ) goto err; } - /* From the service object, get the intro point object of that circuit. The - * following will query both descriptors intro points list. */ ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk); if (ip == NULL) { - log_warn(LD_REND, "Unknown authentication key on the introduction " - "circuit %u for service %s", - TO_CIRCUIT(circ)->n_circ_id, - safe_str_client(service->onion_address)); /* Closing this circuit because we don't recognize the key. */ close_reason = END_CIRC_REASON_NOSUCHSERVICE; goto err; @@ -1764,10 +1758,103 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ) /* XXX: Implement rendezvous support. */ } +/* Handle an INTRO_ESTABLISHED cell arriving on the given introduction + * circuit. Return 0 on success else a negative value. */ +static int +service_handle_intro_established(origin_circuit_t *circ, + const uint8_t *payload, + size_t payload_len) +{ + hs_service_t *service = NULL; + hs_service_intro_point_t *ip = NULL; + + tor_assert(circ); + tor_assert(payload); + tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); + + /* Get service object from the circuit identifier. */ + service = find_service(hs_service_map, &circ->hs_ident->identity_pk); + if (service == NULL) { + log_warn(LD_REND, "Unknown service identity key %s on the introduction " + "circuit %u. Can't find onion service.", + safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)), + TO_CIRCUIT(circ)->n_circ_id); + goto err; + } + + /* From the service object, get the intro point object of that circuit. The + * following will query both descriptors intro points list. */ + ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk); + if (ip == NULL) { + /* We don't recognize the key. */ + log_warn(LD_REND, "Introduction circuit established without an intro " + "point object on circuit %u for service %s", + TO_CIRCUIT(circ)->n_circ_id, + safe_str_client(service->onion_address)); + goto err; + } + + /* Try to parse the payload into a cell making sure we do actually have a + * valid cell. On success, the ip object is updated. */ + if (hs_circ_handle_intro_established(service, ip, circ, payload, + payload_len) < 0) { + goto err; + } + + /* Flag that we have an established circuit for this intro point. This value + * is what indicates the upload scheduled event if we are ready to build the + * intro point into the descriptor and upload. */ + ip->circuit_established = 1; + + log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell " + "on circuit %u for service %s", + TO_CIRCUIT(circ)->n_circ_id, + safe_str_client(service->onion_address)); + return 0; + + err: + return -1; +} + /* ========== */ /* Public API */ /* ========== */ +/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an + * established introduction point. Return 0 on success else a negative value + * and the circuit is closed. */ +int +hs_service_receive_intro_established(origin_circuit_t *circ, + const uint8_t *payload, + size_t payload_len) +{ + int ret = -1; + + tor_assert(circ); + tor_assert(payload); + + if (TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) { + log_warn(LD_PROTOCOL, "Received an INTRO_ESTABLISHED cell on a " + "non introduction circuit of purpose %d", + TO_CIRCUIT(circ)->purpose); + goto err; + } + + /* Handle both version. v2 uses rend_data and v3 uses the hs circuit + * identifier hs_ident. Can't be both. */ + ret = (circ->hs_ident) ? service_handle_intro_established(circ, payload, + payload_len) : + rend_service_intro_established(circ, payload, + payload_len); + if (ret < 0) { + goto err; + } + return 0; + err: + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); + return -1; +} + /* Called when any kind of hidden service circuit is done building thus * opened. This is the entry point from the circuit subsystem. */ void diff --git a/src/or/hs_service.h b/src/or/hs_service.h index 96df09493e..3de96d64e0 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -232,6 +232,9 @@ int hs_service_load_all_keys(void); void hs_service_run_scheduled_events(time_t now); void hs_service_circuit_has_opened(origin_circuit_t *circ); +int hs_service_receive_intro_established(origin_circuit_t *circ, + const uint8_t *payload, + size_t payload_len); /* These functions are only used by unit tests and we need to expose them else * hs_service.o ends up with no symbols in libor.a which makes clang throw a diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 986bfde75f..2cd66cb9ce 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -793,7 +793,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, break; case RELAY_COMMAND_INTRO_ESTABLISHED: if (origin_circ) - r = rend_service_intro_established(origin_circ,payload,length); + r = hs_service_receive_intro_established(origin_circ,payload,length); break; case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED: if (origin_circ) |