From 46783eb6d7f6668ccfad6c4c44021e606cccdbcb Mon Sep 17 00:00:00 2001 From: Robert Ransom Date: Tue, 13 Dec 2011 03:36:48 -0800 Subject: Extract function to determine how many intros an intro point has handled --- src/or/rendservice.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 177f3bf23c..0f22cdfe2b 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -28,6 +28,7 @@ static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest); static rend_intro_point_t *find_intro_point(origin_circuit_t *circ); +static int intro_point_accepted_intro_count(rend_intro_point_t *intro); static int intro_point_should_expire_now(rend_intro_point_t *intro, time_t now); @@ -1937,6 +1938,18 @@ upload_service_descriptor(rend_service_t *service) service->desc_is_dirty = 0; } +/** Return the number of INTRODUCE2 cells an intro point has + * received. */ +static int +intro_point_accepted_intro_count(rend_intro_point_t *intro) +{ + if (intro->accepted_intro_rsa_parts == NULL) { + return 0; + } else { + return digestmap_size(intro->accepted_intro_rsa_parts); + } +} + /** Return non-zero iff intro should 'expire' now (i.e. we * should stop publishing it in new descriptors and eventually close * it). */ @@ -1957,8 +1970,7 @@ intro_point_should_expire_now(rend_intro_point_t *intro, return 1; } - if (intro->accepted_intro_rsa_parts != NULL && - digestmap_size(intro->accepted_intro_rsa_parts) >= + if (intro_point_accepted_intro_count(intro) >= INTRO_POINT_LIFETIME_INTRODUCTIONS) { /* This intro point has been used too many times. Expire it now. */ return 1; -- cgit v1.2.3-54-g00ecf From dae000735e75b178cdf27000d316f6504bf61373 Mon Sep 17 00:00:00 2001 From: Robert Ransom Date: Tue, 13 Dec 2011 05:00:09 -0800 Subject: Adjust n_intro_points_wanted when a service's intro points are closed --- changes/bug3825b | 7 ++++ src/or/or.h | 5 +++ src/or/rendservice.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 changes/bug3825b (limited to 'src') diff --git a/changes/bug3825b b/changes/bug3825b new file mode 100644 index 0000000000..08c0c2de73 --- /dev/null +++ b/changes/bug3825b @@ -0,0 +1,7 @@ + o Major features: + + - Adjust the number of introduction points that a hidden service + will try to maintain based on how long its introduction points + remain in use and how many introductions they handle. Fixes + part of bug 3825. + diff --git a/src/or/or.h b/src/or/or.h index 6ff02ee36c..63ff5c4b31 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4114,6 +4114,11 @@ typedef struct rend_intro_point_t { * included in the last HS descriptor we generated. */ unsigned int listed_in_last_desc : 1; + /** (Service side only) Flag indicating that + * rend_service_note_removing_intro_point has been called for this + * intro point. */ + unsigned int rend_service_note_removing_intro_point_called : 1; + /** (Service side only) A digestmap recording the INTRODUCE2 cells * this intro point's circuit has received. Each key is the digest * of the RSA-encrypted part of a received INTRODUCE2 cell; each diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 0f22cdfe2b..646d423dae 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -116,6 +116,17 @@ num_rend_services(void) return smartlist_len(rend_service_list); } +/** Return a string identifying service, suitable for use in a + * log message. The result does not need to be freed, but may be + * overwritten by the next call to this function. */ +static const char * +rend_service_describe_for_log(rend_service_t *service) +{ + /* XXX024 Use this function throughout rendservice.c. */ + /* XXX024 Return a more useful description? */ + return safe_str_client(service->service_id); +} + /** Helper: free storage held by a single service authorized client entry. */ static void rend_authorized_client_free(rend_authorized_client_t *client) @@ -915,6 +926,104 @@ clean_accepted_intro_dh_parts(rend_service_t *service, time_t now) } DIGESTMAP_FOREACH_END; } +/** Called when intro will soon be removed from + * service's list of intro points. */ +static void +rend_service_note_removing_intro_point(rend_service_t *service, + rend_intro_point_t *intro) +{ + time_t now = time(NULL); + + /* Don't process an intro point twice here. */ + if (intro->rend_service_note_removing_intro_point_called) { + return; + } else { + intro->rend_service_note_removing_intro_point_called = 1; + } + + /* Update service->n_intro_points_wanted based on how long intro + * lasted and how many introductions it handled. */ + if (intro->time_published == -1) { + /* This intro point was never used. Don't change + * n_intro_points_wanted. */ + } else { + /* We want to increase the number of introduction points service + * operates if intro was heavily used, or decrease the number of + * intro points if intro was lightly used. + * + * We consider an intro point's target 'usage' to be + * INTRO_POINT_LIFETIME_INTRODUCTIONS introductions in + * INTRO_POINT_LIFETIME_MIN_SECONDS seconds. To calculate intro's + * fraction of target usage, we divide the fraction of + * _LIFETIME_INTRODUCTIONS introductions that it has handled by + * the fraction of _LIFETIME_MIN_SECONDS for which it existed. + * + * Then we take the reciprocal of that fraction of desired usage, + * then multiply by a fudge factor of 1.5, to decide how many new + * introduction points should ideally replace intro (which is now + * closed or soon to be closed). In theory, assuming that + * introduction load is distributed equally across all intro + * points and ignoring the fact that different intro points are + * established and closed at different times, that number of intro + * points should bring all of our intro points exactly to our + * target usage. + * + * Then we clamp that number to a number of intro points we might + * be willing to replace this intro point with and turn it into an + * integer. then we clamp it again to the number of new intro + * points we could establish now, then we adjust + * service->n_intro_points_wanted and let rend_services_introduce + * create the new intro points we want (if any). + */ + double fractional_n_intro_points_wanted_to_replace_this_one = + ((((double)now - intro->time_published) / + INTRO_POINT_LIFETIME_MIN_SECONDS) * + ((intro_point_accepted_intro_count(intro)) / + INTRO_POINT_LIFETIME_INTRODUCTIONS)) * 1.5; + unsigned int n_intro_points_wanted_to_replace_this_one; + unsigned int n_intro_points_wanted_now; + unsigned int n_intro_points_really_wanted_now; + int n_intro_points_really_replacing_this_one; + + if (fractional_n_intro_points_wanted_to_replace_this_one > + NUM_INTRO_POINTS_MAX) { + n_intro_points_wanted_to_replace_this_one = NUM_INTRO_POINTS_MAX; + } else if (fractional_n_intro_points_wanted_to_replace_this_one < 0) { + n_intro_points_wanted_to_replace_this_one = 0; + } else { + n_intro_points_wanted_to_replace_this_one = + fractional_n_intro_points_wanted_to_replace_this_one; + } + + n_intro_points_wanted_now = + service->n_intro_points_wanted + + n_intro_points_wanted_to_replace_this_one - 1; + + if (n_intro_points_wanted_now < NUM_INTRO_POINTS_DEFAULT) { + /* XXXX This should be NUM_INTRO_POINTS_MIN instead. Perhaps + * another use of NUM_INTRO_POINTS_DEFAULT should be, too. */ + n_intro_points_really_wanted_now = NUM_INTRO_POINTS_DEFAULT; + } else if (n_intro_points_wanted_now > NUM_INTRO_POINTS_MAX) { + n_intro_points_really_wanted_now = NUM_INTRO_POINTS_MAX; + } else { + n_intro_points_really_wanted_now = n_intro_points_wanted_now; + } + + n_intro_points_really_replacing_this_one = + n_intro_points_really_wanted_now - service->n_intro_points_wanted + 1; + + log_info(LD_REND, "Replacing closing intro point for service %s " + "with %d new intro points (wanted %g replacements); " + "service will now try to have %u intro points", + rend_service_describe_for_log(service), + n_intro_points_really_replacing_this_one, + fractional_n_intro_points_wanted_to_replace_this_one, + n_intro_points_really_wanted_now); + + service->n_intro_points_wanted = n_intro_points_really_wanted_now; + } +} + /****** * Handle cells ******/ @@ -2073,6 +2182,7 @@ rend_services_introduce(void) " (circuit disappeared).", safe_str_client(extend_info_describe(intro->extend_info)), safe_str_client(service->service_id)); + rend_service_note_removing_intro_point(service, intro); if (intro->time_expiring != -1) { log_info(LD_REND, "We were already expiring the intro point; " "no need to mark the HS descriptor as dirty over this."); @@ -2095,6 +2205,8 @@ rend_services_introduce(void) safe_str_client(extend_info_describe(intro->extend_info)), safe_str_client(service->service_id)); + rend_service_note_removing_intro_point(service, intro); + /* The polite (and generally Right) way to expire an intro * point is to establish a new one to replace it, publish a * new descriptor that doesn't list any expiring intro points, -- cgit v1.2.3-54-g00ecf