📄 circuitbuild.c
字号:
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Wrong length %d on extend cell. Closing circuit.",
rh.length);
return -1;
}
circ->n_addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
circ->n_port = ntohs(get_uint16(cell->payload+RELAY_HEADER_SIZE+4));
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2;
id_digest = cell->payload+RELAY_HEADER_SIZE+4+2+ONIONSKIN_CHALLENGE_LEN;
n_conn = connection_or_get_by_identity_digest(id_digest);
/* If we don't have an open conn, or the conn we have is obsolete
* (i.e. old or broken) and the other side will let us make a second
* connection without dropping it immediately... */
if (!n_conn || n_conn->_base.state != OR_CONN_STATE_OPEN ||
(n_conn->_base.or_is_obsolete &&
router_digest_version_as_new_as(id_digest,"0.1.1.9-alpha-cvs"))) {
struct in_addr in;
char tmpbuf[INET_NTOA_BUF_LEN];
in.s_addr = htonl(circ->n_addr);
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
log_debug(LD_CIRC|LD_OR,"Next router (%s:%d) not connected. Connecting.",
tmpbuf, circ->n_port);
circ->n_conn_onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
memcpy(circ->n_conn_onionskin, onionskin, ONIONSKIN_CHALLENGE_LEN);
circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
/* imprint the circuit with its future n_conn->id */
memcpy(circ->n_conn_id_digest, id_digest, DIGEST_LEN);
if (n_conn && !n_conn->_base.or_is_obsolete) {
circ->n_addr = n_conn->_base.addr;
circ->n_port = n_conn->_base.port;
} else {
/* we should try to open a connection */
n_conn = connection_or_connect(circ->n_addr, circ->n_port, id_digest);
if (!n_conn) {
log_info(LD_CIRC,"Launching n_conn failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
return 0;
}
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
}
/* return success. The onion/circuit/etc will be taken care of
* automatically (may already have been) whenever n_conn reaches
* OR_CONN_STATE_OPEN.
*/
return 0;
}
/* these may be different if the router connected to us from elsewhere */
circ->n_addr = n_conn->_base.addr;
circ->n_port = n_conn->_base.port;
circ->n_conn = n_conn;
memcpy(circ->n_conn_id_digest, n_conn->identity_digest, DIGEST_LEN);
log_debug(LD_CIRC,"n_conn is %s:%u",
n_conn->_base.address,n_conn->_base.port);
if (circuit_deliver_create_cell(circ, CELL_CREATE, onionskin) < 0)
return -1;
return 0;
}
/** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in
* key_data. key_data must contain CPATH_KEY_MATERIAL bytes, which are
* used as follows:
* - 20 to initialize f_digest
* - 20 to initialize b_digest
* - 16 to key f_crypto
* - 16 to key b_crypto
*
* (If 'reverse' is true, then f_XX and b_XX are swapped.)
*/
int
circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
int reverse)
{
crypto_digest_env_t *tmp_digest;
crypto_cipher_env_t *tmp_crypto;
tor_assert(cpath);
tor_assert(key_data);
tor_assert(!(cpath->f_crypto || cpath->b_crypto ||
cpath->f_digest || cpath->b_digest));
cpath->f_digest = crypto_new_digest_env();
crypto_digest_add_bytes(cpath->f_digest, key_data, DIGEST_LEN);
cpath->b_digest = crypto_new_digest_env();
crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN);
if (!(cpath->f_crypto =
crypto_create_init_cipher(key_data+(2*DIGEST_LEN),1))) {
log_warn(LD_BUG,"Forward cipher initialization failed.");
return -1;
}
if (!(cpath->b_crypto =
crypto_create_init_cipher(key_data+(2*DIGEST_LEN)+CIPHER_KEY_LEN,0))) {
log_warn(LD_BUG,"Backward cipher initialization failed.");
return -1;
}
if (reverse) {
tmp_digest = cpath->f_digest;
cpath->f_digest = cpath->b_digest;
cpath->b_digest = tmp_digest;
tmp_crypto = cpath->f_crypto;
cpath->f_crypto = cpath->b_crypto;
cpath->b_crypto = tmp_crypto;
}
return 0;
}
/** A created or extended cell came back to us on the circuit, and it included
* <b>reply</b> as its body. (If <b>reply_type</b> is CELL_CREATED, the body
* contains (the second DH key, plus KH). If <b>reply_type</b> is
* CELL_CREATED_FAST, the body contains a secret y and a hash H(x|y).)
*
* Calculate the appropriate keys and digests, make sure KH is
* correct, and initialize this hop of the cpath.
*
* Return - reason if we want to mark circ for close, else return 0.
*/
int
circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
const char *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
else {
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) { /* got an extended when we're all done? */
log_warn(LD_PROTOCOL,"got extended when circ already built? Closing.");
return - END_CIRC_REASON_TORPROTOCOL;
}
}
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
if (reply_type == CELL_CREATED && hop->dh_handshake_state) {
if (onion_skin_client_handshake(hop->dh_handshake_state, reply, keys,
DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
return -END_CIRC_REASON_TORPROTOCOL;
}
/* Remember hash of g^xy */
memcpy(hop->handshake_digest, reply+DH_KEY_LEN, DIGEST_LEN);
} else if (reply_type == CELL_CREATED_FAST && !hop->dh_handshake_state) {
if (fast_client_handshake(hop->fast_handshake_state, reply, keys,
DIGEST_LEN*2+CIPHER_KEY_LEN*2) < 0) {
log_warn(LD_CIRC,"fast_client_handshake failed.");
return -END_CIRC_REASON_TORPROTOCOL;
}
memcpy(hop->handshake_digest, reply+DIGEST_LEN, DIGEST_LEN);
} else {
log_warn(LD_PROTOCOL,"CREATED cell type did not match CREATE cell type.");
return -END_CIRC_REASON_TORPROTOCOL;
}
if (hop->dh_handshake_state) {
crypto_dh_free(hop->dh_handshake_state); /* don't need it anymore */
hop->dh_handshake_state = NULL;
}
memset(hop->fast_handshake_state, 0, sizeof(hop->fast_handshake_state));
if (circuit_init_cpath_crypto(hop, keys, 0)<0) {
return -END_CIRC_REASON_TORPROTOCOL;
}
hop->state = CPATH_STATE_OPEN;
log_info(LD_CIRC,"Finished building %scircuit hop:",
(reply_type == CELL_CREATED_FAST) ? "fast " : "");
circuit_log_path(LOG_INFO,LD_CIRC,circ);
control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
return 0;
}
/** We received a relay truncated cell on circ.
*
* Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up: for circ to close, and return 0.
*/
int
circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
{
// crypt_path_t *victim;
// connection_t *stream;
tor_assert(circ);
tor_assert(layer);
/* XXX Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up.
*/
circuit_mark_for_close(TO_CIRCUIT(circ),
END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_OR_CONN_CLOSED);
return 0;
#if 0
while (layer->next != circ->cpath) {
/* we need to clear out layer->next */
victim = layer->next;
log_debug(LD_CIRC, "Killing a layer of the cpath.");
for (stream = circ->p_streams; stream; stream=stream->next_stream) {
if (stream->cpath_layer == victim) {
log_info(LD_APP, "Marking stream %d for close because of truncate.",
stream->stream_id);
/* no need to send 'end' relay cells,
* because the other side's already dead
*/
connection_mark_unattached_ap(stream, END_STREAM_REASON_DESTROY);
}
}
layer->next = victim->next;
circuit_free_cpath_node(victim);
}
log_info(LD_CIRC, "finished");
return 0;
#endif
}
/** Given a response payload and keys, initialize, then send a created
* cell back.
*/
int
onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
const char *keys)
{
cell_t cell;
crypt_path_t *tmp_cpath;
tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
tmp_cpath->magic = CRYPT_PATH_MAGIC;
memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type;
cell.circ_id = circ->p_circ_id;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
memcpy(cell.payload, payload,
cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
(unsigned int)*(uint32_t*)(keys),
(unsigned int)*(uint32_t*)(keys+20));
if (circuit_init_cpath_crypto(tmp_cpath, keys, 0)<0) {
log_warn(LD_BUG,"Circuit initialization failed");
tor_free(tmp_cpath);
return -1;
}
circ->n_digest = tmp_cpath->f_digest;
circ->n_crypto = tmp_cpath->f_crypto;
circ->p_digest = tmp_cpath->b_digest;
circ->p_crypto = tmp_cpath->b_crypto;
tmp_cpath->magic = 0;
tor_free(tmp_cpath);
if (cell_type == CELL_CREATED)
memcpy(circ->handshake_digest, cell.payload+DH_KEY_LEN, DIGEST_LEN);
else
memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN);
circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
circ->p_conn, &cell, CELL_DIRECTION_IN);
log_debug(LD_CIRC,"Finished sending 'created' cell.");
if (!is_local_IP(circ->p_conn->_base.addr) &&
!connection_or_nonopen_was_started_here(circ->p_conn)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
router_orport_found_reachable();
}
return 0;
}
/** Choose a length for a circuit of purpose <b>purpose</b>.
* Default length is 3 + the number of endpoints that would give something
* away. If the routerlist <b>routers</b> doesn't have enough routers
* to handle the desired path length, return as large a path length as
* is feasible, except if it's less than 2, in which case return -1.
*/
static int
new_route_len(uint8_t purpose, extend_info_t *exit,
smartlist_t *routers)
{
int num_acceptable_routers;
int routelen;
tor_assert(routers);
routelen = 3;
if (exit &&
purpose != CIRCUIT_PURPOSE_TESTING &&
purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
routelen++;
log_debug(LD_CIRC,"Chosen route length %d (%d routers available).",
routelen, smartlist_len(routers));
num_acceptable_routers = count_acceptable_routers(routers);
if (num_acceptable_routers < 2) {
log_info(LD_CIRC,
"Not enough acceptable routers (%d). Discarding this circuit.",
num_acceptable_routers);
return -1;
}
if (num_acceptable_routers < routelen) {
log_info(LD_CIRC,"Not enough routers: cutting routelen from %d to %d.",
routelen, num_acceptable_routers);
routelen = num_acceptable_routers;
}
return routelen;
}
/** Fetch the list of predicted ports, dup it into a smartlist of
* uint16_t's, remove the ones that are already handled by an
* existing circuit, and return it.
*/
static smartlist_t *
circuit_get_unhandled_ports(time_t now)
{
smartlist_t *source = rep_hist_get_predicted_ports(now);
smartlist_t *dest = smartlist_create();
uint16_t *tmp;
int i;
for (i = 0; i < smartlist_len(source); ++i) {
tmp = tor_malloc(sizeof(uint16_t));
memcpy(tmp, smartlist_get(source, i), sizeof(uint16_t));
smartlist_add(dest, tmp);
}
circuit_remove_handled_ports(dest);
return dest;
}
/** Return 1 if we already have circuits present or on the way for
* all anticipated ports. Return 0 if we should make more.
*
* If we're returning 0, set need_uptime and need_capacity to
* indicate any requirements that the unhandled ports have.
*/
int
circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity)
{
int i, enough;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -