From 18e4d7835484924d6d26685dd890012058434472 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 8 Sep 2005 20:36:40 +0000 Subject: [PATCH] Fix an assert in directory.c. Check received network-status objects against the list we expected to get. Do not let anyone else update our network-status object. svn:r4945 --- src/or/directory.c | 22 +++++++++++++++------- src/or/dirserv.c | 3 ++- src/or/or.h | 5 ++++- src/or/routerlist.c | 25 ++++++++++++++++++++----- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/or/directory.c b/src/or/directory.c index 2b13cbae86..74167694b9 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -401,7 +401,8 @@ directory_send_command(connection_t *conn, const char *platform, tor_assert(conn->type == CONN_TYPE_DIR); tor_free(conn->requested_resource); - conn->requested_resource = tor_strdup(resource); + if (resource) + conn->requested_resource = tor_strdup(resource); /* come up with a string for which Host: we want */ if (conn->port == 80) { @@ -450,13 +451,13 @@ directory_send_command(connection_t *conn, const char *platform, url = tor_strdup("/tor/running-routers"); break; case DIR_PURPOSE_FETCH_NETWORKSTATUS: - httpcommand = "GET";//XXXX + httpcommand = "GET"; len = strlen(resource)+32; url = tor_malloc(len); tor_snprintf(url, len, "/tor/status/%s", resource); break; case DIR_PURPOSE_FETCH_SERVERDESC: - httpcommand = "GET";//XXXX + httpcommand = "GET"; len = strlen(resource)+32; url = tor_malloc(len); tor_snprintf(url, len, "/tor/server/%s", resource); @@ -887,9 +888,7 @@ 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. Also, never ask someone else for a status we - * generated! */ + smartlist_t *which = NULL; log_fn(LOG_INFO,"Received networkstatus objects (size %d) from server '%s:%d'",(int) body_len, conn->address, conn->port); if (status_code != 200) { log_fn(LOG_WARN,"Received http status code %d (\"%s\") from server '%s:%d'. Failing.", @@ -897,17 +896,26 @@ connection_dir_client_reached_eof(connection_t *conn) tor_free(body); tor_free(headers); tor_free(reason); return -1; } + if (conn->requested_resource && + !strcmpstart(conn->requested_resource,"fp/")) { + which = smartlist_create(); + smartlist_split_string(which, conn->requested_resource+3, "+", 0, -1); + } while (*body) { char *next = strstr(body, "\nnetwork-status-version"); if (next) *next = '\0'; - if (router_set_networkstatus(body, time(NULL), 0)<0) + if (router_set_networkstatus(body, time(NULL), NS_FROM_DIR, which)<0) break; if (next) body = next+1; else break; } + if (which) { + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + smartlist_free(which); + } } if (conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC) { diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 66204dbaf9..a32414a5d8 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1134,7 +1134,8 @@ generate_v2_networkstatus(void) set_cached_dir(&the_v2_networkstatus, status, time(NULL)); status = NULL; /* So it doesn't get double-freed. */ the_v2_networkstatus_is_dirty = 0; - router_set_networkstatus(the_v2_networkstatus.dir, time(NULL), 0); + router_set_networkstatus(the_v2_networkstatus.dir, time(NULL), NS_GENERATED, + NULL); r = 0; done: diff --git a/src/or/or.h b/src/or/or.h index 9bdca92bc0..05a0895adc 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2072,7 +2072,10 @@ int router_add_to_routerlist(routerinfo_t *router, const char **msg); int router_load_single_router(const char *s, const char **msg); int router_load_routerlist_from_directory(const char *s,crypto_pk_env_t *pkey, int dir_is_recent, int dir_is_cached); -int router_set_networkstatus(const char *s, time_t arrived_at, int is_cached); +typedef enum { NS_FROM_CACHE, NS_FROM_DIR, NS_GENERATED} networkstatus_source_t; +int router_set_networkstatus(const char *s, time_t arrived_at, + networkstatus_source_t source, + smartlist_t *requested_fingerprints); addr_policy_result_t router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port, addr_policy_t *policy); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index ccbb5b0b23..3640e8ce79 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -108,7 +108,7 @@ router_reload_networkstatus(void) s = read_file_to_str(filename, 0); if (s) { stat(filename, &st); - if (router_set_networkstatus(s, st.st_mtime, 1)<0) { + if (router_set_networkstatus(s, st.st_mtime, NS_FROM_CACHE, NULL)<0) { log_fn(LOG_WARN, "Couldn't load networkstatus from \"%s\"",filename); } tor_free(s); @@ -1199,9 +1199,11 @@ router_load_routerlist_from_directory(const char *s, } /** DOCDOC returns 0 on no problems, -1 on problems. + * requested fingerprints must be upcased. */ int -router_set_networkstatus(const char *s, time_t arrived_at, int is_cached) +router_set_networkstatus(const char *s, time_t arrived_at, + networkstatus_source_t source, smartlist_t *requested_fingerprints) { networkstatus_t *ns; int i, found; @@ -1215,6 +1217,7 @@ router_set_networkstatus(const char *s, time_t arrived_at, int is_cached) } if (!router_digest_is_trusted_dir(ns->identity_digest)) { log_fn(LOG_INFO, "Network status was signed, but not by an authoritative directory we recognize."); + networkstatus_free(ns); return -1; } now = time(NULL); @@ -1228,6 +1231,20 @@ router_set_networkstatus(const char *s, time_t arrived_at, int is_cached) if (!networkstatus_list) networkstatus_list = smartlist_create(); + if (source == NS_FROM_DIR && router_digest_is_me(ns->identity_digest)) { + /* Drop our own networkstatus when we get it from somebody else. */ + networkstatus_free(ns); + return 0; + } + + base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN); + + if (requested_fingerprints && + !smartlist_string_isin(requested_fingerprints, fp)) { + log_fn(LOG_WARN, "We received a network status with a fingerprint (%s) that we never requested. Dropping.", fp); + return 0; + } + found = 0; for (i=0; i < smartlist_len(networkstatus_list); ++i) { networkstatus_t *old_ns = smartlist_get(networkstatus_list, i); @@ -1256,9 +1273,7 @@ router_set_networkstatus(const char *s, time_t arrived_at, int is_cached) if (!found) smartlist_add(networkstatus_list, ns); - base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN); - - if (!is_cached) { + if (source != NS_FROM_CACHE) { const char *datadir = get_options()->DataDirectory; size_t len = strlen(datadir)+64; char *fn = tor_malloc(len+1);