📄 rendservice.c
字号:
ROUTER_PURPOSE_GENERAL,
1, NULL, desc->desc_str,
strlen(desc->desc_str), 0);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc->desc_id, DIGEST_LEN);
log_info(LD_REND, "Sending publish request for v2 descriptor for "
"service '%s' with descriptor ID '%s' with validity "
"of %d seconds to hidden service directory '%s' on "
"port %d.",
safe_str(service_id),
safe_str(desc_id_base32),
seconds_valid,
hs_dir->nickname,
hs_dir->dir_port);
}
smartlist_clear(responsible_dirs);
}
smartlist_free(responsible_dirs);
}
/** Encode and sign up-to-date v0 and/or v2 service descriptors for
* <b>service</b>, and upload it/them to all the dirservers/to the
* responsible hidden service directories.
*/
static void
upload_service_descriptor(rend_service_t *service)
{
time_t now = time(NULL);
int rendpostperiod;
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
int uploaded = 0;
/* Update the descriptor. */
rend_service_update_descriptor(service);
rendpostperiod = get_options()->RendPostPeriod;
/* Upload unversioned (v0) descriptor? */
if (service->descriptor_version == 0 &&
get_options()->PublishHidServDescriptors) {
char *desc;
size_t desc_len;
/* Encode the descriptor. */
if (rend_encode_service_descriptor(service->desc,
service->private_key,
&desc, &desc_len)<0) {
log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; "
"not uploading.");
return;
}
/* Post it to the dirservers */
rend_get_service_id(service->desc->pk, serviceid);
log_info(LD_REND, "Sending publish request for hidden service %s",
serviceid);
directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_RENDDESC,
ROUTER_PURPOSE_GENERAL,
HIDSERV_AUTHORITY, desc, desc_len, 0);
tor_free(desc);
service->next_upload_time = now + rendpostperiod;
uploaded = 1;
}
/* Upload v2 descriptor? */
if (service->descriptor_version == 2 &&
get_options()->PublishHidServDescriptors) {
networkstatus_t *c = networkstatus_get_latest_consensus();
if (c && smartlist_len(c->routerstatus_list) > 0) {
int seconds_valid;
smartlist_t *descs = smartlist_create();
int i;
/* Encode the current descriptor. */
seconds_valid = rend_encode_v2_descriptors(descs, service->desc, now,
NULL, 0);
if (seconds_valid < 0) {
log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; "
"not uploading.");
smartlist_free(descs);
return;
}
/* Post the current descriptors to the hidden service directories. */
rend_get_service_id(service->desc->pk, serviceid);
log_info(LD_REND, "Sending publish request for hidden service %s",
serviceid);
directory_post_to_hs_dir(descs, serviceid, seconds_valid);
/* Free memory for descriptors. */
for (i = 0; i < smartlist_len(descs); i++)
rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
smartlist_clear(descs);
/* Update next upload time. */
if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
> rendpostperiod)
service->next_upload_time = now + rendpostperiod;
else if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS)
service->next_upload_time = now + seconds_valid + 1;
else
service->next_upload_time = now + seconds_valid -
REND_TIME_PERIOD_OVERLAPPING_V2_DESCS + 1;
/* Post also the next descriptors, if necessary. */
if (seconds_valid < REND_TIME_PERIOD_OVERLAPPING_V2_DESCS) {
seconds_valid = rend_encode_v2_descriptors(descs, service->desc,
now, NULL, 1);
if (seconds_valid < 0) {
log_warn(LD_BUG, "Internal error: couldn't encode service "
"descriptor; not uploading.");
smartlist_free(descs);
return;
}
directory_post_to_hs_dir(descs, serviceid, seconds_valid);
/* Free memory for descriptors. */
for (i = 0; i < smartlist_len(descs); i++)
rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
}
smartlist_free(descs);
uploaded = 1;
log_info(LD_REND, "Successfully uploaded v2 rend descriptors!");
}
}
/* If not uploaded, try again in one minute. */
if (!uploaded)
service->next_upload_time = now + 60;
/* Unmark dirty flag of this service. */
service->desc_is_dirty = 0;
}
/** For every service, check how many intro points it currently has, and:
* - Pick new intro points as necessary.
* - Launch circuits to any new intro points.
*/
void
rend_services_introduce(void)
{
int i,j,r;
routerinfo_t *router;
rend_service_t *service;
rend_intro_point_t *intro;
int changed, prev_intro_nodes;
smartlist_t *intro_routers, *exclude_routers;
time_t now;
intro_routers = smartlist_create();
exclude_routers = smartlist_create();
now = time(NULL);
for (i=0; i < smartlist_len(rend_service_list); ++i) {
smartlist_clear(intro_routers);
service = smartlist_get(rend_service_list, i);
tor_assert(service);
changed = 0;
if (now > service->intro_period_started+INTRO_CIRC_RETRY_PERIOD) {
/* One period has elapsed; we can try building circuits again. */
service->intro_period_started = now;
service->n_intro_circuits_launched = 0;
} else if (service->n_intro_circuits_launched >=
MAX_INTRO_CIRCS_PER_PERIOD) {
/* We have failed too many times in this period; wait for the next
* one before we try again. */
continue;
}
/* Find out which introduction points we have in progress for this
service. */
for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
intro = smartlist_get(service->intro_nodes, j);
router = router_get_by_digest(intro->extend_info->identity_digest);
if (!router || !find_intro_circuit(intro, service->pk_digest,
service->descriptor_version)) {
log_info(LD_REND,"Giving up on %s as intro point for %s.",
intro->extend_info->nickname, service->service_id);
rend_intro_point_free(intro);
smartlist_del(service->intro_nodes,j--);
changed = 1;
service->desc_is_dirty = now;
}
smartlist_add(intro_routers, router);
}
/* We have enough intro points, and the intro points we thought we had were
* all connected.
*/
if (!changed && smartlist_len(service->intro_nodes) >= NUM_INTRO_POINTS) {
/* We have all our intro points! Start a fresh period and reset the
* circuit count. */
service->intro_period_started = now;
service->n_intro_circuits_launched = 0;
continue;
}
/* Remember how many introduction circuits we started with. */
prev_intro_nodes = smartlist_len(service->intro_nodes);
smartlist_add_all(exclude_routers, intro_routers);
/* The directory is now here. Pick three ORs as intro points. */
for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) {
router = router_choose_random_node(service->intro_prefer_nodes,
service->intro_exclude_nodes, exclude_routers, 1, 0, 0,
get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION,
0, 0);
if (!router) {
log_warn(LD_REND,
"Could only establish %d introduction points for %s.",
smartlist_len(service->intro_nodes), service->service_id);
break;
}
changed = 1;
smartlist_add(intro_routers, router);
smartlist_add(exclude_routers, router);
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
intro->extend_info = extend_info_from_router(router);
if (service->descriptor_version == 2) {
intro->intro_key = crypto_new_pk_env();
tor_assert(!crypto_pk_generate_key(intro->intro_key));
}
smartlist_add(service->intro_nodes, intro);
log_info(LD_REND, "Picked router %s as an intro point for %s.",
router->nickname, service->service_id);
}
/* Reset exclude_routers, for the next time around the loop. */
smartlist_clear(exclude_routers);
/* If there's no need to launch new circuits, stop here. */
if (!changed)
continue;
/* Establish new introduction points. */
for (j=prev_intro_nodes; j < smartlist_len(service->intro_nodes); ++j) {
intro = smartlist_get(service->intro_nodes, j);
r = rend_service_launch_establish_intro(service, intro);
if (r<0) {
log_warn(LD_REND, "Error launching circuit to node %s for service %s.",
intro->extend_info->nickname, service->service_id);
}
}
}
smartlist_free(intro_routers);
smartlist_free(exclude_routers);
}
/** Regenerate and upload rendezvous service descriptors for all
* services, if necessary. If the descriptor has been dirty enough
* for long enough, definitely upload; else only upload when the
* periodic timeout has expired.
*
* For the first upload, pick a random time between now and two periods
* from now, and pick it independently for each service.
*/
void
rend_consider_services_upload(time_t now)
{
int i;
rend_service_t *service;
int rendpostperiod = get_options()->RendPostPeriod;
if (!get_options()->PublishHidServDescriptors)
return;
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
if (!service->next_upload_time) { /* never been uploaded yet */
service->next_upload_time =
now + crypto_rand_int(2*rendpostperiod);
}
if (service->next_upload_time < now ||
(service->desc_is_dirty &&
service->desc_is_dirty < now-30)) {
/* if it's time, or if the directory servers have a wrong service
* descriptor and ours has been stable for 30 seconds, upload a
* new one of each format. */
upload_service_descriptor(service);
}
}
}
/** Log the status of introduction points for all rendezvous services
* at log severity <b>severity</b>.
*/
void
rend_service_dump_stats(int severity)
{
int i,j;
rend_service_t *service;
rend_intro_point_t *intro;
const char *safe_name;
origin_circuit_t *circ;
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
log(severity, LD_GENERAL, "Service configured in \"%s\":",
service->directory);
for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
intro = smartlist_get(service->intro_nodes, j);
safe_name = safe_str(intro->extend_info->nickname);
circ = find_intro_circuit(intro, service->pk_digest,
service->descriptor_version);
if (!circ) {
log(severity, LD_GENERAL, " Intro point %d at %s: no circuit",
j, safe_name);
continue;
}
log(severity, LD_GENERAL, " Intro point %d at %s: circuit is %s",
j, safe_name, circuit_state_to_string(circ->_base.state));
}
}
}
/** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for
* 'circ', and look up the port and address based on conn-\>port.
* Assign the actual conn-\>addr and conn-\>port. Return -1 if failure,
* or 0 for success.
*/
int
rend_service_set_connection_addr_port(edge_connection_t *conn,
origin_circuit_t *circ)
{
rend_service_t *service;
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
smartlist_t *matching_ports;
rend_service_port_config_t *chosen_port;
tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circ->rend_pk_digest, REND_SERVICE_ID_LEN);
service = rend_service_get_by_pk_digest_and_version(circ->rend_pk_digest,
circ->rend_desc_version);
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %d; closing.",
serviceid, circ->_base.n_circ_id);
return -1;
}
matching_ports = smartlist_create();
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
{
if (conn->_base.port == p->virtual_port) {
smartlist_add(matching_ports, p);
}
});
chosen_port = smartlist_choose(matching_ports);
smartlist_free(matching_ports);
if (chosen_port) {
conn->_base.addr = chosen_port->real_addr;
conn->_base.port = chosen_port->real_port;
return 0;
}
log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
conn->_base.port,serviceid);
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -