/** A helper function for circuit_dump_by_conn() below. Log a bunch * of information about circuit <b>circ</b>. */ static void circuit_dump_details(int severity, circuit_t *circ, int conn_array_index, const char *type, int this_circid, int other_circid) { log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " "state %d (%s), born %d:", conn_array_index, type, this_circid, other_circid, circ->state, circuit_state_to_string(circ->state), (int)circ->timestamp_created); if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); } }
/* 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); /* Pad the payload with random bytes so it matches the size of a legacy cell * which is normally always bigger. Also, the size of a legacy cell is * always smaller than the RELAY_PAYLOAD_SIZE so this is safe. */ if (payload_len < HS_LEGACY_RENDEZVOUS_CELL_SIZE) { crypto_rand((char *) payload + payload_len, HS_LEGACY_RENDEZVOUS_CELL_SIZE - payload_len); payload_len = HS_LEGACY_RENDEZVOUS_CELL_SIZE; } 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)); }
/* Called when a service introduction point circuit is done building. Given * the service and intro point object, this function will send the * ESTABLISH_INTRO cell on the circuit. Return 0 on success. Return 1 if the * circuit has been repurposed to General because we already have too many * opened. */ 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) { int ret = 0; unsigned int num_intro_circ, num_needed_circ; tor_assert(service); tor_assert(ip); tor_assert(desc); tor_assert(circ); /* Cound opened circuits that have sent ESTABLISH_INTRO cells or are already * established introduction circuits */ num_intro_circ = count_opened_desc_intro_point_circuits(service, desc); num_needed_circ = service->config.num_intro_points; if (num_intro_circ > num_needed_circ) { /* There are too many opened valid intro circuit for what the service * needs so repurpose this one. */ /* XXX: Legacy code checks options->ExcludeNodes and if not NULL it just * closes the circuit. I have NO idea why it does that so it hasn't been * added here. I can only assume in case our ExcludeNodes list changes but * in that case, all circuit are flagged unusable (config.c). --dgoulet */ log_info(LD_CIRC | LD_REND, "Introduction circuit just opened but we " "have enough for service %s. Repurposing " "it to general and leaving internal.", safe_str_client(service->onion_address)); tor_assert(circ->build_state->is_internal); /* Remove it from the circuitmap. */ hs_circuitmap_remove_circuit(TO_CIRCUIT(circ)); /* Cleaning up the hidden service identifier and repurpose. */ hs_ident_circuit_free(circ->hs_ident); circ->hs_ident = NULL; if (circuit_should_use_vanguards(TO_CIRCUIT(circ)->purpose)) circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_HS_VANGUARDS); else circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_GENERAL); /* Inform that this circuit just opened for this new purpose. */ circuit_has_opened(circ); /* This return value indicate to the caller that the IP object should be * removed from the service because it's corresponding circuit has just * been repurposed. */ ret = 1; goto done; } log_info(LD_REND, "Introduction circuit %u established for service %s.", TO_CIRCUIT(circ)->n_circ_id, safe_str_client(service->onion_address)); circuit_log_path(LOG_INFO, LD_REND, circ); /* Time to send an ESTABLISH_INTRO cell on this circuit. On error, this call * makes sure the circuit gets closed. */ send_establish_intro(service, ip, circ); done: return ret; }