diff options
-rw-r--r-- | src/or/hs_cell.c | 35 | ||||
-rw-r--r-- | src/or/hs_cell.h | 7 | ||||
-rw-r--r-- | src/or/hs_circuit.c | 57 | ||||
-rw-r--r-- | src/or/hs_circuit.h | 5 | ||||
-rw-r--r-- | src/or/hs_service.c | 35 |
5 files changed, 135 insertions, 4 deletions
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c index 18d15fe0a6..68c201b890 100644 --- a/src/or/hs_cell.c +++ b/src/or/hs_cell.c @@ -18,6 +18,7 @@ #include "hs/cell_common.h" #include "hs/cell_establish_intro.h" #include "hs/cell_introduce1.h" +#include "hs/cell_rendezvous.h" /* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is * the cell content up to the ENCRYPTED section of length encoded_cell_len. @@ -500,3 +501,37 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, return ret; } +/* Build a RENDEZVOUS1 cell with the given rendezvous cookie and handshake + * info. The encoded cell is put in cell_out and the length of the data is + * returned. This can't fail. */ +ssize_t +hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie, + size_t rendezvous_cookie_len, + const uint8_t *rendezvous_handshake_info, + size_t rendezvous_handshake_info_len, + uint8_t *cell_out) +{ + ssize_t cell_len; + trn_cell_rendezvous1_t *cell; + + tor_assert(rendezvous_cookie); + tor_assert(rendezvous_handshake_info); + tor_assert(cell_out); + + cell = trn_cell_rendezvous1_new(); + /* Set the RENDEZVOUS_COOKIE. */ + memcpy(trn_cell_rendezvous1_getarray_rendezvous_cookie(cell), + rendezvous_cookie, rendezvous_cookie_len); + /* Set the HANDSHAKE_INFO. */ + trn_cell_rendezvous1_setlen_handshake_info(cell, + rendezvous_handshake_info_len); + memcpy(trn_cell_rendezvous1_getarray_handshake_info(cell), + rendezvous_handshake_info, rendezvous_handshake_info_len); + /* Encoding. */ + cell_len = trn_cell_rendezvous1_encode(cell_out, RELAY_PAYLOAD_SIZE, cell); + tor_assert(cell_len > 0); + + trn_cell_rendezvous1_free(cell); + return cell_len; +} + diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h index 901ff81aae..fb4950d519 100644 --- a/src/or/hs_cell.h +++ b/src/or/hs_cell.h @@ -47,10 +47,17 @@ typedef struct hs_cell_introduce2_data_t { smartlist_t *link_specifiers; } hs_cell_introduce2_data_t; +/* Build cell API. */ 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_build_rendezvous1(const uint8_t *rendezvous_cookie, + size_t rendezvous_cookie_len, + const uint8_t *rendezvous_handshake_info, + size_t rendezvous_handshake_info_len, + uint8_t *cell_out); +/* Parse cell API. */ ssize_t hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len); ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c index 7184e1e18a..22a2c33479 100644 --- a/src/or/hs_circuit.c +++ b/src/or/hs_circuit.c @@ -685,6 +685,63 @@ hs_circ_service_intro_has_opened(hs_service_t *service, return ret; } +/* Called when a service rendezvous point circuit is done building. Given the + * service and the circuit, this function will send a RENDEZVOUS1 cell on the + * circuit using the information in the circuit identifier. If the cell can't + * be sent, the circuit is closed. */ +void +hs_circ_service_rp_has_opened(const hs_service_t *service, + origin_circuit_t *circ) +{ + size_t payload_len; + uint8_t payload[RELAY_PAYLOAD_SIZE] = {0}; + + tor_assert(service); + tor_assert(circ); + tor_assert(circ->hs_ident); + + /* Some useful logging. */ + log_info(LD_REND, "Rendezvous circuit %u has opened with cookie %s " + "for service %s", + TO_CIRCUIT(circ)->n_circ_id, + hex_str((const char *) circ->hs_ident->rendezvous_cookie, + REND_COOKIE_LEN), + safe_str_client(service->onion_address)); + circuit_log_path(LOG_INFO, LD_REND, circ); + + /* This can't fail. */ + payload_len = hs_cell_build_rendezvous1( + circ->hs_ident->rendezvous_cookie, + sizeof(circ->hs_ident->rendezvous_cookie), + circ->hs_ident->rendezvous_handshake_info, + sizeof(circ->hs_ident->rendezvous_handshake_info), + payload); + + if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), + RELAY_COMMAND_RENDEZVOUS1, + (const char *) payload, payload_len, + circ->cpath->prev) < 0) { + /* On error, circuit is closed. */ + log_warn(LD_REND, "Unable to send RENDEZVOUS1 cell on circuit %u " + "for service %s", + TO_CIRCUIT(circ)->n_circ_id, + safe_str_client(service->onion_address)); + goto done; + } + + /* Setup end-to-end rendezvous circuit between the client and us. */ + if (hs_circuit_setup_e2e_rend_circ(circ, + circ->hs_ident->rendezvous_ntor_key_seed, + sizeof(circ->hs_ident->rendezvous_ntor_key_seed), + 1) < 0) { + log_warn(LD_GENERAL, "Failed to setup circ"); + goto done; + } + + done: + memwipe(payload, 0, sizeof(payload)); +} + /* 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. */ diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h index 1cada0b8a6..ca8f1b2f6a 100644 --- a/src/or/hs_circuit.h +++ b/src/or/hs_circuit.h @@ -20,6 +20,8 @@ int hs_circ_service_intro_has_opened(hs_service_t *service, hs_service_intro_point_t *ip, const hs_service_descriptor_t *desc, origin_circuit_t *circ); +void hs_circ_service_rp_has_opened(const hs_service_t *service, + origin_circuit_t *circ); int hs_circ_launch_intro_point(hs_service_t *service, const hs_service_intro_point_t *ip, extend_info_t *ei, time_t now); @@ -28,9 +30,6 @@ int hs_circ_launch_rendezvous_point(const hs_service_t *service, const uint8_t *rendezvous_cookie); /* Cell API. */ -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, diff --git a/src/or/hs_service.c b/src/or/hs_service.c index 83b8b507f0..a2ab0629a8 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -1782,11 +1782,44 @@ service_intro_circ_has_opened(origin_circuit_t *circ) return; } +/* Called when a rendezvous circuit is done building and ready to be used. */ static void service_rendezvous_circ_has_opened(origin_circuit_t *circ) { + hs_service_t *service = NULL; + tor_assert(circ); - /* XXX: Implement rendezvous support. */ + tor_assert(circ->cpath); + /* Getting here means this is a v3 intro circuit. */ + tor_assert(circ->hs_ident); + tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); + + /* Declare the circuit dirty to avoid reuse, and for path-bias */ + if (!TO_CIRCUIT(circ)->timestamp_dirty) + TO_CIRCUIT(circ)->timestamp_dirty = time(NULL); + pathbias_count_use_attempt(circ); + + /* Get the corresponding service and intro point. */ + get_objects_from_ident(circ->hs_ident, &service, NULL, NULL); + if (service == NULL) { + log_warn(LD_REND, "Unknown service identity key %s on the rendezvous " + "circuit %u with cookie %s. Can't find onion service.", + safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)), + TO_CIRCUIT(circ)->n_circ_id, + hex_str((const char *) circ->hs_ident->rendezvous_cookie, + REND_COOKIE_LEN)); + goto err; + } + + /* If the cell can't be sent, the circuit will be closed within this + * function. */ + hs_circ_service_rp_has_opened(service, circ); + goto done; + + err: + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOSUCHSERVICE); + done: + return; } /* Handle an INTRO_ESTABLISHED cell arriving on the given introduction |