diff options
-rw-r--r-- | src/or/Makefile.am | 4 | ||||
-rw-r--r-- | src/or/connection.c | 2 | ||||
-rw-r--r-- | src/or/connection_or.c | 1 | ||||
-rw-r--r-- | src/or/directory.c | 36 | ||||
-rw-r--r-- | src/or/dirserv.c | 387 | ||||
-rw-r--r-- | src/or/main.c | 147 | ||||
-rw-r--r-- | src/or/or.h | 31 | ||||
-rw-r--r-- | src/or/routers.c | 192 |
8 files changed, 509 insertions, 291 deletions
diff --git a/src/or/Makefile.am b/src/or/Makefile.am index 02eea56e9..cf33b1464 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -5,14 +5,14 @@ noinst_PROGRAMS = test bin_PROGRAMS = tor tor_SOURCES = buffers.c circuit.c command.c connection.c \ - connection_or.c config.c \ + connection_or.c config.c dirserv.c \ onion.c routers.c directory.c dns.c connection_edge.c \ cpuworker.c main.c tor_main.c tor_LDADD = ../common/libor.a test_SOURCES = buffers.c circuit.c command.c connection.c \ - connection_or.c config.c \ + connection_or.c config.c dirserv.c \ onion.c routers.c directory.c dns.c connection_edge.c \ cpuworker.c main.c test.c diff --git a/src/or/connection.c b/src/or/connection.c index 0604cd8f8..20522b848 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -110,6 +110,8 @@ void connection_free(connection_t *conn) { crypto_free_pk_env(conn->link_pkey); if (conn->identity_pkey) crypto_free_pk_env(conn->identity_pkey); + if (conn->nickname) + free(conn->nickname); if(conn->s > 0) { log_fn(LOG_INFO,"closing fd %d.",conn->s); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index cddbc93c2..d1cc66e62 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -81,6 +81,7 @@ void connection_or_init_conn_from_router(connection_t *conn, routerinfo_t *route conn->onion_pkey = crypto_pk_dup_key(router->onion_pkey); conn->link_pkey = crypto_pk_dup_key(router->link_pkey); conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); + conn->nickname = strdup(router->nickname); if(conn->address) free(conn->address); conn->address = strdup(router->address); diff --git a/src/or/directory.c b/src/or/directory.c index 2ed210cde..562326d6a 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -4,22 +4,17 @@ #include "or.h" -#define MAX_DIR_SIZE 50000 /* XXX, big enough? */ - static int directory_send_command(connection_t *conn, int command); -static void directory_rebuild(void); static int directory_handle_command(connection_t *conn); /********* START VARIABLES **********/ extern or_options_t options; /* command-line and config-file options */ -static char the_directory[MAX_DIR_SIZE+1]; -static int directorylen=0; -static int directory_dirty=1; - static char fetchstring[] = "GET / HTTP/1.0\r\n\r\n"; static char answerstring[] = "HTTP/1.0 200 OK\r\n\r\n"; +static char the_directory[MAX_DIR_SIZE+1]; +static int directorylen=0; /********* END VARIABLES ************/ @@ -115,25 +110,6 @@ static int directory_send_command(connection_t *conn, int command) { return 0; } -void directory_set_dirty(void) { - directory_dirty = 1; -} - -static void directory_rebuild(void) { - if(directory_dirty) { - if (dump_signed_directory_to_string(the_directory, MAX_DIR_SIZE, - get_identity_key())) { - log(LOG_WARNING, "Error creating directory"); - return; - } - directorylen = strlen(the_directory); - log(LOG_INFO,"New directory (size %d):\n%s",directorylen,the_directory); - directory_dirty = 0; - } else { - log(LOG_INFO,"Directory still clean, reusing."); - } -} - int connection_dir_process_inbuf(connection_t *conn) { assert(conn && conn->type == CONN_TYPE_DIR); @@ -191,6 +167,8 @@ int connection_dir_process_inbuf(connection_t *conn) { static int directory_handle_command(connection_t *conn) { char headers[1024]; char body[50000]; /* XXX */ + size_t dl; + const char *cp; assert(conn && conn->type == CONN_TYPE_DIR); @@ -209,16 +187,16 @@ static int directory_handle_command(connection_t *conn) { if(!strncasecmp(headers,"GET",3)) { /* XXX should check url and http version */ - directory_rebuild(); /* rebuild it now, iff it's dirty */ + dl = dirserv_get_directory(&cp); - if(directorylen == 0) { + if(dl == 0) { log_fn(LOG_WARNING,"My directory is empty. Closing."); return -1; } log_fn(LOG_DEBUG,"Dumping directory to client."); if((connection_write_to_buf(answerstring, strlen(answerstring), conn) < 0) || - (connection_write_to_buf(the_directory, directorylen, conn) < 0)) { + (connection_write_to_buf(cp, dl, conn) < 0)) { log_fn(LOG_WARNING,"Failed to write answerstring+directory to outbuf."); return -1; } diff --git a/src/or/dirserv.c b/src/or/dirserv.c new file mode 100644 index 000000000..901d2e945 --- /dev/null +++ b/src/or/dirserv.c @@ -0,0 +1,387 @@ +/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */ +/* See LICENSE for licensing information */ +/* $Id$ */ + +#include "or.h" + +static int the_directory_is_dirty = 1; +static char *the_directory = NULL; +static int the_directory_len = -1; + +/* + * Fingerprint handling code. + */ +typedef struct fingerprint_entry_t { + char *nickname; + char *fingerprint; +} fingerprint_entry_t; + +static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR]; +static int n_fingerprints = 0; + +/* return 0 on success, -1 on failure */ +int +dirserv_parse_fingerprint_file(const char *fname) +{ + FILE *file; +#define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20) + char buf[BUF_LEN+1]; + char *cp, *nickname, *fingerprint; + fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR]; + int n_fingerprints_tmp = 0; + int lineno=0; + int i; + if (!(file = fopen(fname, "r"))) { + log(LOG_WARNING, "Cannot open fingerprint file %s", fname); + goto err; + } + while (1) { + cp = fgets(buf, BUF_LEN, file); + ++lineno; + if (!cp) { + if (feof(file)) + break; + else { + log(LOG_WARNING, "Error reading from fingerprint file"); + goto err; + } + } + buf[BUF_LEN]='\0'; + cp = buf; + while (isspace(*cp)) + ++cp; + if (*cp == '#' || *cp == '\0') + continue; + nickname = cp; + cp = strchr(cp, ' '); + if (!cp) { + log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); + goto err; + } + *cp++ = '\0'; + while (isspace(*cp)) + ++cp; + if (strlen(cp) < FINGERPRINT_LEN) { + log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); + goto err; + } + fingerprint = cp; + cp[FINGERPRINT_LEN] = '\0'; + if (strlen(nickname) > MAX_NICKNAME_LEN) { + log(LOG_WARNING, "Nickname too long on line %d of fingerprint file", + lineno); + goto err; + } + if (!crypto_pk_check_fingerprint_syntax(fingerprint)) { + log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file", + lineno); + goto err; + } + for (i = 0; i < n_fingerprints_tmp; ++i) { + if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) { + log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno); + goto err; + } + } + fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname); + fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint); + ++n_fingerprints_tmp; + } + /* replace the global fingerprints list. */ + dirserv_free_fingerprint_list(); + memcpy(fingerprint_list, fingerprint_list_tmp, + sizeof(fingerprint_entry_t)*n_fingerprints_tmp); + n_fingerprints = n_fingerprints_tmp; + return 0; + + err: + for (i = 0; i < n_fingerprints_tmp; ++i) { + free(fingerprint_list_tmp[i].nickname); + free(fingerprint_list_tmp[i].fingerprint); + } + return -1; +#undef BUF_LEN +} + +/* return 1 if router's identity and nickname match. */ +int +dirserv_router_fingerprint_is_known(const routerinfo_t *router) +{ + int i; + fingerprint_entry_t *ent =NULL; + char fp[FINGERPRINT_LEN+1]; + + for (i=0;i<n_fingerprints;++i) { + if (!strcasecmp(router->nickname,fingerprint_list[i].nickname)) { + ent = &fingerprint_list[i]; + break; + } + } + + if (!ent) { + /* No such server known */ + return 0; + } + if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) { + /* XXX Error computing fingerprint: log */ + return 0; + } + if (0==strcasecmp(ent->fingerprint, fp)) { + /* Right fingerprint. */ + return 1; + } else { + /* Wrong fingerprint. */ + return 0; + } +} + +void +dirserv_free_fingerprint_list() +{ + int i; + for (i = 0; i < n_fingerprints; ++i) { + free(fingerprint_list[i].nickname); + free(fingerprint_list[i].fingerprint); + } + n_fingerprints = 0; +} + +/* + * Descriptor list + */ +typedef struct descriptor_entry_t { + char *nickname; + time_t published; + size_t desc_len; + char *descriptor; +} descriptor_entry_t; + +static descriptor_entry_t *descriptor_list[MAX_ROUTERS_IN_DIR]; +static int n_descriptors = 0; + +static void free_descriptor_entry(descriptor_entry_t *desc) +{ + if (desc->descriptor) + free(desc->descriptor); + if (desc->nickname) + free(desc->nickname); + free(desc); +} + +void +dirserv_free_descriptors() +{ + int i; + for (i = 0; i < n_descriptors; ++i) { + free_descriptor_entry(descriptor_list[i]); + } + n_descriptors = 0; +} + +/* Return 0 if descriptor added; -1 if descriptor rejected. Updates *desc + * to point after the descriptor if the descriptor is OK. + */ +int +dirserv_add_descriptor(const char **desc) +{ + descriptor_entry_t **desc_ent_ptr; + routerinfo_t *ri = NULL; + int i; + char *start, *end; + char *desc_tmp = NULL; + size_t desc_len; + + start = strstr(*desc, "router "); + if (!start) { + log(LOG_WARNING, "no descriptor found."); + goto err; + } + end = strstr(start+6, "\nrouter "); + if (end) { + ++end; /* Include NL. */ + } else { + end = start+strlen(start); + } + desc_len = end-start; + desc_tmp = tor_malloc(desc_len+1); + strncpy(desc_tmp, start, desc_len); + desc_tmp[desc_len]='\0'; + + /* Check: is the descriptor syntactically valid? */ + ri = router_get_entry_from_string(&desc_tmp); + if (!ri) { + log(LOG_WARNING, "Couldn't parse descriptor"); + goto err; + } + free(desc_tmp); desc_tmp = NULL; + /* Okay. Now check whether the fingerprint is recognized. */ + if (!dirserv_router_fingerprint_is_known(ri)) { + log(LOG_WARNING, "Identity is unrecognized for descriptor"); + goto err; + } + /* Do we already have an entry for this router? */ + desc_ent_ptr = NULL; + for (i = 0; i < n_descriptors; ++i) { + if (!strcasecmp(ri->nickname, descriptor_list[i]->nickname)) { + desc_ent_ptr = &descriptor_list[i]; + break; + } + } + if (desc_ent_ptr) { + /* if so, decide whether to update it. */ + if ((*desc_ent_ptr)->published > ri->published_on) { + /* We already have a newer descriptor */ + goto err; + } + /* We don't have a newer one; we'll update this one. */ + free_descriptor_entry(*desc_ent_ptr); + } else { + /* Add this at the end. */ + desc_ent_ptr = &descriptor_list[n_descriptors++]; + } + + (*desc_ent_ptr) = tor_malloc(sizeof(descriptor_entry_t)); + (*desc_ent_ptr)->nickname = ri->nickname; + (*desc_ent_ptr)->published = ri->published_on; + (*desc_ent_ptr)->desc_len = desc_len; + (*desc_ent_ptr)->descriptor = tor_malloc(desc_len+1); + strncpy((*desc_ent_ptr)->descriptor, start, desc_len); + (*desc_ent_ptr)->descriptor[desc_len] = '\0'; + *desc = end; + the_directory_is_dirty = 1; + + routerinfo_free(ri); + return 0; + err: + if (desc_tmp) + free(desc_tmp); + if (ri) + routerinfo_free(ri); + + return -1; +} + +void +directory_set_dirty() +{ + the_directory_is_dirty = 1; +} + +int +dirserv_init_from_directory_string(const char *dir) +{ + const char *cp = dir; + while(1) { + cp = strstr(cp, "\nrouter "); + if (!cp) break; + ++cp; + if (dirserv_add_descriptor(&cp)) { + return -1; + } + --cp; /*Back up to newline.*/ + } + return 0; +} + +int +dirserv_dump_directory_to_string(char *s, int maxlen, + crypto_pk_env_t *private_key) +{ + char *cp, *eos; + char digest[20]; + char signature[128]; + char published[33]; + time_t published_on; + int i; + eos = s+maxlen; + + if (list_running_servers(&cp)) + return -1; + published_on = time(NULL); + strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on)); + snprintf(s, maxlen, + "signed-directory\n" + "published %s\n" + "recommended-software "RECOMMENDED_SOFTWARE_VERSIONS"\n" + "running-routers %s\n", published, cp); + free(cp); + i = strlen(s); + cp = s+i; + + for (i = 0; i < n_descriptors; ++i) { + strncat(cp, descriptor_list[i]->descriptor, descriptor_list[i]->desc_len); + cp += descriptor_list[i]->desc_len; + assert(!cp); + } + /* These multiple strlen calls are inefficient, but dwarfed by the RSA + signature. + */ + i = strlen(s); + strncat(s, "directory-signature\n", maxlen-i); + i = strlen(s); + cp = s + i; + + if (crypto_SHA_digest(s, i, digest)) { + log_fn(LOG_WARNING,"couldn't compute digest"); + return -1; + } + if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) { + log_fn(LOG_WARNING,"couldn't sign digest"); + return -1; + } + + strncpy(cp, + "-----BEGIN SIGNATURE-----\n", maxlen-i); + + i = strlen(s); + cp = s+i; + if (base64_encode(cp, maxlen-i, signature, 128) < 0) { + log_fn(LOG_WARNING," couldn't base64-encode signature"); + return -1; + } + + i = strlen(s); + cp = s+i; + strncat(cp, "-----END SIGNATURE-----\n", maxlen-i); + i = strlen(s); + if (i == maxlen) { + log_fn(LOG_WARNING,"tried to exceed string length."); + return -1; + } + + return 0; +} + +size_t dirserv_get_directory(const char **directory) +{ + char *new_directory; + if (the_directory_is_dirty) { + new_directory = tor_malloc(MAX_DIR_SIZE); + if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE, + get_identity_key())) { + log(LOG_WARNING, "Error creating directory."); + free(new_directory); + return 0; + } + if (the_directory) + free(the_directory); + the_directory = new_directory; + the_directory_len = strlen(the_directory); + log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len, + the_directory); + the_directory_is_dirty = 0; + /* Now read the directory we just made in order to update our own + * router lists. This does more signature checking than is strictly + * necessary, but safe is better than sorry. */ + new_directory = strdup(*directory); + if (router_get_dir_from_string(new_directory, get_identity_key())) { + log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying."); + exit(0); + } + free(new_directory); + } else { + log(LOG_INFO,"Directory still clean, reusing."); + } + *directory = the_directory; + return the_directory_len; +} diff --git a/src/or/main.c b/src/or/main.c index eb0ef7a14..5421c96ea 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -741,11 +741,12 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router, strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on)); result = snprintf(s, maxlen, - "router %s %d %d %d %d\n" + "router %s %s %d %d %d %d\n" "published %s\n" "onion-key\n%s" "link-key\n%s" "signing-key\n%s", + router->nickname, router->address, router->or_port, router->ap_port, @@ -805,126 +806,36 @@ int dump_router_to_string(char *s, int maxlen, routerinfo_t *router, return written+1; } -static int -build_directory(directory_t *dir) { - routerinfo_t **routers = NULL; +int +list_running_servers(char **nicknames_out) +{ + char *nickname_lst[MAX_ROUTERS_IN_DIR]; connection_t *conn; - routerinfo_t *router; - int i, n = 0; - - routers = (routerinfo_t **)tor_malloc(sizeof(routerinfo_t*) * (nfds+1)); - if (my_routerinfo) { - log(LOG_INFO, "build_directory(): adding self (%s:%d)", - my_routerinfo->address, my_routerinfo->or_port); - routers[n++] = my_routerinfo; - } - for(i = 0; i<nfds; ++i) { + char *cp; + int n = 0, i; + int length; + *nicknames_out = NULL; + if (my_routerinfo) + nickname_lst[n++] = my_routerinfo->nickname; + for (i = 0; i<nfds; ++i) { conn = connection_array[i]; - - if(conn->type != CONN_TYPE_OR) - continue; /* we only want to list ORs */ - if(conn->state != OR_CONN_STATE_OPEN) - continue; /* we only want to list ones that successfully handshaked */ - router = router_get_by_addr_port(conn->addr,conn->port); - if(!router) { - /* XXX this legitimately happens when conn is an OP. How to detect this? */ - log(LOG_INFO,"build_directory(): couldn't find router %d:%d!", - conn->addr,conn->port); - continue; - } - log(LOG_INFO, "build_directory(): adding router (%s:%d)", - router->address, router->or_port); - routers[n++] = router; + if (conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) + continue; /* only list successfully handshaked OR's. */ + nickname_lst[n++] = conn->nickname; + } + length = n + 1; /* spaces + EOS + 1. */ + for (i = 0; i<n; ++i) { + length += strlen(nickname_lst[i]); + } + *nicknames_out = tor_malloc(length); + cp = *nicknames_out; + for (i = 0; i<n; ++i) { + if (i) + strcat(cp, " "); + strcat(cp, nickname_lst[i]); + while (*cp) + ++cp; } - dir->routers = routers; - dir->n_routers = n; - return 0; -} - -int -dump_signed_directory_to_string(char *s, int maxlen, - crypto_pk_env_t *private_key) -{ - directory_t dir; - if (build_directory(&dir)) { - log(LOG_WARNING,"dump_signed_directory_to_string(): build_directory failed."); - return -1; - } - return dump_signed_directory_to_string_impl(s, maxlen, &dir, private_key); -} - -int -dump_signed_directory_to_string_impl(char *s, int maxlen, directory_t *dir, - crypto_pk_env_t *private_key) -{ - char *cp, *eos; - char digest[20]; - char signature[128]; - int i, written; - routerinfo_t *router; - eos = s+maxlen; - strncpy(s, - "signed-directory\n" - "recommended-software " - RECOMMENDED_SOFTWARE_VERSIONS - "\n" - , maxlen); - - i = strlen(s); - cp = s+i; - for (i = 0; i < dir->n_routers; ++i) { - router = dir->routers[i]; - /* XXX This is wrong; we shouldn't sign routers, but rather propagate - * XXX the original router blocks, unaltered. - */ - written = dump_router_to_string(cp, eos-cp, router, private_key); - - if(written < 0) { - log(LOG_WARNING,"dump_signed_directory_to_string(): tried to exceed string length."); - cp[maxlen-1] = 0; /* make sure it's null terminated */ - free(dir->routers); - return -1; - } - cp += written; - } - free(dir->routers); /* not needed anymore */ - - /* These multiple strlen calls are inefficient, but dwarfed by the RSA - signature. - */ - i = strlen(s); - strncat(s, "directory-signature\n", maxlen-i); - i = strlen(s); - cp = s + i; - - if (crypto_SHA_digest(s, i, digest)) { - log(LOG_WARNING,"dump_signed_directory_to_string(): couldn't compute digest"); - return -1; - } - if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) { - log(LOG_WARNING,"dump_signed_directory_to_string(): couldn't sign digest"); - return -1; - } - - strncpy(cp, - "-----BEGIN SIGNATURE-----\n", maxlen-i); - - i = strlen(s); - cp = s+i; - if (base64_encode(cp, maxlen-i, signature, 128) < 0) { - log_fn(LOG_WARNING," couldn't base64-encode signature"); - return -1; - } - - i = strlen(s); - cp = s+i; - strncat(cp, "-----END SIGNATURE-----\n", maxlen-i); - i = strlen(s); - if (i == maxlen) { - log(LOG_WARNING,"dump_signed_directory_to_string(): tried to exceed string length."); - return -1; - } - return 0; } diff --git a/src/or/or.h b/src/or/or.h index be41e2b44..7f051fa6d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -102,6 +102,7 @@ #define MAX_BUF_SIZE (640*1024) #define DEFAULT_BANDWIDTH_OP (1024 * 1000) #define MAX_NICKNAME_LEN 32 +#define MAX_DIR_SIZE 50000 /* XXX, big enough? */ #define ACI_TYPE_LOWER 0 #define ACI_TYPE_HIGHER 1 @@ -214,6 +215,8 @@ /* legal characters in a filename */ #define CONFIG_LEGAL_FILENAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/" +/* legal characters in a nickname */ +#define LEGAL_NICKNAME_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" /* structure of a socks client operation */ typedef struct { @@ -282,6 +285,7 @@ struct connection_t { crypto_pk_env_t *onion_pkey; /* public RSA key for the other side's onions */ crypto_pk_env_t *link_pkey; /* public RSA key for the other side's TLS */ crypto_pk_env_t *identity_pkey; /* public RSA key for the other side's signing */ + char *nickname; /* Used only by OR connections: */ tor_tls *tls; @@ -335,6 +339,8 @@ typedef struct { crypto_pk_env_t *link_pkey; /* public RSA key for TLS */ crypto_pk_env_t *identity_pkey; /* public RSA key for signing */ + int is_running; + /* link info */ uint32_t bandwidth; struct exit_policy_t *exit_policy; @@ -345,6 +351,7 @@ typedef struct { routerinfo_t **routers; int n_routers; char *software_versions; + time_t published_on; } directory_t; struct crypt_path_t { @@ -582,7 +589,6 @@ int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type, /********************************* directory.c ***************************/ void directory_initiate_command(routerinfo_t *router, int command); -void directory_set_dirty(void); int connection_dir_process_inbuf(connection_t *conn); int connection_dir_finished_flushing(connection_t *conn); @@ -618,12 +624,8 @@ void connection_start_reading(connection_t *conn); void connection_stop_writing(connection_t *conn); void connection_start_writing(connection_t *conn); -int dump_signed_directory_to_string(char *s, int maxlen, - crypto_pk_env_t *private_key); -/* Exported for debugging */ -int dump_signed_directory_to_string_impl(char *s, int maxlen, - directory_t *dir, - crypto_pk_env_t *private_key); +int list_running_servers(char **nicknames_out); + const char *router_get_my_descriptor(void); int main(int argc, char *argv[]); @@ -676,7 +678,7 @@ int router_get_router_hash(char *s, char *digest); /* Reads a list of known routers, unsigned. */ int router_get_list_from_string(char *s); /* Exported for debugging */ -int router_get_list_from_string_impl(char **s, directory_t **dest); +int router_get_list_from_string_impl(char **s, directory_t **dest, int n_good_nicknames, const char *good_nickname_lst[]); /* Reads a signed directory. */ int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey); /* Exported or debugging */ @@ -686,6 +688,19 @@ routerinfo_t *router_get_entry_from_string(char **s); int router_compare_to_exit_policy(connection_t *conn); void routerinfo_free(routerinfo_t *router); +/********************************* dirserv.c ***************************/ +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); +void dirserv_free_descriptors(); +int dirserv_dump_directory_to_string(char *s, int maxlen, + crypto_pk_env_t *private_key); +void directory_set_dirty(); +size_t dirserv_get_directory(const char **cp); + + #endif /* diff --git a/src/or/routers.c b/src/or/routers.c index 3a9248cad..9c43cdde3 100644 --- a/src/or/routers.c +++ b/src/or/routers.c @@ -319,6 +319,7 @@ typedef enum { K_LINK_KEY, K_ROUTER_SIGNATURE, K_PUBLISHED, + K_RUNNING_ROUTERS, _SIGNATURE, _PUBLIC_KEY, _ERR, @@ -339,10 +340,11 @@ static struct token_table_ent token_table[] = { { "link-key", K_LINK_KEY }, { "router-signature", K_ROUTER_SIGNATURE }, { "published", K_PUBLISHED }, + { "running-routers", K_RUNNING_ROUTERS }, { NULL, -1 } }; -#define MAX_ARGS 8 +#define MAX_ARGS 1024 struct directory_token { directory_keyword tp; union { @@ -495,6 +497,7 @@ router_dump_token(directory_token_t *tok) { case K_LINK_KEY: printf("Link-key"); break; case K_ROUTER_SIGNATURE: printf("Router-signature"); break; case K_PUBLISHED: printf("Published"); break; + case K_RUNNING_ROUTERS: printf("Running-routers"); break; default: printf("?????? %d\n", tok->tp); return; } @@ -551,7 +554,7 @@ static char *find_whitespace(char *s) { int router_get_list_from_string(char *s) { - if (router_get_list_from_string_impl(&s, &directory)) { + if (router_get_list_from_string_impl(&s, &directory, -1, NULL)) { log(LOG_WARNING, "Error parsing router file"); return -1; } @@ -653,6 +656,10 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, char signed_digest[128]; directory_t *new_dir = NULL; char *versions; + struct tm published; + time_t published_on; + const char *good_nickname_lst[1024]; + int n_good_nicknames; #define NEXT_TOK() \ do { \ @@ -676,6 +683,18 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, TOK_IS(K_SIGNED_DIRECTORY, "signed-directory"); NEXT_TOK(); + TOK_IS(K_PUBLISHED, "published"); + if (tok.val.cmd.n_args != 2) { + log_fn(LOG_WARNING, "Invalid published line"); + goto err; + } + tok.val.cmd.args[1][-1] = ' '; + if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) { + log_fn(LOG_WARNING, "Published time was unparseable"); goto err; + } + published_on = timegm(&published); + + NEXT_TOK(); TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software"); if (tok.val.cmd.n_args != 1) { log_fn(LOG_WARNING, "Invalid recommded-software line"); @@ -683,11 +702,18 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, } versions = strdup(tok.val.cmd.args[0]); - if (router_get_list_from_string_impl(&s, &new_dir)) { + NEXT_TOK(); + TOK_IS(K_RUNNING_ROUTERS, "running-routers"); + n_good_nicknames = tok.val.cmd.n_args; + memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames); + + if (router_get_list_from_string_impl(&s, &new_dir, + n_good_nicknames, good_nickname_lst)) { log_fn(LOG_WARNING, "Error reading routers from directory"); goto err; } new_dir->software_versions = versions; + new_dir->published_on = published_on; NEXT_TOK(); TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature"); @@ -725,11 +751,14 @@ int router_get_dir_from_string_impl(char *s, directory_t **dest, #undef TOK_IS } -int router_get_list_from_string_impl(char **s, directory_t **dest) +int router_get_list_from_string_impl(char **s, directory_t **dest, + int n_good_nicknames, + const char **good_nickname_lst) { routerinfo_t *router; routerinfo_t **rarray; int rarray_len = 0; + int i, router_is_running; assert(s); @@ -749,6 +778,15 @@ int router_get_list_from_string_impl(char **s, directory_t **dest) routerinfo_free(router); continue; } + if (n_good_nicknames>=0) { + router->is_running = 0; + for (i = 0; i < n_good_nicknames; ++i) { + if (0==strcasecmp(good_nickname_lst[i], router->nickname)) { + router->is_running = 1; + break; + } + } + } rarray[rarray_len++] = router; } @@ -846,31 +884,38 @@ routerinfo_t *router_get_entry_from_string(char**s) { thank me for this someday. */ router->onion_pkey = router->identity_pkey = router->link_pkey = NULL; - if (tok->val.cmd.n_args != 5) { + if (tok->val.cmd.n_args != 6) { log_fn(LOG_WARNING,"Wrong # of arguments to \"router\""); goto err; } - + if (!(router->nickname = strdup(ARGS[0]))) + goto err; + if (strlen(router->nickname) > MAX_NICKNAME_LEN) + goto err; + if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) != + strlen(router->nickname)) + goto err; + /* read router.address */ - if (!(router->address = strdup(ARGS[0]))) + if (!(router->address = strdup(ARGS[1]))) goto err; router->addr = 0; /* Read router->or_port */ - router->or_port = atoi(ARGS[1]); + router->or_port = atoi(ARGS[2]); if(!router->or_port) { log_fn(LOG_WARNING,"or_port unreadable or 0. Failing."); goto err; } /* Router->ap_port */ - router->ap_port = atoi(ARGS[2]); + router->ap_port = atoi(ARGS[3]); /* Router->dir_port */ - router->dir_port = atoi(ARGS[3]); + router->dir_port = atoi(ARGS[4]); /* Router->bandwidth */ - router->bandwidth = atoi(ARGS[4]); + router->bandwidth = atoi(ARGS[5]); if (!router->bandwidth) { log_fn(LOG_WARNING,"bandwidth unreadable or 0. Failing."); } @@ -885,8 +930,8 @@ routerinfo_t *router_get_entry_from_string(char**s) { if (tok->val.cmd.n_args != 2) { log_fn(LOG_WARNING, "Wrong number of arguments to published"); goto err; } - tok->val.cmd.args[1][-1] = ' '; /* Re-insert space. */ - if (!strptime(tok->val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) { + ARGS[1][-1] = ' '; /* Re-insert space. */ + if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) { log_fn(LOG_WARNING, "Published time was unparseable"); goto err; } router->published_on = timegm(&published); @@ -1073,127 +1118,6 @@ int router_compare_to_exit_policy(connection_t *conn) { return 0; /* accept all by default. */ } -/*** Fingerprint handling code. ***/ -typedef struct fingerprint_entry_t { - char *nickname; - char *fingerprint; -} fingerprint_entry_t; - -static fingerprint_entry_t fingerprint_list[MAX_ROUTERS_IN_DIR]; -static int n_fingerprints = 0; -/* return 0 on success, -1 on failure */ -int directory_parse_fingerprint_file(const char *fname) -{ - FILE *file; -#define BUF_LEN (FINGERPRINT_LEN+MAX_NICKNAME_LEN+20) - char buf[BUF_LEN+1]; - char *cp, *nickname, *fingerprint; - fingerprint_entry_t fingerprint_list_tmp[MAX_ROUTERS_IN_DIR]; - int n_fingerprints_tmp = 0; - int lineno=0; - int i; - if (!(file = fopen(fname, "r"))) { - log(LOG_WARNING, "Cannot open fingerprint file %s", fname); - goto err; - } - while (1) { - cp = fgets(buf, BUF_LEN, file); - ++lineno; - if (!cp) { - if (feof(file)) - break; - else { - log(LOG_WARNING, "Error reading from fingerprint file"); - goto err; - } - } - buf[BUF_LEN]='\0'; - cp = buf; - while (isspace(*cp)) - ++cp; - if (*cp == '#' || *cp == '\0') - continue; - nickname = cp; - cp = strchr(cp, ' '); - if (!cp) { - log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); - goto err; - } - *cp++ = '\0'; - while (isspace(*cp)) - ++cp; - if (strlen(cp) < FINGERPRINT_LEN) { - log(LOG_WARNING, "Bad line %d of fingerprint file", lineno); - goto err; - } - fingerprint = cp; - cp[FINGERPRINT_LEN] = '\0'; - if (strlen(nickname) > MAX_NICKNAME_LEN) { - log(LOG_WARNING, "Nickname too long on line %d of fingerprint file", - lineno); - goto err; - } - if (!crypto_pk_check_fingerprint_syntax(fingerprint)) { - log(LOG_WARNING, "Invalid fingerprint on line %d of fingerprint file", - lineno); - goto err; - } - for (i = 0; i < n_fingerprints_tmp; ++i) { - if (0==strcasecmp(fingerprint_list_tmp[i].nickname, nickname)) { - log(LOG_WARNING, "Duplicate nickname on line %d of fingerprint file", lineno); - goto err; - } - } - fingerprint_list_tmp[n_fingerprints_tmp].nickname = strdup(nickname); - fingerprint_list_tmp[n_fingerprints_tmp].fingerprint = strdup(fingerprint); - ++n_fingerprints_tmp; - } - /* replace the global fingerprints list. */ - for (i = 0; i < n_fingerprints; ++i) { - free(fingerprint_list[i].nickname); - free(fingerprint_list[i].fingerprint); - } - memcpy(fingerprint_list, fingerprint_list_tmp, - sizeof(fingerprint_entry_t)*n_fingerprints_tmp); - n_fingerprints = n_fingerprints_tmp; - return 0; - - err: - for (i = 0; i < n_fingerprints_tmp; ++i) { - free(fingerprint_list_tmp[i].nickname); - free(fingerprint_list_tmp[i].fingerprint); - } - return -1; -#undef BUF_LEN -} - -/* return 1 if router's identity and nickname match. */ -int -directory_check_router_identity(const routerinfo_t *router) -{ - int i; - char fp[FINGERPRINT_LEN+1]; - if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) { - /* XXX Error computing fingerprint: log */ - return 0; - } - for (i=0;i<n_fingerprints;++i) { - if (0==strcasecmp(fingerprint_list[i].nickname,router->nickname)) { - /* Right nickname... */ - if (0==strcasecmp(fingerprint_list[i].fingerprint, fp)) { - /* Right fingerprint. */ - return 1; - } else { - /* Wrong fingerprint. */ - return 0; - } - } - } - /* No match found. XXX log. */ - return 0; -} - - /* Local Variables: |