diff options
-rw-r--r-- | src/or/config.c | 57 | ||||
-rw-r--r-- | src/or/directory.c | 104 | ||||
-rw-r--r-- | src/or/or.h | 13 | ||||
-rw-r--r-- | src/or/routerlist.c | 159 | ||||
-rw-r--r-- | src/or/routerparse.c | 7 |
5 files changed, 270 insertions, 70 deletions
diff --git a/src/or/config.c b/src/or/config.c index c605d2b42..5fb19bc3d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -34,6 +34,7 @@ static int config_get_lines(FILE *f, struct config_line_t **result); static void config_free_lines(struct config_line_t *front); static int config_compare(struct config_line_t *c, const char *key, config_type_t type, void *arg); static int config_assign(or_options_t *options, struct config_line_t *list); +static int parse_dir_server_line(const char *line); /** Helper: Read a list of configuration options from the command line. */ static struct config_line_t *config_get_commandlines(int argc, char **argv) { @@ -205,6 +206,7 @@ static int config_assign(or_options_t *options, struct config_line_t *list) { config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) || config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) || config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) || + config_compare(list, "DirServer", CONFIG_TYPE_LINELIST, &options->DirServers) || config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) || config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) || @@ -387,6 +389,11 @@ int config_assign_default_dirservers(void) { log_fn(LOG_WARN,"Bug: the default dirservers internal string is corrupt."); return -1; } +#if 0 + parse_dir_server_line("18.244.0.188:9031 XXXX"); + parse_dir_server_line("18.244.0.188:9032 XXXX"); + parse_dir_server_line("62.116.124.106:9030 XXXX"); +#endif return 0; } @@ -535,6 +542,7 @@ static void free_options(or_options_t *options) { config_free_lines(options->DirBindAddress); config_free_lines(options->ExitPolicy); config_free_lines(options->SocksPolicy); + config_free_lines(options->DirServers); if (options->FirewallPorts) { SMARTLIST_FOREACH(options->FirewallPorts, char *, cp, tor_free(cp)); smartlist_free(options->FirewallPorts); @@ -573,6 +581,7 @@ static void init_options(or_options_t *options) { options->NumCpus = 1; options->RendConfigLines = NULL; options->FirewallPorts = NULL; + options->DirServers = NULL; } static char *get_default_conf_file(void) @@ -856,6 +865,11 @@ int getconfig(int argc, char **argv, or_options_t *options) { result = -1; } + for (cl = options->DirServers; cl; cl = cl->next) { + if (parse_dir_server_line(cl->value)<0) + return -1; + } + /* XXX look at the various nicknamelists and make sure they're * valid and don't have hostnames that are too long. */ @@ -1025,6 +1039,49 @@ void exit_policy_free(struct exit_policy_t *p) { } } +static int parse_dir_server_line(const char *line) +{ + smartlist_t *items = NULL; + int r; + char *addrport, *address=NULL; + uint16_t port; + char digest[DIGEST_LEN]; + items = smartlist_create(); + smartlist_split_string(items, line, " ", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); + if (smartlist_len(items) < 2) { + log_fn(LOG_WARN, "Too few arguments to DirServer line."); goto err; + } + addrport = smartlist_get(items, 0); + if (parse_addr_port(addrport, &address, NULL, &port)<0) { + log_fn(LOG_WARN, "Error parsing DirServer address '%s'", addrport);goto err; + } + if (!port) { + log_fn(LOG_WARN, "Missing port in DirServe address '%s'",addrport);goto err; + } + + tor_strstrip(smartlist_get(items, 1), " "); + if (strlen(smartlist_get(items, 1)) != HEX_DIGEST_LEN) { + log_fn(LOG_WARN, "Key digest for DirServer is wrong length."); goto err; + } + if (base16_decode(digest, DIGEST_LEN, + smartlist_get(items,1), HEX_DIGEST_LEN)<0) { + log_fn(LOG_WARN, "Unable to decode DirServer key digest."); goto err; + } + + add_trusted_dir_server(address, port, digest); + + r = 0; + goto done; + err: + r = -1; + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + if (address) tor_free(address); + return r; +} + const char *get_data_directory(or_options_t *options) { const char *d; if (options->DataDirectory) diff --git a/src/or/directory.c b/src/or/directory.c index 0393f43e7..62e66d1a2 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -27,10 +27,21 @@ */ static void -directory_initiate_command(routerinfo_t *router, uint8_t purpose, +directory_initiate_command_router(routerinfo_t *router, uint8_t purpose, + const char *payload, int payload_len); +static void +directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv, + uint8_t purpose, const char *payload, int payload_len); + +static void +directory_initiate_command(const char *address, uint32_t addr, uint16_t port, + const char *platform, + const char *digest, uint8_t purpose, const char *payload, int payload_len); + static void -directory_send_command(connection_t *conn, routerinfo_t *router, int purpose, +directory_send_command(connection_t *conn, const char *platform, + uint16_t dir_port, int purpose, const char *payload, int payload_len); static int directory_handle_command(connection_t *conn); @@ -75,7 +86,7 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload, /* Note: this posts our descriptor to ourselves, if we're an * authdirserver. But I think that's ok. */ if(router->is_trusted_dir) - directory_initiate_command(router, purpose, payload, payload_len); + directory_initiate_command_router(router, purpose, payload, payload_len); } } @@ -88,29 +99,37 @@ void directory_get_from_dirserver(uint8_t purpose, const char *payload, int payload_len) { - routerinfo_t *ds; + routerinfo_t *r = NULL; + trusted_dir_server_t *ds = NULL; if (purpose == DIR_PURPOSE_FETCH_DIR) { if (advertised_server_mode()) { /* only ask authdirservers, and don't ask myself */ - ds = router_pick_directory_server(1, 1); + r = router_pick_directory_server(1, 1); + /* XXXX NM Enable this once we actually set keys for dirservers. + * ds = router_pick_trusteddirserver(1); + */ } else { /* anybody with a non-zero dirport will do */ - ds = router_pick_directory_server(0, 1); + r = router_pick_directory_server(0, 1); } } else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC) /* only ask authdirservers, any of them will do */ - ds = router_pick_directory_server(1, 0); + r = router_pick_directory_server(1, 0); + /* XXXX NM Enable this once we actually set keys for dirservers. + * ds = router_pick_trusteddirserver(0); + */ } - if (!ds) { /* no viable dirserver found */ + if (r) + directory_initiate_command_router(r, purpose, payload, payload_len); + else if (ds) + directory_initiate_command_trusted_dir(ds, purpose, payload, payload_len); + else log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose); - return; - } - - directory_initiate_command(ds, purpose, payload, payload_len); } + /** Launch a new connection to the directory server <b>router</b> to upload or * download a service or rendezvous descriptor. <b>purpose</b> determines what * kind of directory connection we're launching, and must be one of @@ -121,13 +140,31 @@ directory_get_from_dirserver(uint8_t purpose, const char *payload, * and <b>payload_len</b> are the service ID we want to fetch. */ static void -directory_initiate_command(routerinfo_t *router, uint8_t purpose, +directory_initiate_command_router(routerinfo_t *router, uint8_t purpose, + const char *payload, int payload_len) +{ + directory_initiate_command(router->address, router->addr, router->dir_port, + router->platform, router->identity_digest, + purpose, payload, payload_len); +} + +static void +directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv, + uint8_t purpose, const char *payload, int payload_len) +{ + directory_initiate_command(dirserv->address, dirserv->addr, dirserv->dir_port, + NULL, dirserv->digest, purpose, payload, payload_len); +} + +static void +directory_initiate_command(const char *address, uint32_t addr, + uint16_t dir_port, const char *platform, + const char *digest, uint8_t purpose, const char *payload, int payload_len) { connection_t *conn; - tor_assert(router); - tor_assert(router->dir_port); + tor_assert(address && addr && dir_port && digest); switch (purpose) { case DIR_PURPOSE_FETCH_DIR: @@ -154,14 +191,15 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, conn->addr = options.HttpProxyAddr; conn->port = options.HttpProxyPort; } else { - conn->addr = router->addr; - conn->port = router->dir_port; + conn->addr = addr; + conn->port = dir_port; } - conn->address = tor_strdup(router->address); - conn->nickname = tor_strdup(router->nickname); - tor_assert(router->identity_pkey); - conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); - crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); + conn->address = tor_strdup(address); + /* conn->nickname = tor_strdup(router->nickname); */ + /* tor_assert(router->identity_pkey); */ + /* conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); */ + /* crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); */ + memcpy(conn->identity_digest, digest, DIGEST_LEN); conn->purpose = purpose; @@ -185,7 +223,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, /* fall through */ case 0: /* queue the command on the outbuf */ - directory_send_command(conn, router, purpose, payload, payload_len); + directory_send_command(conn, platform, dir_port, + purpose, payload, payload_len); connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); /* writable indicates finish, readable indicates broken link, @@ -206,7 +245,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, conn->state = DIR_CONN_STATE_CLIENT_SENDING; connection_add(conn); /* queue the command on the outbuf */ - directory_send_command(conn, router, purpose, payload, payload_len); + directory_send_command(conn, platform, dir_port, + purpose, payload, payload_len); connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); } } @@ -216,7 +256,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose, * directory_initiate_command. */ static void -directory_send_command(connection_t *conn, routerinfo_t *router, int purpose, +directory_send_command(connection_t *conn, const char *platform, + uint16_t dir_port, int purpose, const char *payload, int payload_len) { char tmp[8192]; char proxystring[128]; @@ -226,14 +267,15 @@ directory_send_command(connection_t *conn, routerinfo_t *router, int purpose, char *httpcommand = NULL; tor_assert(conn && conn->type == CONN_TYPE_DIR); - tor_assert(router); + tor_assert(dir_port && conn); - use_newer = tor_version_as_new_as(router->platform, "0.0.9pre1"); + /* If we don't know the platform, assume it's up-to-date. */ + use_newer = platform ? tor_version_as_new_as(platform, "0.0.9pre1"):1; - if(router->dir_port == 80) { - strlcpy(hoststring, router->address, sizeof(hoststring)); + if(dir_port == 80) { + strlcpy(hoststring, conn->address, sizeof(hoststring)); } else { - sprintf(hoststring, "%s:%d", router->address, router->dir_port); + sprintf(hoststring, "%s:%d", conn->address, dir_port); } if(options.HttpProxy) { sprintf(proxystring, "http://%s", hoststring); @@ -245,7 +287,7 @@ directory_send_command(connection_t *conn, routerinfo_t *router, int purpose, case DIR_PURPOSE_FETCH_DIR: tor_assert(payload == NULL); log_fn(LOG_DEBUG, "Asking for %scompressed directory from server running %s", - use_newer?"":"un", router->platform); + use_newer?"":"un", platform?platform:"<unknown version>"); httpcommand = "GET"; strlcpy(url, use_newer ? "/tor/dir.z" : "/", sizeof(url)); break; diff --git a/src/or/or.h b/src/or/or.h index e8a4355ed..b8a72ae2b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -900,6 +900,9 @@ typedef struct { uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */ uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */ + struct config_line_t *DirServers; /**< List of configuration lines + * for directory servers. */ + } or_options_t; /* XXX are these good enough defaults? */ @@ -1397,8 +1400,17 @@ int is_legal_nickname_or_hexdigest(const char *s); /********************************* routerlist.c ***************************/ +typedef struct trusted_dir_server_t { + char *address; + uint32_t addr; + uint16_t dir_port; + char digest[DIGEST_LEN]; + int is_running; +} trusted_dir_server_t; + int router_reload_router_list(void); routerinfo_t *router_pick_directory_server(int requireauth, int requireothers); +trusted_dir_server_t *router_pick_trusteddirserver(int requireothers); int all_directory_servers_down(void); struct smartlist_t; void routerlist_add_friends(struct smartlist_t *sl, routerinfo_t *router); @@ -1440,6 +1452,7 @@ void routerlist_update_from_runningrouters(routerlist_t *list, int router_update_status_from_smartlist(routerinfo_t *r, time_t list_time, smartlist_t *running_list); +void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest); /********************************* routerparse.c ************************/ diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 66a8d7c5e..1bcaeb4ee 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -18,17 +18,19 @@ extern or_options_t options; /**< command-line and config-file options */ /* ********************************************************************** */ +static smartlist_t *trusted_dir_servers = NULL; + /* static function prototypes */ static routerinfo_t * router_pick_directory_server_impl(int requireauth, int requireothers, int fascistfirewall); -static void mark_all_authdirservers_up(void); +static trusted_dir_server_t * +router_pick_trusteddirserver_impl(int requireother, int fascistfirewall); +static void mark_all_trusteddirservers_up(void); static int router_resolve_routerlist(routerlist_t *dir); +static void clear_trusted_dir_servers(void); /****************************************************************************/ -/** List of digests of keys for servers that are trusted directories. */ -static smartlist_t *trusted_dir_digests = NULL; - /**** * Functions to manage and access our list of known routers. (Note: * dirservers maintain a separate, independent list of known router @@ -92,7 +94,7 @@ routerinfo_t *router_pick_directory_server(int requireauth, int requireothers) { log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again."); /* mark all authdirservers as up again */ - mark_all_authdirservers_up(); + mark_all_trusteddirservers_up(); /* try again */ choice = router_pick_directory_server_impl(requireauth, requireothers, 0); if(choice) @@ -110,6 +112,34 @@ routerinfo_t *router_pick_directory_server(int requireauth, int requireothers) { return choice; } +trusted_dir_server_t *router_pick_trusteddirserver(int requireothers) { + trusted_dir_server_t *choice; + + choice = router_pick_trusteddirserver_impl(requireothers, + options.FascistFirewall); + if(choice) + return choice; + + log_fn(LOG_INFO,"No trusted dirservers are reachable. Trying them all again."); + /* mark all authdirservers as up again */ + mark_all_trusteddirservers_up(); + /* try again */ + choice = router_pick_trusteddirserver_impl(requireothers, 0); + if(choice) + return choice; + + log_fn(LOG_WARN,"Still no dirservers %s. Reloading and trying again.", + options.FascistFirewall ? "reachable" : "known"); + has_fetched_directory=0; /* reset it */ + routerlist_clear_trusted_directories(); + if(router_reload_router_list()) { + return NULL; + } + /* give it one last try */ + choice = router_pick_trusteddirserver_impl(requireothers, 0); + return choice; +} + /** Pick a random running router from our routerlist. If requireauth, * it has to be a trusted server. If requireothers, it cannot be us. */ @@ -147,21 +177,48 @@ router_pick_directory_server_impl(int requireauth, int requireothers, int fascis return router; } -/** Go through and mark the auth dirservers as up */ -static void mark_all_authdirservers_up(void) { - int i; - routerinfo_t *router; +static trusted_dir_server_t * +router_pick_trusteddirserver_impl(int requireother, int fascistfirewall) +{ + smartlist_t *sl; + routerinfo_t *me; + char buf[16]; + trusted_dir_server_t *ds; + sl = smartlist_create(); + me = router_get_my_routerinfo(); - if(!routerlist) - return; + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d, + { + if (!d->is_running) continue; + if (requireother && me && + !memcmp(me->identity_digest, d->digest, DIGEST_LEN)) + continue; + if (fascistfirewall) { + sprintf(buf,"%d",d->dir_port); + if (!smartlist_string_isin(options.FirewallPorts, buf)) + continue; + } + smartlist_add(sl, d); + }); - for(i=0; i < smartlist_len(routerlist->routers); i++) { - router = smartlist_get(routerlist->routers, i); - if(router->is_trusted_dir) { - tor_assert(router->dir_port > 0); - router->is_running = 1; - router->status_set_at = time(NULL); - } + ds = smartlist_choose(sl); + smartlist_free(sl); + return ds; +} + +/** Go through and mark the auth dirservers as up */ +static void mark_all_trusteddirservers_up(void) { + if(routerlist) { + SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, + if(router->is_trusted_dir) { + tor_assert(router->dir_port > 0); + router->is_running = 1; + router->status_set_at = time(NULL); + }); + } + if (trusted_dir_servers) { + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir, + dir->is_running = 1); } } @@ -180,6 +237,12 @@ int all_directory_servers_down(void) { return 0; } } + /* XXXX NM look at trusted_dir_servers instead. + if (!trusted_dir_servers) + return 1; + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir, + if (dir->is_running) return 0); + */ return 1; } @@ -477,14 +540,13 @@ routerinfo_t *router_get_by_nickname(const char *nickname) return NULL; } -/* XXX008 currently this trusted_dir_digests stuff is not used. */ /** Return true iff <b>digest</b> is the digest of the identity key of * a trusted directory. */ int router_digest_is_trusted_dir(const char *digest) { - if (!trusted_dir_digests) + if (!trusted_dir_servers) return 0; - SMARTLIST_FOREACH(trusted_dir_digests, char *, cp, - if (!memcmp(digest, cp, DIGEST_LEN)) return 1); + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent, + if (!memcmp(digest, ent->digest, DIGEST_LEN)) return 1); return 0; } @@ -586,6 +648,11 @@ void routerlist_free(routerlist_t *rl) void router_mark_as_down(const char *digest) { routerinfo_t *router; tor_assert(digest); + + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d, + if (!memcmp(d->digest, digest, DIGEST_LEN)) + d->is_running = 0); + router = router_get_by_digest(digest); if(!router) /* we don't seem to know about him in the first place */ return; @@ -619,7 +686,9 @@ int router_add_to_routerlist(routerinfo_t *router) { log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]", router->nickname, r->nickname, hex_str(id_digest,DIGEST_LEN)); /* Remember whether we trust this router as a dirserver. */ - if (r->is_trusted_dir) + /*XXXXNM first test is redundant; second should move elsewhere */ + if (r->is_trusted_dir || + router_digest_is_trusted_dir(router->identity_digest)) router->is_trusted_dir = 1; /* If the address hasn't changed; no need to re-resolve. */ if (!strcasecmp(r->address, router->address)) @@ -735,10 +804,7 @@ void routerlist_clear_trusted_directories(void) SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r, r->is_trusted_dir = 0); } - if (trusted_dir_digests) { - SMARTLIST_FOREACH(trusted_dir_digests, char *, cp, tor_free(cp)); - smartlist_clear(trusted_dir_digests); - } + clear_trusted_dir_servers(); } /** Helper function: read routerinfo elements from s, and throw out the @@ -760,17 +826,12 @@ int router_load_routerlist_from_string(const char *s, int trusted) } if (trusted) { int i; - if (!trusted_dir_digests) - trusted_dir_digests = smartlist_create(); for (i=0;i<smartlist_len(new_list->routers);++i) { routerinfo_t *r = smartlist_get(new_list->routers, i); if (r->dir_port) { - char *b; log_fn(LOG_DEBUG,"Trusting router %s.", r->nickname); r->is_trusted_dir = 1; - b = tor_malloc(DIGEST_LEN); - memcpy(b, r->identity_digest, DIGEST_LEN); - smartlist_add(trusted_dir_digests, b); + add_trusted_dir_server(r->address, r->dir_port, r->identity_digest); } } } @@ -1079,6 +1140,38 @@ int router_update_status_from_smartlist(routerinfo_t *router, return 0; } +void add_trusted_dir_server(const char *addr, uint16_t port, const char *digest) +{ + trusted_dir_server_t *ent; + uint32_t a; + if (!trusted_dir_servers) + trusted_dir_servers = smartlist_create(); + + if (tor_lookup_hostname(addr, &a)) { + log_fn(LOG_WARN, "Unable to lookup address for directory server at %s", + addr); + return; + } + + ent = tor_malloc(sizeof(trusted_dir_server_t)); + ent->address = tor_strdup(addr); + ent->addr = a; + ent->dir_port = port; + ent->is_running = 1; + memcpy(ent->digest, digest, DIGEST_LEN); +} + +static void clear_trusted_dir_servers(void) +{ + if (trusted_dir_servers) { + SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent, + { tor_free(ent->address); tor_free(ent); }); + smartlist_clear(trusted_dir_servers); + } else { + trusted_dir_servers = smartlist_create(); + } +} + /* Local Variables: mode:c diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 4ce8684bb..9d999e884 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -577,17 +577,12 @@ static crypto_pk_env_t *find_dir_signing_key(const char *str) static int dir_signing_key_is_trusted(crypto_pk_env_t *key) { char digest[DIGEST_LEN]; - routerinfo_t *r; if (!key) return 0; if (crypto_pk_get_digest(key, digest) < 0) { log_fn(LOG_WARN, "Error computing dir-signing-key digest"); return 0; } - if (!(r = router_get_by_digest(digest))) { - log_fn(LOG_WARN, "No router known with given dir-signing-key digest"); - return 0; - } - if (! r->is_trusted_dir) { + if(!router_digest_is_trusted_dir(digest)) { log_fn(LOG_WARN, "Listed dir-signing-key is not trusted"); return 0; } |