/** Process a 'destroy' <b>cell</b> that just arrived from * <b>conn</b>. Find the circ that it refers to (if any). * * If the circ is in state * onionskin_pending, then call onion_pending_remove() to remove it * from the pending onion list (note that if it's already being * processed by the cpuworker, it won't be in the list anymore; but * when the cpuworker returns it, the circuit will be gone, and the * cpuworker response will be dropped). * * Then mark the circuit for close (which marks all edges for close, * and passes the destroy cell onward if necessary). */ static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn) { circuit_t *circ; int reason; circ = circuit_get_by_circid_orconn(cell->circ_id, conn); reason = (uint8_t)cell->payload[0]; if (!circ) { log_info(LD_OR,"unknown circuit %d on connection from %s:%d. Dropping.", cell->circ_id, conn->_base.address, conn->_base.port); return; } log_debug(LD_OR,"Received for circID %d.",cell->circ_id); if (!CIRCUIT_IS_ORIGIN(circ) && cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) { /* the destroy came from behind */ circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL); circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); } else { /* the destroy came from ahead */ circuit_set_n_circid_orconn(circ, 0, NULL); if (CIRCUIT_IS_ORIGIN(circ)) { circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE); } else { char payload[1]; log_debug(LD_OR, "Delivering 'truncated' back."); payload[0] = (char)reason; relay_send_command_from_edge(0, circ, RELAY_COMMAND_TRUNCATED, payload, sizeof(payload), NULL); } } }
/** Allocate a new or_circuit_t, connected to <b>p_conn</b> as * <b>p_circ_id</b>. If <b>p_conn</b> is NULL, the circuit is unattached. */ or_circuit_t * or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn) { /* CircIDs */ or_circuit_t *circ; circ = tor_malloc_zero(sizeof(or_circuit_t)); circ->_base.magic = OR_CIRCUIT_MAGIC; if (p_conn) circuit_set_p_circid_orconn(circ, p_circ_id, p_conn); circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; init_circuit_base(TO_CIRCUIT(circ)); /* Initialize the cell_ewma_t structure */ /* Initialize the cell counts to 0 */ circ->p_cell_ewma.cell_count = 0.0; circ->p_cell_ewma.last_adjusted_tick = cell_ewma_get_tick(); circ->p_cell_ewma.is_for_p_conn = 1; /* It's not in any heap yet. */ circ->p_cell_ewma.heap_index = -1; return circ; }
/** Allocate a new or_circuit_t, connected to <b>p_conn</b> as * <b>p_circ_id</b>. If <b>p_conn</b> is NULL, the circuit is unattached. */ or_circuit_t * or_circuit_new(circid_t p_circ_id, or_connection_t *p_conn) { /* CircIDs */ or_circuit_t *circ; circ = tor_malloc_zero(sizeof(or_circuit_t)); circ->_base.magic = OR_CIRCUIT_MAGIC; if (p_conn) circuit_set_p_circid_orconn(circ, p_circ_id, p_conn); circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; init_circuit_base(TO_CIRCUIT(circ)); return circ; }
/** For each circuit that has <b>conn</b> as n_conn or p_conn, unlink the * circuit from the orconn,circid map, and mark it for close if it hasn't * been marked already. */ void circuit_unlink_all_from_or_conn(or_connection_t *conn, int reason) { circuit_t *circ; connection_or_unlink_all_active_circs(conn); for (circ = global_circuitlist; circ; circ = circ->next) { int mark = 0; if (circ->n_conn == conn) { circuit_set_n_circid_orconn(circ, 0, NULL); mark = 1; } if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); if (or_circ->p_conn == conn) { circuit_set_p_circid_orconn(or_circ, 0, NULL); mark = 1; } } if (mark && !circ->marked_for_close) circuit_mark_for_close(circ, reason); } }
/** Deallocate space associated with circ. */ static void circuit_free(circuit_t *circ) { void *mem; size_t memlen; tor_assert(circ); if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); mem = ocirc; memlen = sizeof(origin_circuit_t); tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); if (ocirc->build_state) { if (ocirc->build_state->chosen_exit) extend_info_free(ocirc->build_state->chosen_exit); if (ocirc->build_state->pending_final_cpath) circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); } tor_free(ocirc->build_state); circuit_free_cpath(ocirc->cpath); if (ocirc->intro_key) crypto_free_pk_env(ocirc->intro_key); if (ocirc->rend_data) rend_data_free(ocirc->rend_data); } else { or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); mem = ocirc; memlen = sizeof(or_circuit_t); tor_assert(circ->magic == OR_CIRCUIT_MAGIC); if (ocirc->p_crypto) crypto_free_cipher_env(ocirc->p_crypto); if (ocirc->p_digest) crypto_free_digest_env(ocirc->p_digest); if (ocirc->n_crypto) crypto_free_cipher_env(ocirc->n_crypto); if (ocirc->n_digest) crypto_free_digest_env(ocirc->n_digest); if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC); other->rend_splice = NULL; } /* remove from map. */ circuit_set_p_circid_orconn(ocirc, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(ô->p_conn_cells); } if (circ->n_hop) extend_info_free(circ->n_hop); tor_free(circ->n_conn_onionskin); /* Remove from map. */ circuit_set_n_circid_orconn(circ, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(&circ->n_conn_cells); memset(circ, 0xAA, memlen); /* poison memory */ tor_free(mem); }
/** Deallocate space associated with circ. */ static void circuit_free(circuit_t *circ) { void *mem; size_t memlen; if (!circ) return; if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); mem = ocirc; memlen = sizeof(origin_circuit_t); tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); circuit_free_cpath(ocirc->cpath); crypto_pk_free(ocirc->intro_key); rend_data_free(ocirc->rend_data); tor_free(ocirc->dest_address); if (ocirc->socks_username) { memwipe(ocirc->socks_username, 0x12, ocirc->socks_username_len); tor_free(ocirc->socks_username); } if (ocirc->socks_password) { memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len); tor_free(ocirc->socks_password); } } else { or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); /* Remember cell statistics for this circuit before deallocating. */ if (get_options()->CellStatistics) rep_hist_buffer_stats_add_circ(circ, time(NULL)); mem = ocirc; memlen = sizeof(or_circuit_t); tor_assert(circ->magic == OR_CIRCUIT_MAGIC); crypto_cipher_free(ocirc->p_crypto); crypto_digest_free(ocirc->p_digest); crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC); other->rend_splice = NULL; } /* remove from map. */ circuit_set_p_circid_orconn(ocirc, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(ô->p_conn_cells); } extend_info_free(circ->n_hop); tor_free(circ->n_conn_onionskin); /* Remove from map. */ circuit_set_n_circid_orconn(circ, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(&circ->n_conn_cells); memwipe(mem, 0xAA, memlen); /* poison memory */ tor_free(mem); }