mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Download network-status at regular intervals. The code is probably iffy, and the constants need to be renamed.
svn:r4921
This commit is contained in:
parent
2f6664ce80
commit
f50ddfd4dd
@ -163,14 +163,25 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
trusted_dir_server_t *ds = NULL;
|
||||
int fascistfirewall = firewall_is_fascist();
|
||||
int directconn = purpose == DIR_PURPOSE_FETCH_DIR ||
|
||||
purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
|
||||
purpose == DIR_PURPOSE_FETCH_RUNNING_LIST ||
|
||||
purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS ||
|
||||
purpose == DIR_PURPOSE_FETCH_SERVERDESC;
|
||||
int fetch_fresh_first = advertised_server_mode();
|
||||
int priv = purpose_is_private(purpose);
|
||||
int need_v1_support = purpose == DIR_PURPOSE_FETCH_DIR ||
|
||||
purpose == DIR_PURPOSE_FETCH_RUNNING_LIST;
|
||||
|
||||
if (directconn) {
|
||||
if (fetch_fresh_first) {
|
||||
if (fetch_fresh_first && purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS &&
|
||||
strlen(resource) == HEX_DIGEST_LEN) {
|
||||
/* Try to ask the actual dirserver its opinion. */
|
||||
char digest[DIGEST_LEN];
|
||||
base16_decode(digest, DIGEST_LEN, resource, HEX_DIGEST_LEN);
|
||||
ds = router_get_trusteddirserver_by_digest(digest);
|
||||
}
|
||||
if (!ds && fetch_fresh_first) {
|
||||
/* only ask authdirservers, and don't ask myself */
|
||||
ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
|
||||
ds = router_pick_trusteddirserver(need_v1_support, 1, fascistfirewall,
|
||||
retry_if_no_servers);
|
||||
}
|
||||
if (!ds) {
|
||||
@ -178,9 +189,17 @@ directory_get_from_dirserver(uint8_t purpose, const char *resource,
|
||||
r = router_pick_directory_server(1, fascistfirewall, 0,
|
||||
retry_if_no_servers);
|
||||
if (!r) {
|
||||
log_fn(LOG_INFO, "No router found for %s; falling back to dirserver list",
|
||||
purpose == DIR_PURPOSE_FETCH_RUNNING_LIST
|
||||
? "status list" : "directory");
|
||||
const char *which;
|
||||
if (purpose == DIR_PURPOSE_FETCH_DIR)
|
||||
which = "directory";
|
||||
else if (purpose == DIR_PURPOSE_FETCH_RUNNING_LIST)
|
||||
which = "status list";
|
||||
else if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
|
||||
which = "network status";
|
||||
else // if (purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS)
|
||||
which = "server descriptors";
|
||||
log_fn(LOG_INFO,
|
||||
"No router found for %s; falling back to dirserver list",which);
|
||||
ds = router_pick_trusteddirserver(1, 1, fascistfirewall,
|
||||
retry_if_no_servers);
|
||||
}
|
||||
@ -466,19 +485,21 @@ directory_send_command(connection_t *conn, const char *platform,
|
||||
httpcommand = "POST";
|
||||
url = tor_strdup("/tor/rendezvous/publish");
|
||||
break;
|
||||
default:
|
||||
tor_assert(0);
|
||||
return;
|
||||
}
|
||||
tor_snprintf(request, sizeof(request), "%s %s", httpcommand, proxystring);
|
||||
connection_write_to_buf(request, strlen(request), conn);
|
||||
connection_write_to_buf(url, strlen(url), conn);
|
||||
tor_free(url);
|
||||
|
||||
tor_snprintf(request, len, " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
|
||||
tor_snprintf(request, sizeof(request), " HTTP/1.0\r\nContent-Length: %lu\r\nHost: %s%s\r\n\r\n",
|
||||
payload ? (unsigned long)payload_len : 0,
|
||||
hoststring,
|
||||
proxyauthstring);
|
||||
connection_write_to_buf(request, strlen(request), conn);
|
||||
|
||||
|
||||
if (payload) {
|
||||
/* then send the payload afterwards too */
|
||||
connection_write_to_buf(payload, payload_len, conn);
|
||||
@ -858,6 +879,34 @@ connection_dir_client_reached_eof(connection_t *conn)
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->purpose == DIR_PURPOSE_FETCH_NETWORKSTATUS) {
|
||||
/* XXXX NM We *must* make certain we get the one(s) we asked for or we
|
||||
* could be partitioned. */
|
||||
log_fn(LOG_INFO,"Received networkstatus objects (size %d)",(int) body_len);
|
||||
if (status_code != 200) {
|
||||
log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s'. Failing.",
|
||||
status_code, reason, conn->address);
|
||||
tor_free(body); tor_free(headers); tor_free(reason);
|
||||
return -1;
|
||||
}
|
||||
while (*body) {
|
||||
char *next = strstr(body, "\nnetwork-status-version");
|
||||
if (next)
|
||||
*next = '\0';
|
||||
if (router_set_networkstatus(body, time(NULL), 0)<0)
|
||||
break;
|
||||
if (next)
|
||||
body = next+1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) {
|
||||
/* XXXX NM implement this. */
|
||||
log_fn(LOG_WARN, "Somehow, we requested some individual server descriptors. Skipping.");
|
||||
}
|
||||
|
||||
if (conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||
switch (status_code) {
|
||||
case 200:
|
||||
|
@ -731,6 +731,8 @@ run_scheduled_events(time_t now)
|
||||
stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT &&
|
||||
!we_are_hibernating())
|
||||
consider_testing_reachability();
|
||||
|
||||
update_networkstatus_downloads();
|
||||
}
|
||||
|
||||
/** 3a. Every second, we examine pending circuits and prune the
|
||||
|
@ -2027,6 +2027,8 @@ trusted_dir_server_t *router_pick_trusteddirserver(int need_v1_support,
|
||||
int requireother,
|
||||
int fascistfirewall,
|
||||
int retry_if_no_servers);
|
||||
trusted_dir_server_t *router_get_trusteddirserver_by_digest(
|
||||
const char *digest);
|
||||
int all_trusted_directory_servers_down(void);
|
||||
void routerlist_add_family(smartlist_t *sl, routerinfo_t *router);
|
||||
void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int warn_if_down);
|
||||
@ -2086,6 +2088,8 @@ int router_update_status_from_smartlist(routerinfo_t *r,
|
||||
void add_trusted_dir_server(const char *addr, uint16_t port,
|
||||
const char *digest, int supports_v1);
|
||||
void clear_trusted_dir_servers(void);
|
||||
networkstatus_t *networkstatus_get_by_digest(const char *digest);
|
||||
void update_networkstatus_downloads(void);
|
||||
|
||||
/********************************* routerparse.c ************************/
|
||||
|
||||
|
@ -176,6 +176,21 @@ router_pick_directory_server(int requireother,
|
||||
return choice;
|
||||
}
|
||||
|
||||
trusted_dir_server_t *
|
||||
router_get_trusteddirserver_by_digest(const char *digest)
|
||||
{
|
||||
if (!trusted_dir_servers)
|
||||
return NULL;
|
||||
|
||||
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
||||
{
|
||||
if (!memcmp(ds->digest, digest, DIGEST_LEN))
|
||||
return ds;
|
||||
});
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Try to find a running trusted dirserver. If there are no running
|
||||
* trusted dirservers and <b>retry_if_no_servers</b> is non-zero,
|
||||
* set them all as running again, and try again.
|
||||
@ -1219,7 +1234,10 @@ router_set_networkstatus(const char *s, time_t arrived_at, int is_cached)
|
||||
if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
|
||||
if (!memcmp(old_ns->networkstatus_digest,
|
||||
ns->networkstatus_digest, DIGEST_LEN)) {
|
||||
/* Same one we had before. */
|
||||
networkstatus_free(ns);
|
||||
if (old_ns->received_on < arrived_at)
|
||||
old_ns->received_on = arrived_at;
|
||||
return 0;
|
||||
} else if (old_ns->published_on >= ns->published_on) {
|
||||
log_fn(LOG_INFO, "Dropping network-status; we have a newer one for this authority.");
|
||||
@ -1257,6 +1275,70 @@ router_set_networkstatus(const char *s, time_t arrived_at, int is_cached)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
update_networkstatus_downloads(void)
|
||||
{
|
||||
/* XXX Yes, these constants are supposed to be dumb, so we can choose better
|
||||
* values. */
|
||||
#define ABOUT_TWO_DAYS (48*60*60)
|
||||
#define ABOUT_HALF_AN_HOUR (30*60)
|
||||
int n_live = 0, needed = 0, n_dirservers, i;
|
||||
int most_recent_idx = -1;
|
||||
trusted_dir_server_t *most_recent = NULL;
|
||||
time_t most_recent_received = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
/* This is a little tricky. We want to download enough network-status
|
||||
* objects so that we have at least half of them under ABOUT_TWO_DAYS
|
||||
* publication time. We want to download a new *one* if the most recent
|
||||
* one's publication time is under ABOUT_HALF_AN_HOUR.
|
||||
*/
|
||||
|
||||
tor_assert(trusted_dir_servers);
|
||||
n_dirservers = smartlist_len(trusted_dir_servers);
|
||||
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
||||
{
|
||||
networkstatus_t *ns = networkstatus_get_by_digest(ds->digest);
|
||||
if (ns->published_on > now-ABOUT_TWO_DAYS)
|
||||
++n_live;
|
||||
if (!most_recent || ns->received_on > most_recent_received) {
|
||||
most_recent_idx = ds_sl_idx; /* magic variable from FOREACH*/
|
||||
most_recent = ds;
|
||||
most_recent_received = ns->received_on;
|
||||
}
|
||||
});
|
||||
|
||||
/* Download enough so we have at least half live, but no more than all the
|
||||
* trusted dirservers we know.
|
||||
*/
|
||||
if (n_live < (n_dirservers/2)+1)
|
||||
needed = (n_dirservers/2)+1-n_live;
|
||||
if (needed > n_dirservers)
|
||||
needed = n_dirservers;
|
||||
/* Also, download at least 1 every ABOUT_HALF_AN_HOUR. */
|
||||
if (most_recent_received < now-ABOUT_HALF_AN_HOUR && needed < 1)
|
||||
needed = 1;
|
||||
|
||||
/* If no networkstatus was found, choose a dirserver at random as "most
|
||||
* recent". */
|
||||
if (most_recent_idx<0)
|
||||
most_recent_idx = crypto_pseudo_rand_int(n_dirservers);
|
||||
|
||||
/* XXXX NM This could compress multiple downloads into a single request.
|
||||
* It could also be smarter on failures. */
|
||||
for (i = most_recent_idx+1; needed; ++i) {
|
||||
char resource[HEX_DIGEST_LEN+1];
|
||||
trusted_dir_server_t *ds;
|
||||
if (i > n_dirservers)
|
||||
i = 0;
|
||||
ds = smartlist_get(trusted_dir_servers, i);
|
||||
base16_encode(resource, sizeof(resource), ds->digest, DIGEST_LEN);
|
||||
directory_get_from_dirserver(DIR_PURPOSE_FETCH_NETWORKSTATUS, resource, 1);
|
||||
--needed;
|
||||
}
|
||||
}
|
||||
|
||||
/** Ensure that our own routerinfo is at the front, and remove duplicates
|
||||
* of our routerinfo.
|
||||
*/
|
||||
@ -1709,3 +1791,14 @@ clear_trusted_dir_servers(void)
|
||||
}
|
||||
}
|
||||
|
||||
networkstatus_t *
|
||||
networkstatus_get_by_digest(const char *digest)
|
||||
{
|
||||
SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
|
||||
{
|
||||
if (!memcmp(ns->identity_digest, digest, DIGEST_LEN))
|
||||
return ns;
|
||||
});
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user