📄 rendservice.c
字号:
void
rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
{
origin_circuit_t *newcirc;
cpath_build_state_t *newstate, *oldstate;
tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
if (!oldcirc->build_state ||
oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
oldcirc->build_state->expiry_time < time(NULL)) {
log_info(LD_REND,
"Attempt to build circuit to %s for rendezvous has failed "
"too many times or expired; giving up.",
oldcirc->build_state ?
oldcirc->build_state->chosen_exit->nickname : "*unknown*");
return;
}
oldstate = oldcirc->build_state;
tor_assert(oldstate);
if (oldstate->pending_final_cpath == NULL) {
log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. "
"Initiator will retry.");
return;
}
log_info(LD_REND,"Reattempting rendezvous circuit to '%s'",
oldstate->chosen_exit->nickname);
newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
oldstate->chosen_exit,
CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
if (!newcirc) {
log_warn(LD_REND,"Couldn't relaunch rendezvous circuit to '%s'.",
oldstate->chosen_exit->nickname);
return;
}
newstate = newcirc->build_state;
tor_assert(newstate);
newstate->failure_count = oldstate->failure_count+1;
newstate->expiry_time = oldstate->expiry_time;
newstate->pending_final_cpath = oldstate->pending_final_cpath;
oldstate->pending_final_cpath = NULL;
memcpy(newcirc->rend_query, oldcirc->rend_query,
REND_SERVICE_ID_LEN_BASE32+1);
memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest,
DIGEST_LEN);
memcpy(newcirc->rend_cookie, oldcirc->rend_cookie,
REND_COOKIE_LEN);
newcirc->rend_desc_version = oldcirc->rend_desc_version;
}
/** Launch a circuit to serve as an introduction point for the service
* <b>service</b> at the introduction point <b>nickname</b>
*/
static int
rend_service_launch_establish_intro(rend_service_t *service,
rend_intro_point_t *intro)
{
origin_circuit_t *launched;
log_info(LD_REND,
"Launching circuit to introduction point %s for service %s",
escaped_safe_str(intro->extend_info->nickname),
service->service_id);
rep_hist_note_used_internal(time(NULL), 1, 0);
++service->n_intro_circuits_launched;
launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
intro->extend_info,
CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL);
if (!launched) {
log_info(LD_REND,
"Can't launch circuit to establish introduction at %s.",
escaped_safe_str(intro->extend_info->nickname));
return -1;
}
strlcpy(launched->rend_query, service->service_id,
sizeof(launched->rend_query));
memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN);
launched->rend_desc_version = service->descriptor_version;
if (service->descriptor_version == 2)
launched->intro_key = crypto_pk_dup_key(intro->intro_key);
if (launched->_base.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);
return 0;
}
/** Called when we're done building a circuit to an introduction point:
* sends a RELAY_ESTABLISH_INTRO cell.
*/
void
rend_service_intro_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
size_t len;
int r;
char buf[RELAY_PAYLOAD_SIZE];
char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
int reason = END_CIRC_REASON_TORPROTOCOL;
crypto_pk_env_t *intro_key;
tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
tor_assert(circuit->cpath);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_pk_digest, REND_SERVICE_ID_LEN);
service = rend_service_get_by_pk_digest_and_version(
circuit->rend_pk_digest, circuit->rend_desc_version);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
serviceid, circuit->_base.n_circ_id);
reason = END_CIRC_REASON_NOSUCHSERVICE;
goto err;
}
log_info(LD_REND,
"Established circuit %d as introduction point for service %s",
circuit->_base.n_circ_id, serviceid);
/* If the introduction point will not be used in an unversioned
* descriptor, use the intro key instead of the service key in
* ESTABLISH_INTRO. */
if (service->descriptor_version == 0)
intro_key = service->private_key;
else
intro_key = circuit->intro_key;
/* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
r = crypto_pk_asn1_encode(intro_key, buf+2,
RELAY_PAYLOAD_SIZE-2);
if (r < 0) {
log_warn(LD_BUG, "Internal error; failed to establish intro point.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
len = r;
set_uint16(buf, htons((uint16_t)len));
len += 2;
memcpy(auth, circuit->cpath->prev->handshake_digest, DIGEST_LEN);
memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
if (crypto_digest(buf+len, auth, DIGEST_LEN+9))
goto err;
len += 20;
note_crypto_pk_op(REND_SERVER);
r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len);
if (r<0) {
log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
len += r;
if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit),
RELAY_COMMAND_ESTABLISH_INTRO,
buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL,
"Couldn't send introduction request for service %s on circuit %d",
serviceid, circuit->_base.n_circ_id);
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
return;
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
}
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
* live introduction point, and note that the service descriptor is
* now out-of-date.*/
int
rend_service_intro_established(origin_circuit_t *circuit, const char *request,
size_t request_len)
{
rend_service_t *service;
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
(void) request;
(void) request_len;
if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
}
service = rend_service_get_by_pk_digest_and_version(
circuit->rend_pk_digest, circuit->rend_desc_version);
if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %d.",
circuit->_base.n_circ_id);
goto err;
}
service->desc_is_dirty = time(NULL);
circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32 + 1,
circuit->rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
"Received INTRO_ESTABLISHED cell on circuit %d for service %s",
circuit->_base.n_circ_id, serviceid);
return 0;
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_TORPROTOCOL);
return -1;
}
/** Called once a circuit to a rendezvous point is established: sends a
* RELAY_COMMAND_RENDEZVOUS1 cell.
*/
void
rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
char buf[RELAY_PAYLOAD_SIZE];
crypt_path_t *hop;
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
char hexcookie[9];
int reason;
tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
hop = circuit->build_state->pending_final_cpath;
tor_assert(hop);
base16_encode(hexcookie,9,circuit->rend_cookie,4);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_pk_digest, REND_SERVICE_ID_LEN);
log_info(LD_REND,
"Done building circuit %d to rendezvous with "
"cookie %s for service %s",
circuit->_base.n_circ_id, hexcookie, serviceid);
service = rend_service_get_by_pk_digest_and_version(
circuit->rend_pk_digest, circuit->rend_desc_version);
if (!service) {
log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
"introduction circuit.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
/* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN);
if (crypto_dh_get_public(hop->dh_handshake_state,
buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
log_warn(LD_GENERAL,"Couldn't get DH public key.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->handshake_digest,
DIGEST_LEN);
/* Send the cell */
if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit),
RELAY_COMMAND_RENDEZVOUS1,
buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
circuit->cpath->prev)<0) {
log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
reason = END_CIRC_REASON_INTERNAL;
goto err;
}
crypto_dh_free(hop->dh_handshake_state);
hop->dh_handshake_state = NULL;
/* Append the cpath entry. */
hop->state = CPATH_STATE_OPEN;
/* set the windows to default. these are the windows
* that bob thinks alice has.
*/
hop->package_window = CIRCWINDOW_START;
hop->deliver_window = CIRCWINDOW_START;
onion_append_to_cpath(&circuit->cpath, hop);
circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
/* Change the circuit purpose. */
circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
return;
err:
circuit_mark_for_close(TO_CIRCUIT(circuit), reason);
}
/*
* Manage introduction points
*/
/** Return the (possibly non-open) introduction circuit ending at
* <b>intro</b> for the service whose public key is <b>pk_digest</b> and
* which publishes descriptor of version <b>desc_version</b>. Return
* NULL if no such service is found.
*/
static origin_circuit_t *
find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest,
int desc_version)
{
origin_circuit_t *circ = NULL;
tor_assert(intro);
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) {
if (!strcasecmp(circ->build_state->chosen_exit->identity_digest,
intro->extend_info->identity_digest) &&
circ->rend_desc_version == desc_version) {
return circ;
}
}
circ = NULL;
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
if (!strcasecmp(circ->build_state->chosen_exit->identity_digest,
intro->extend_info->identity_digest) &&
circ->rend_desc_version == desc_version) {
return circ;
}
}
return NULL;
}
/** Determine the responsible hidden service directories for the
* rend_encoded_v2_service_descriptor_t's in <b>descs</b> and upload them;
* <b>service_id</b> and <b>seconds_valid</b> are only passed for logging
* purposes. */
static void
directory_post_to_hs_dir(smartlist_t *descs, const char *service_id,
int seconds_valid)
{
int i, j;
smartlist_t *responsible_dirs = smartlist_create();
routerstatus_t *hs_dir;
for (i = 0; i < smartlist_len(descs); i++) {
rend_encoded_v2_service_descriptor_t *desc = smartlist_get(descs, i);
/* Determine responsible dirs. */
if (hid_serv_get_responsible_directories(responsible_dirs,
desc->desc_id) < 0) {
log_warn(LD_REND, "Could not determine the responsible hidden service "
"directories to post descriptors to.");
smartlist_free(responsible_dirs);
return;
}
for (j = 0; j < smartlist_len(responsible_dirs); j++) {
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
hs_dir = smartlist_get(responsible_dirs, j);
/* Send publish request. */
directory_initiate_command_routerstatus(hs_dir,
DIR_PURPOSE_UPLOAD_RENDDESC_V2,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -