/** Send the establish-rendezvous cell along a rendezvous circuit. if * it fails, mark the circ for close and return -1. else return 0. */ static int rend_client_send_establish_rendezvous(origin_circuit_t *circ) { tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); tor_assert(circ->rend_data); log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell"); if (crypto_rand(circ->rend_data->rend_cookie, REND_COOKIE_LEN) < 0) { log_warn(LD_BUG, "Internal error: Couldn't produce random cookie."); circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); return -1; } /* Set timestamp_dirty, because circuit_expire_building expects it, * and the rend cookie also means we've used the circ. */ circ->base_.timestamp_dirty = time(NULL); /* We've attempted to use this circuit. Probe it if we fail */ pathbias_count_use_attempt(circ); if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_RENDEZVOUS, circ->rend_data->rend_cookie, REND_COOKIE_LEN, circ->cpath->prev)<0) { /* circ is already marked for close */ log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell"); return -1; } return 0; }
/* Send an ESTABLISH_RENDEZVOUS cell along the rendezvous circuit circ. On * success, 0 is returned else -1 and the circuit is marked for close. */ int hs_circ_send_establish_rendezvous(origin_circuit_t *circ) { ssize_t cell_len = 0; uint8_t cell[RELAY_PAYLOAD_SIZE] = {0}; tor_assert(circ); tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND); log_info(LD_REND, "Send an ESTABLISH_RENDEZVOUS cell on circuit %u", TO_CIRCUIT(circ)->n_circ_id); /* Set timestamp_dirty, because circuit_expire_building expects it, * and the rend cookie also means we've used the circ. */ TO_CIRCUIT(circ)->timestamp_dirty = time(NULL); /* We've attempted to use this circuit. Probe it if we fail */ pathbias_count_use_attempt(circ); /* Generate the RENDEZVOUS_COOKIE and place it in the identifier so we can * complete the handshake when receiving the acknowledgement. */ crypto_rand((char *) circ->hs_ident->rendezvous_cookie, HS_REND_COOKIE_LEN); /* Generate the client keypair. No need to be extra strong, not long term */ curve25519_keypair_generate(&circ->hs_ident->rendezvous_client_kp, 0); cell_len = hs_cell_build_establish_rendezvous(circ->hs_ident->rendezvous_cookie, cell); if (BUG(cell_len < 0)) { goto err; } if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_RENDEZVOUS, (const char *) cell, cell_len, circ->cpath->prev) < 0) { /* Circuit has been marked for close */ log_warn(LD_REND, "Unable to send ESTABLISH_RENDEZVOUS cell on " "circuit %u", TO_CIRCUIT(circ)->n_circ_id); memwipe(cell, 0, cell_len); goto err; } memwipe(cell, 0, cell_len); return 0; err: return -1; }
/* For a given introduction point and an introduction circuit, send the * ESTABLISH_INTRO cell. The service object is used for logging. This can fail * and if so, the circuit is closed and the intro point object is flagged * that the circuit is not established anymore which is important for the * retry mechanism. */ static void send_establish_intro(const hs_service_t *service, hs_service_intro_point_t *ip, origin_circuit_t *circ) { ssize_t cell_len; uint8_t payload[RELAY_PAYLOAD_SIZE]; tor_assert(service); tor_assert(ip); tor_assert(circ); /* Encode establish intro cell. */ cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce, ip, payload); if (cell_len < 0) { log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s " "on circuit %u. Closing circuit.", safe_str_client(service->onion_address), TO_CIRCUIT(circ)->n_circ_id); goto err; } /* Send the cell on the circuit. */ if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), RELAY_COMMAND_ESTABLISH_INTRO, (char *) payload, cell_len, circ->cpath->prev) < 0) { log_info(LD_REND, "Unable to send ESTABLISH_INTRO cell for service %s " "on circuit %u.", safe_str_client(service->onion_address), TO_CIRCUIT(circ)->n_circ_id); /* On error, the circuit has been closed. */ goto done; } /* Record the attempt to use this circuit. */ pathbias_count_use_attempt(circ); goto done; err: circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL); done: memwipe(payload, 0, sizeof(payload)); }