aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/or/directory.c12
-rw-r--r--src/or/dirserv.c80
-rw-r--r--src/or/main.c7
-rw-r--r--src/or/or.h14
-rw-r--r--src/or/rephist.c39
-rw-r--r--src/or/router.c6
-rw-r--r--src/or/routerlist.c48
-rw-r--r--src/or/routerparse.c163
8 files changed, 324 insertions, 45 deletions
diff --git a/src/or/directory.c b/src/or/directory.c
index 3f8b3a94c..61c98df4c 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -352,6 +352,8 @@ int connection_dir_process_inbuf(connection_t *conn) {
}
if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
+ running_routers_t *rrs;
+ routerlist_t *rl;
/* just update our list of running routers, if this list is new info */
log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
if(status_code != 200) {
@@ -361,7 +363,15 @@ int connection_dir_process_inbuf(connection_t *conn) {
connection_mark_for_close(conn);
return -1;
}
- /* XXX008 hand 'body' to something that parses a running-routers list. */
+ if (!(rrs = router_parse_runningrouters(body))) {
+ log_fn(LOG_WARN, "Can't parse runningrouters list");
+ free(body); free(headers);
+ connection_mark_for_close(conn);
+ return -1;
+ }
+ router_get_routerlist(&rl);
+ routerlist_update_from_runningrouters(rl,rrs);
+ running_routers_free(rrs);
}
if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index e8e727892..6e09ee1ec 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -16,6 +16,7 @@ extern or_options_t options; /**< command-line and config-file options */
/** Do we need to regenerate the directory when someone asks for it? */
static int the_directory_is_dirty = 1;
+static int runningrouters_is_dirty = 1;
static int list_running_servers(char **nicknames_out);
static void directory_remove_unrecognized(void);
@@ -406,13 +407,14 @@ void
directory_set_dirty()
{
the_directory_is_dirty = 1;
+ runningrouters_is_dirty = 1;
}
-/** Load all descriptors from an earlier directory stored in the string
+/** Load all descriptors from a directory stored in the string
* <b>dir</b>.
*/
int
-dirserv_init_from_directory_string(const char *dir)
+dirserv_load_from_directory_string(const char *dir)
{
const char *cp = dir;
while(1) {
@@ -525,7 +527,9 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
"signed-directory\n"
"published %s\n"
"recommended-software %s\n"
- "running-routers %s\n\n", published, options.RecommendedVersions, cp);
+ "running-routers %s\n\n",
+ published, options.RecommendedVersions, cp);
+
free(cp);
i = strlen(s);
cp = s+i;
@@ -563,7 +567,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
log_fn(LOG_WARN,"couldn't base64-encode signature");
return -1;
}
-
+
if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
goto truncated;
@@ -583,6 +587,7 @@ static int cached_directory_len = -1;
void dirserv_set_cached_directory(const char *directory, time_t when)
{
time_t now;
+ char filename[512];
if (!options.AuthoritativeDir)
return;
now = time(NULL);
@@ -591,6 +596,11 @@ void dirserv_set_cached_directory(const char *directory, time_t when)
tor_free(cached_directory);
cached_directory = tor_strdup(directory);
cached_directory_len = strlen(cached_directory);
+ cached_directory_published = when;
+ sprintf(filename,"%s/cached-directory", options.DataDirectory);
+ if(write_str_to_file(filename,cached_directory) < 0) {
+ log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
+ }
}
}
@@ -644,12 +654,70 @@ size_t dirserv_get_directory(const char **directory)
return the_directory_len;
}
+static char *runningrouters_string=NULL;
+static size_t runningrouters_len=0;
+
+/** Replace the current running-routers list with a newly generated one. */
+static int generate_runningrouters(crypto_pk_env_t *private_key)
+{
+ char *s, *cp;
+ char digest[DIGEST_LEN];
+ char signature[PK_BYTES];
+ int i, len;
+ char published[33];
+ time_t published_on;
+
+ len = 1024+MAX_NICKNAME_LEN*smartlist_len(descriptor_list);
+ s = tor_malloc_zero(len);
+ if (list_running_servers(&cp))
+ return -1;
+ published_on = time(NULL);
+ strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
+ sprintf(s, "network-status\n"
+ "published %s\n"
+ "running-routers %s\n"
+ "directory-signature %s\n"
+ "-----BEGIN SIGNATURE-----\n",
+ published, cp, options.Nickname);
+ free(cp);
+ if (router_get_runningrouters_hash(s,digest)) {
+ log_fn(LOG_WARN,"couldn't compute digest");
+ return -1;
+ }
+ if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
+ log_fn(LOG_WARN,"couldn't sign digest");
+ return -1;
+ }
+
+ i = strlen(s);
+ cp = s+i;
+ if (base64_encode(cp, len-i, signature, 128) < 0) {
+ log_fn(LOG_WARN,"couldn't base64-encode signature");
+ return -1;
+ }
+ if (strlcat(s, "-----END SIGNATURE-----\n", len) >= len) {
+ return -1;
+ }
+
+ tor_free(runningrouters_string);
+ runningrouters_string = s;
+ runningrouters_len = strlen(s);
+ runningrouters_is_dirty = 0;
+ return 0;
+}
+
/** Set *<b>rr</b> to the most recently generated encoded signed
* running-routers list, generating a new one as necessary. */
size_t dirserv_get_runningrouters(const char **rr)
{
- /* XXX008 fill in this function */
- return 0;
+ if (runningrouters_is_dirty) {
+ if(generate_runningrouters(get_identity_key())) {
+ log_fn(LOG_ERR, "Couldn't generate running-routers list?");
+ return -1;
+ }
+ }
+ *rr = runningrouters_string;
+ return runningrouters_len;
}
/*
diff --git a/src/or/main.c b/src/or/main.c
index 983e9a34d..99e83f37c 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -451,9 +451,8 @@ static void run_scheduled_events(time_t now) {
router_rebuild_descriptor();
router_upload_dir_desc_to_dirservers();
}
- if(!options.DirPort) {
- /* NOTE directory servers do not currently fetch directories.
- * Hope this doesn't bite us later. */
+ if(!options.DirPort || !options.AuthoritativeDir) {
+ /* XXXX should directories do this next part too? */
routerlist_remove_old_routers(); /* purge obsolete entries */
directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
} else {
@@ -461,6 +460,8 @@ static void run_scheduled_events(time_t now) {
dirserv_remove_old_servers();
/* dirservers try to reconnect too, in case connections have failed */
router_retry_connections();
+ /* fetch another directory, in case it knows something we don't */
+ directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
}
/* Force an upload of our descriptors every DirFetchPostPeriod seconds. */
rend_services_upload(1);
diff --git a/src/or/or.h b/src/or/or.h
index e6a014dc5..496109a31 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -595,10 +595,17 @@ typedef struct {
* published?
*/
time_t published_on;
+ time_t running_routers_updated_on;
/** Which router is claimed to have signed it? */
char *signing_router;
} routerlist_t;
+/* DOCDOC */
+typedef struct running_routers_t {
+ time_t published_on;
+ smartlist_t *running_routers;
+} running_routers_t;
+
/** Holds accounting information for a single step in the layered encryption
* performed by a circuit. Used only at the client edge of a circuit. */
struct crypt_path_t {
@@ -1130,7 +1137,7 @@ int dirserv_parse_fingerprint_file(const char *fname);
int dirserv_router_fingerprint_is_known(const routerinfo_t *router);
void dirserv_free_fingerprint_list();
int dirserv_add_descriptor(const char **desc);
-int dirserv_init_from_directory_string(const char *dir);
+int dirserv_load_from_directory_string(const char *dir);
void dirserv_free_descriptors();
void dirserv_remove_old_servers(void);
int dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
@@ -1352,11 +1359,15 @@ int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
#define ADDR_POLICY_UNKNOWN 1
int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port);
int router_exit_policy_rejects_all(routerinfo_t *router);
+void running_routers_free(running_routers_t *rr);
+void routerlist_update_from_runningrouters(routerlist_t *list,
+ running_routers_t *rr);
/********************************* routerparse.c ************************/
int router_get_router_hash(const char *s, char *digest);
int router_get_dir_hash(const char *s, char *digest);
+int router_get_runningrouters_hash(const char *s, char *digest);
int router_parse_list_from_string(const char **s,
routerlist_t **dest,
int n_good_nicknames,
@@ -1364,6 +1375,7 @@ int router_parse_list_from_string(const char **s,
int router_parse_routerlist_from_directory(const char *s,
routerlist_t **dest,
crypto_pk_env_t *pkey);
+running_routers_t *router_parse_runningrouters(const char *str);
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
struct exit_policy_t *router_parse_exit_policy_from_string(const char *s);
diff --git a/src/or/rephist.c b/src/or/rephist.c
index cd71eabc4..418fc8dd6 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -248,6 +248,45 @@ void rep_hist_dump_stats(time_t now, int severity)
}
}
+#if 0
+void write_rep_history(const char *filename)
+{
+ FILE *f = NULL;
+ char *tmpfile;
+ int completed = 0;
+ or_history_t *or_history;
+ link_history_t *link_history;
+ strmap_iter_t *lhist_it;
+ strmap_iter_t *orhist_it;
+ void *or_history_p, *link_history_p;
+ const char *name1;
+
+ tmpfile = tor_malloc(strlen(filename)+5);
+ strcpy(tmpfile, filename);
+ strcat(tmpfile, "_tmp");
+
+ f = fopen(tmpfile, "w");
+ if (!f) goto done;
+ for (orhist_it = strmap_iter_init(history_map); !strmap_iter_done(orhist_it);
+ orhist_it = strmap_iter_next(history_map,orhist_it)) {
+ strmap_iter_get(orhist_it, &name1, &or_history_p);
+ or_history = (or_history_t*) or_history_p;
+ fprintf(f, "link %s connected:u%ld failed:%uld uptime:%uld",
+ name1, or_history->since1,
+ }
+
+
+ done:
+ if (f)
+ fclose(f);
+ if (completed)
+ replace_file(filename, tmpfile);
+ else
+ unlink(tmpfile);
+ tor_free(tmpfile);
+}
+#endif
+
/*
Local Variables:
mode:c
diff --git a/src/or/router.c b/src/or/router.c
index dd6dd452c..9d386bbad 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -284,12 +284,14 @@ int init_keys(void) {
if(!cp) {
log_fn(LOG_INFO,"Cached directory %s not present. Ok.",keydir);
} else {
- if(dirserv_init_from_directory_string(cp) < 0) {
+ if(options.AuthoritativeDir && dirserv_load_from_directory_string(cp) < 0){
log_fn(LOG_ERR, "Cached directory %s is corrupt", keydir);
free(cp);
return -1;
}
- free(cp);
+ /* set time to 1 so it will be replaced on first download.
+ */
+ dirserv_set_cached_directory(cp, 1);
}
/* success */
return 0;
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index ed9a06420..8dd51a8ce 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -477,7 +477,11 @@ int router_load_routerlist_from_directory(const char *s,
log_fn(LOG_WARN, "Error resolving routerlist");
return -1;
}
+ /* Remember the directory, if we're nonauthoritative.*/
dirserv_set_cached_directory(s, routerlist->published_on);
+ /* Learn about the descriptors in the directory, if we're authoritative */
+ if (options.AuthoritativeDir)
+ dirserv_load_from_directory_string(s);
return 0;
}
@@ -621,6 +625,50 @@ int router_exit_policy_rejects_all(routerinfo_t *router) {
== ADDR_POLICY_REJECTED;
}
+/* DODCDOC */
+void running_routers_free(running_routers_t *rr)
+{
+ tor_assert(rr);
+ if (rr->running_routers) {
+ SMARTLIST_FOREACH(rr->running_routers, char *, s, tor_free(s));
+ smartlist_free(rr->running_routers);
+ }
+ tor_free(rr);
+}
+
+/* DOCDOC*/
+void routerlist_update_from_runningrouters(routerlist_t *list,
+ running_routers_t *rr)
+{
+ int n_routers, n_names, i, j, running;
+ routerinfo_t *router;
+ const char *name;
+ if (!routerlist)
+ return;
+ if (routerlist->published_on >= rr->published_on)
+ return;
+ if (routerlist->running_routers_updated_on >= rr->published_on)
+ return;
+
+ n_routers = smartlist_len(list->routers);
+ n_names = smartlist_len(rr->running_routers);
+ for (i=0; i<n_routers; ++i) {
+ running = 0;
+ router = smartlist_get(list->routers, i);
+ for (j=0; j<n_names; ++j) {
+ name = smartlist_get(rr->running_routers, j);
+ if (!strcmp(name, router->nickname)) {
+ running=1;
+ break;
+ }
+ }
+ router->is_running = 1; /* arma: is this correct? */
+ }
+ routerlist->running_routers_updated_on = rr->published_on;
+ /* XXXX008 Should there also be a list of which are down, so that we
+ * don't mark merely unknown routers as down? */
+}
+
/*
Local Variables:
mode:c
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index efd8f3731..60daf0e33 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -41,6 +41,7 @@ typedef enum {
K_PORTS,
K_DIRCACHEPORT,
K_CONTACT,
+ K_NETWORK_STATUS,
_UNRECOGNIZED,
_ERR,
_EOF,
@@ -88,7 +89,7 @@ typedef enum {
typedef enum {
ANY = 0, /**< Appears in router descriptor or in directory sections. */
DIR_ONLY, /**< Appears only in directory. */
- RTR_ONLY, /**< Appears only in router descriptor. */
+ RTR_ONLY, /**< Appears only in router descriptor or runningrouters */
} where_syntax;
/** Table mapping keywords to token value and to argument rules. */
@@ -113,6 +114,7 @@ static struct {
{ "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY },
{ "dircacheport", K_DIRCACHEPORT, ARGS, NO_OBJ, RTR_ONLY },
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY },
+ { "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR_ONLY },
{ NULL, -1 }
};
@@ -128,6 +130,10 @@ static directory_token_t *find_first_by_keyword(smartlist_t *s,
static int tokenize_string(const char *start, const char *end,
smartlist_t *out, int is_dir);
static directory_token_t *get_next_token(const char **s, where_syntax where);
+static int check_directory_signature(const char *digest,
+ directory_token_t *tok,
+ crypto_pk_env_t *pkey);
+
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
* <b>s</b>. Return 0 on success, nonzero on failure.
@@ -147,6 +153,13 @@ int router_get_router_hash(const char *s, char *digest)
"router ","router-signature");
}
+/** DOCDOC */
+int router_get_runningrouters_hash(const char *s, char *digest)
+{
+ return router_get_hash_impl(s,digest,
+ "network-status ","directory-signature");
+}
+
/** Parse a date of the format "YYYY-MM-DD hh:mm:ss" and store the result into
* *<b>t</b>.
*/
@@ -273,13 +286,12 @@ router_parse_routerlist_from_directory(const char *str,
crypto_pk_env_t *pkey)
{
directory_token_t *tok;
- char digest[20];
- char signed_digest[128];
+ char digest[DIGEST_LEN];
routerlist_t *new_dir = NULL;
char *versions = NULL;
- time_t published_on;
- char *good_nickname_lst[1024];
int n_good_nicknames = 0;
+ char *good_nickname_lst[1024]; /* XXXX008 correct this limit. */
+ time_t published_on;
int i, r;
const char *end;
smartlist_t *tokens = NULL;
@@ -373,6 +385,108 @@ router_parse_routerlist_from_directory(const char *str,
(tok->tp != K_DIRECTORY_SIGNATURE)) {
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
}
+ if (check_directory_signature(digest, smartlist_get(tokens,0), pkey)<0) {
+ goto err;
+ }
+
+ if (*dest)
+ routerlist_free(*dest);
+ *dest = new_dir;
+
+ r = 0;
+ goto done;
+ err:
+ r = -1;
+ if (new_dir)
+ routerlist_free(new_dir);
+ tor_free(versions);
+ for (i = 0; i < n_good_nicknames; ++i) {
+ tor_free(good_nickname_lst[i]);
+ }
+ done:
+ if (tokens) {
+ SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
+ smartlist_free(tokens);
+ }
+ return r;
+}
+
+running_routers_t *
+router_parse_runningrouters(const char *str)
+{
+ char digest[DIGEST_LEN];
+ running_routers_t *new_list = NULL;
+ directory_token_t *tok;
+ time_t published_on;
+ int i;
+
+ smartlist_t *tokens = NULL;
+
+ if (router_get_runningrouters_hash(str, digest)) {
+ log_fn(LOG_WARN, "Unable to compute digest of directory");
+ goto err;
+ }
+ tokens = smartlist_create();
+ if (tokenize_string(str,str+strlen(str),tokens,1)) {
+ log_fn(LOG_WARN, "Error tokenizing directory"); goto err;
+ }
+ if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
+ log_fn(LOG_WARN, "Unrecognized keyword in \"%s\"; can't parse directory.",
+ tok->args[0]);
+ goto err;
+ }
+ tok = smartlist_get(tokens,0);
+ if (tok->tp != K_NETWORK_STATUS) {
+ log_fn(LOG_WARN, "Network-status starts with wrong token");
+ goto err;
+ }
+
+ if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
+ log_fn(LOG_WARN, "Missing published time on directory.");
+ goto err;
+ }
+ tor_assert(tok->n_args == 1);
+ if (parse_time(tok->args[0], &published_on) < 0) {
+ goto err;
+ }
+
+ if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
+ log_fn(LOG_WARN, "Missing running-routers line from directory.");
+ goto err;
+ }
+
+ new_list = tor_malloc_zero(sizeof(running_routers_t));
+ new_list->published_on = published_on;
+ new_list->running_routers = smartlist_create();
+ for (i=0;i<tok->n_args;++i) {
+ smartlist_add(new_list->running_routers, tok->args[i]);
+ }
+
+ if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
+ log_fn(LOG_WARN, "Missing signature on directory");
+ goto err;
+ }
+ if (check_directory_signature(digest, tok, NULL)<0) {
+ goto err;
+ }
+
+ goto done;
+ err:
+ running_routers_free(new_list);
+ new_list = NULL;
+ done:
+ if (tokens) {
+ SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
+ smartlist_free(tokens);
+ }
+ return new_list;
+}
+
+static int check_directory_signature(const char *digest,
+ directory_token_t *tok,
+ crypto_pk_env_t *pkey)
+{
+ char signed_digest[PK_BYTES];
if (tok->n_args == 1) {
routerinfo_t *r = router_get_by_nickname(tok->args[0]);
log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
@@ -383,53 +497,38 @@ router_parse_routerlist_from_directory(const char *str,
} else if (!r) {
log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
tok->args[0]);
- goto err;
+ return -1;
} else if (r && !r->is_trusted_dir) {
log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
tok->args[0]);
- goto err;
+ return -1;
}
+ } else if (tok->n_args > 1) {
+ log_fn(LOG_WARN, "Too many arguments to directory-signature");
+ return -1;
}
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
log_fn(LOG_WARN, "Bad object type or length on directory signature");
- goto err;
+ return -1;
}
if (pkey) {
if (crypto_pk_public_checksig(pkey, tok->object_body, 128, signed_digest)
!= 20) {
log_fn(LOG_WARN, "Error reading directory: invalid signature.");
- goto err;
+ return -1;
}
log(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
-
if (memcmp(digest, signed_digest, 20)) {
log_fn(LOG_WARN, "Error reading directory: signature does not match.");
- goto err;
+ return -1;
}
+ } else {
+ /* XXXX008 freak out, unless testing. */
}
-
- if (*dest)
- routerlist_free(*dest);
- *dest = new_dir;
-
- r = 0;
- goto done;
- err:
- r = -1;
- if (new_dir)
- routerlist_free(new_dir);
- tor_free(versions);
- for (i = 0; i < n_good_nicknames; ++i) {
- tor_free(good_nickname_lst[i]);
- }
- done:
- if (tokens) {
- SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
- smartlist_free(tokens);
- }
- return r;
+ return 0;
}
+
/** Given a string *<b>s</b> containing a concatenated
* sequence of router descriptors, parses them and stores the result
* in *<b>dest</b>. If good_nickname_lst is provided, then routers whose