From 9c67ae34f106828d5035b4f8a466766ce60a83a5 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Mon, 20 Jun 2005 23:04:13 +0000 Subject: [PATCH] overall cleanup and streamlining and doccing also fix a DoS avenue on dirservers svn:r4468 --- src/or/buffers.c | 29 ------ src/or/connection_or.c | 119 ++++++++++++----------- src/or/directory.c | 8 -- src/or/dirserv.c | 20 +--- src/or/or.h | 12 +-- src/or/routerlist.c | 252 ++++++++++++++++++++++++------------------------- 6 files changed, 200 insertions(+), 240 deletions(-) diff --git a/src/or/buffers.c b/src/or/buffers.c index 7b8f919ccd..8e097c9dde 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -263,34 +263,6 @@ buf_ensure_capacity(buf_t *buf, size_t capacity) return 0; } -#if 0 -/** If the buffer is at least 2*MIN_GREEDY_SHRINK_SIZE bytes in capacity, - * and if the buffer is less than 1/8 full, shrink the buffer until - * one of the above no longer holds. (We shrink the buffer by - * dividing by powers of 2.) - */ -static INLINE void -buf_shrink_if_underfull(buf_t *buf) { - size_t new_len; - /* If the buffer is at least 1/8 full, or if shrinking the buffer would - * put it under MIN_GREEDY_SHRINK_SIZE, don't do it. */ - if (buf->datalen >= (buf->len>>3) || buf->len < MIN_GREEDY_SHRINK_SIZE*2) - return; - /* Shrink new_len by powers of 2 until: datalen is at least 1/4 of - * new_len, OR shrinking new_len more would put it under - * MIN_GREEDY_SHRINK_SIZE. - */ - new_len = (buf->len>>1); - while (buf->datalen < (new_len>>3) && new_len > MIN_GREEDY_SHRINK_SIZE*2) - new_len >>= 1; - log_fn(LOG_DEBUG,"Shrinking buffer from %d to %d bytes.", - (int)buf->len, (int)new_len); - buf_resize(buf, new_len); -} -#else -#define buf_shrink_if_underfull(buf) do {} while (0) -#endif - /** Resize buf so it won't hold extra memory that we haven't been * using lately (that is, since the last time we called buf_shrink). * Try to shrink the buf until it is the largest factor of two that @@ -326,7 +298,6 @@ buf_remove_from_front(buf_t *buf, size_t n) { } else { buf->cur = buf->mem; } - buf_shrink_if_underfull(buf); check(); } diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 0182402baa..c765e38116 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -430,7 +430,13 @@ connection_tls_continue_handshake(connection_t *conn) static char ZERO_DIGEST[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -/** DOCDOC */ +/** Return 1 if we initiated this connection, or 0 if it started + * out as an incoming connection. + * + * This is implemented for now by checking to see if + * conn-\>identity_digest is set or not. Perhaps we should add a flag + * one day so we're clearer. + */ int connection_or_nonopen_was_started_here(connection_t *conn) { @@ -443,42 +449,35 @@ connection_or_nonopen_was_started_here(connection_t *conn) return 1; } -/** The tls handshake is finished. +/** Conn just completed its handshake. Return 0 if all is well, and + * return -1 if he is lying, broken, or otherwise something is wrong. * - * Make sure we are happy with the person we just handshaked with: - * If it's an OP (that is, it has no certificate), make sure I'm an OR. - * If it's an OR (it has a certificate), make sure it has a recognized - * nickname, and its cert is signed by the identity key of that nickname. - * If I initiated the connection, make sure it's the right guy; and if - * he initiated the connection, make sure he's not already connected. + * Make sure he sent a correctly formed certificate. If it has a + * recognized (approved) nickname, make sure his identity key matches + * to it. If I initiated the connection, make sure it's the right guy. * - * If he initiated the conn, also initialize conn from the information - * in router. + * If we return 0, write a hash of the identity key into digest_rcvd, + * which must have DIGEST_LEN space in it. (If we return -1 this + * buffer is undefined.) * - * If either of us is an OP, set bandwidth to the default OP bandwidth. - * - * If all is successful and he's an OR, then call circuit_n_conn_done() - * to handle events that have been pending on the tls handshake - * completion, and set the directory to be dirty (only matters if I'm - * an authdirserver). + * As side effects, + * 1) Set conn->circ_id_type according to tor-spec.txt + * 2) If we're an authdirserver and we initiated the connection: drop all + * descriptors that claim to be on that IP/port but that aren't + * this guy; and note that this guy is reachable. */ -static int -connection_tls_finish_handshake(connection_t *conn) -{ +int +connection_or_check_valid_handshake(connection_t *conn, char *digest_rcvd) { routerinfo_t *router; - char nickname[MAX_NICKNAME_LEN+1]; - connection_t *c; crypto_pk_env_t *identity_rcvd=NULL; - char digest_rcvd[DIGEST_LEN]; + char nickname[MAX_NICKNAME_LEN+1]; or_options_t *options = get_options(); int severity = (authdir_mode(options) || !server_mode(options)) ? LOG_WARN : LOG_INFO; - log_fn(LOG_DEBUG,"tls handshake done. verifying."); check_no_tls_errors(); if (! tor_tls_peer_has_cert(conn->tls)) { log_fn(LOG_INFO,"Peer didn't send a cert! Closing."); - /* XXX we should handle this case rather than just closing. */ return -1; } check_no_tls_errors(); @@ -497,13 +496,6 @@ connection_tls_finish_handshake(connection_t *conn) return -1; } check_no_tls_errors(); -#if 0 - if (tor_tls_check_lifetime(conn->tls, LOOSE_CERT_ALLOW_SKEW)<0) { - log_fn(LOG_WARN,"Other side '%s' (%s:%d) has a very highly skewed clock, or an expired certificate. Closing.", - nickname, conn->address, conn->port); - return -1; - } -#endif log_fn(LOG_DEBUG,"The router's cert is valid."); crypto_pk_get_digest(identity_rcvd, digest_rcvd); @@ -523,25 +515,9 @@ connection_tls_finish_handshake(connection_t *conn) nickname, conn->address, conn->port); return -1; } -#if 0 - if (router_get_by_digest(digest_rcvd)) { - /* This is a known router; don't cut it slack with its clock skew. */ - if (tor_tls_check_lifetime(conn->tls, TIGHT_CERT_ALLOW_SKEW)<0) { - log_fn(LOG_WARN,"Router '%s' (%s:%d) has a skewed clock, or an expired certificate; or else our clock is skewed. Closing.", - nickname, conn->address, conn->port); - return -1; - } - } -#endif if (connection_or_nonopen_was_started_here(conn)) { - if (authdir_mode(options)) { - /* We initiated this connection to address:port. Drop all routers - * with the same address:port and a different key or nickname. - */ - dirserv_orconn_tls_done(conn->address, conn->port, - digest_rcvd, nickname); - } + int as_advertised = 1; if (conn->nickname[0] == '$') { /* I was aiming for a particular digest. Did I get it? */ char d[HEX_DIGEST_LEN+1]; @@ -551,7 +527,7 @@ connection_tls_finish_handshake(connection_t *conn) "Identity key not as expected for router at %s:%d: wanted %s but got %s", conn->address, conn->port, conn->nickname, d); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); - return -1; + as_advertised = 0; } } else if (strcasecmp(conn->nickname, nickname)) { /* I was aiming for a nickname. Did I get it? */ @@ -559,17 +535,54 @@ connection_tls_finish_handshake(connection_t *conn) "Other side (%s:%d) is '%s', but we tried to connect to '%s'", conn->address, conn->port, nickname, conn->nickname); control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED); - return -1; + as_advertised = 0; } - } else { + if (authdir_mode(options)) { + /* We initiated this connection to address:port. Drop all routers + * with the same address:port and a different key or nickname. + */ + dirserv_orconn_tls_done(conn->address, conn->port, + digest_rcvd, nickname, as_advertised); + } + if (!as_advertised) + return -1; + } + return 0; +} + +/** The tls handshake is finished. + * + * Make sure we are happy with the person we just handshaked with. + * + * If he initiated the connection, make sure he's not already connected, + * then initialize conn from the information in router. + * + * If I'm not a server, set bandwidth to the default OP bandwidth. + * + * If all is successful, call circuit_n_conn_done() to handle events + * that have been pending on the tls handshake completion. Also set the + * directory to be dirty (only matters if I'm an authdirserver). + */ +static int +connection_tls_finish_handshake(connection_t *conn) +{ + char digest_rcvd[DIGEST_LEN]; + + log_fn(LOG_DEBUG,"tls handshake done. verifying."); + if (connection_or_check_valid_handshake(conn, digest_rcvd) < 0) + return -1; + + if (!connection_or_nonopen_was_started_here(conn)) { + connection_t *c; if ((c=connection_get_by_identity_digest(digest_rcvd, CONN_TYPE_OR))) { - log_fn(LOG_INFO,"Router '%s' is already connected on fd %d. Dropping fd %d.", nickname, c->s, conn->s); + log_fn(LOG_INFO,"Router '%s' is already connected on fd %d. Dropping fd %d.", + c->nickname, c->s, conn->s); return -1; } connection_or_init_conn_from_address(conn,conn->addr,conn->port,digest_rcvd); } - if (!server_mode(options)) { /* If I'm an OP... */ + if (!server_mode(get_options())) { /* If I'm an OP... */ conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP; } diff --git a/src/or/directory.c b/src/or/directory.c index 4f53078fa9..be88cb164d 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -54,14 +54,6 @@ static int purpose_is_private(uint8_t purpose); static addr_policy_t *dir_policy = NULL; -#if 0 /* commented out for now, since for now what clients send is - different from what servers want to receive */ -/** URL for publishing rendezvous descriptors. */ -char rend_publish_string[] = "/tor/rendezvous/publish"; -/** Prefix for downloading rendezvous descriptors. */ -char rend_fetch_url[] = "/tor/rendezvous/"; -#endif - #define ALLOW_DIRECTORY_TIME_SKEW 30*60 /* 30 minutes */ /********* END VARIABLES ************/ diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 152c992ee5..fcf9411e98 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -819,20 +819,6 @@ dirserv_regenerate_directory(void) return -1; } -#if 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 = tor_strdup(the_directory); - /* use a new copy of the dir, since get_dir_from_string scribbles on it */ - if (router_load_routerlist_from_directory(new_directory, - get_identity_key(), 1, 0)) { - log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying."); - tor_cleanup(); - exit(0); - } - tor_free(new_directory); -#endif the_directory_is_dirty = 0; /* Save the directory to disk so we re-load it quickly on startup. @@ -962,12 +948,16 @@ dirserv_get_runningrouters(const char **rr, int compress) * nickname_rcvd. When this happens, it's clear that any other * descriptors for that address/port combination must be unusable: * delete them if they are not verified. + * + * Also, if as_advertised is 1, then inform the reachability checker + * that we could get to this guy. */ void dirserv_orconn_tls_done(const char *address, uint16_t or_port, const char *digest_rcvd, - const char *nickname_rcvd) + const char *nickname_rcvd, + int as_advertised) //XXXRD { int i; tor_assert(address); diff --git a/src/or/or.h b/src/or/or.h index 1a278ab7ea..68d974e5f6 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1540,7 +1540,8 @@ void dirserv_set_cached_directory(const char *directory, time_t when, void dirserv_orconn_tls_done(const char *address, uint16_t or_port, const char *digest_rcvd, - const char *nickname); + const char *nickname, + int as_advertised); void dirserv_free_all(void); /********************************* dns.c ***************************/ @@ -1818,20 +1819,18 @@ typedef struct trusted_dir_server_t { int router_reload_router_list(void); void router_get_trusted_dir_servers(smartlist_t **outp); -routerinfo_t *router_pick_directory_server(int requireothers, +routerinfo_t *router_pick_directory_server(int requireother, int fascistfirewall, int for_running_routers, int retry_if_no_servers); -trusted_dir_server_t *router_pick_trusteddirserver(int requireothers, +trusted_dir_server_t *router_pick_trusteddirserver(int requireother, int fascistfirewall, int retry_if_no_servers); int all_trusted_directory_servers_down(void); struct smartlist_t; void routerlist_add_family(struct smartlist_t *sl, routerinfo_t *router); void add_nickname_list_to_smartlist(struct smartlist_t *sl, const char *list, int warn_if_down); -int router_nickname_is_in_list(routerinfo_t *router, const char *list); routerinfo_t *routerlist_find_my_routerinfo(void); -int router_nickname_matches(routerinfo_t *router, const char *nickname); int exit_policy_implicitly_allows_local_networks(addr_policy_t *policy, int warn); @@ -1848,7 +1847,6 @@ routerinfo_t *router_choose_random_node(const char *preferred, struct smartlist_t *excludedsmartlist, int need_uptime, int need_bandwidth, int allow_unverified, int strict); -routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port); routerinfo_t *router_get_by_nickname(const char *nickname); routerinfo_t *router_get_by_hexdigest(const char *hexdigest); routerinfo_t *router_get_by_digest(const char *digest); @@ -1874,8 +1872,6 @@ 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_set_runningrouters(routerlist_t *list, running_routers_t *rr); -void routerlist_update_from_runningrouters(routerlist_t *list, - running_routers_t *rr); int routers_update_status_from_entry(smartlist_t *routers, time_t list_time, const char *s); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 26d3168a2e..2a81cb2cc3 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -20,11 +20,13 @@ static smartlist_t *trusted_dir_servers = NULL; /* static function prototypes */ static routerinfo_t * -router_pick_directory_server_impl(int requireothers, int fascistfirewall, +router_pick_directory_server_impl(int requireother, int fascistfirewall, int for_runningrouters); static trusted_dir_server_t * router_pick_trusteddirserver_impl(int requireother, int fascistfirewall); static void mark_all_trusteddirservers_up(void); +static int router_nickname_is_in_list(routerinfo_t *router, const char *list); +static int router_nickname_matches(routerinfo_t *router, const char *nickname); static int router_resolve(routerinfo_t *router); static int router_resolve_routerlist(routerlist_t *dir); @@ -34,7 +36,7 @@ static int router_resolve_routerlist(routerlist_t *dir); * Functions to manage and access our list of known routers. (Note: * dirservers maintain a separate, independent list of known router * descriptors.) - *****/ + ****/ /** Global list of all of the routers that we, as an OR or OP, know about. */ static routerlist_t *routerlist = NULL; @@ -42,8 +44,7 @@ static routerlist_t *routerlist = NULL; extern int has_fetched_directory; /**< from main.c */ /** - * Reload the original list of trusted dirservers, and the most recent - * cached directory (if present). + * Reload the most recent cached directory (if present). */ int router_reload_router_list(void) @@ -88,14 +89,16 @@ router_get_trusted_dir_servers(smartlist_t **outp) } /** Try to find a running dirserver. If there are no running dirservers - * in our routerlist, set all the authoritative ones as running again, - * and pick one. If there are no dirservers at all in our routerlist, - * reload the routerlist and try one last time. If for_runningrouters is + * in our routerlist and retry_if_no_servers is non-zero, + * set all the authoritative ones as running again, and pick one; + * if there are then no dirservers at all in our routerlist, + * reload the routerlist and try one last time. If for_runningrouters is * true, then only pick a dirserver that can answer runningrouters queries * (that is, a trusted dirserver, or one running 0.0.9rc5-cvs or later). + * Other args are as in router_pick_directory_server_impl(). */ routerinfo_t * -router_pick_directory_server(int requireothers, +router_pick_directory_server(int requireother, int fascistfirewall, int for_runningrouters, int retry_if_no_servers) @@ -105,7 +108,7 @@ router_pick_directory_server(int requireothers, if (!routerlist) return NULL; - choice = router_pick_directory_server_impl(requireothers, fascistfirewall, + choice = router_pick_directory_server_impl(requireother, fascistfirewall, for_runningrouters); if (choice || !retry_if_no_servers) return choice; @@ -114,7 +117,7 @@ router_pick_directory_server(int requireothers, /* mark all authdirservers as up again */ mark_all_trusteddirservers_up(); /* try again */ - choice = router_pick_directory_server_impl(requireothers, fascistfirewall, + choice = router_pick_directory_server_impl(requireother, fascistfirewall, for_runningrouters); if (choice) return choice; @@ -126,47 +129,43 @@ router_pick_directory_server(int requireothers, return NULL; } /* give it one last try */ - choice = router_pick_directory_server_impl(requireothers, 0, + choice = router_pick_directory_server_impl(requireother, 0, for_runningrouters); return choice; } -/** DOCDOC */ +/** Try to find a running trusted dirserver. If there are no running + * trusted dirservers and retry_if_no_servers is non-zero, + * set them all as running again, and try again. + * Other args are as in router_pick_trusteddirserver_impl(). + */ trusted_dir_server_t * -router_pick_trusteddirserver(int requireothers, +router_pick_trusteddirserver(int requireother, int fascistfirewall, int retry_if_no_servers) { trusted_dir_server_t *choice; - choice = router_pick_trusteddirserver_impl(requireothers, fascistfirewall); + choice = router_pick_trusteddirserver_impl(requireother, fascistfirewall); if (choice || !retry_if_no_servers) 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, fascistfirewall); - if (choice) - return choice; - - log_fn(LOG_WARN,"Still no dirservers %s. Reloading and trying again.", - get_options()->FascistFirewall ? "reachable" : "known"); - has_fetched_directory=0; /* reset it */ - if (router_reload_router_list()) { - return NULL; - } - /* give it one last try */ - choice = router_pick_trusteddirserver_impl(requireothers, 0); - return choice; + return router_pick_trusteddirserver_impl(requireother, fascistfirewall); } -/** Pick a random running router from our routerlist. If requireauth, - * it has to be a trusted server. If requireothers, it cannot be us. +/** Pick a random running verified directory server/mirror from our + * routerlist. + * If fascistfirewall and we're not using a proxy, + * make sure the port we pick is allowed by options-\>firewallports. + * If requireother, it cannot be us. + * If for_runningrouters, make sure we pick a dirserver that + * can answer queries for running-routers (this option will become obsolete + * once 0.0.9-rc5 is dead). */ static routerinfo_t * -router_pick_directory_server_impl(int requireothers, int fascistfirewall, +router_pick_directory_server_impl(int requireother, int fascistfirewall, int for_runningrouters) { int i; @@ -185,7 +184,7 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall, router = smartlist_get(routerlist->routers, i); if (!router->is_running || !router->dir_port || !router->is_verified) continue; - if (requireothers && router_is_me(router)) + if (requireother && router_is_me(router)) continue; if (fascistfirewall) { if (!smartlist_string_num_isin(get_options()->FirewallPorts, router->dir_port)) @@ -204,7 +203,11 @@ router_pick_directory_server_impl(int requireothers, int fascistfirewall, return router; } -/** DOCDOC */ +/** Choose randomly from among the trusted dirservers that are up. + * If fascistfirewall and we're not using a proxy, + * make sure the port we pick is allowed by options-\>firewallports. + * If requireother, it cannot be us. + */ static trusted_dir_server_t * router_pick_trusteddirserver_impl(int requireother, int fascistfirewall) { @@ -238,7 +241,7 @@ router_pick_trusteddirserver_impl(int requireother, int fascistfirewall) return ds; } -/** Go through and mark the auth dirservers as up */ +/** Go through and mark the authoritative dirservers as up. */ static void mark_all_trusteddirservers_up(void) { @@ -270,6 +273,7 @@ all_trusted_directory_servers_down(void) } /** Add all the family of router to the smartlist sl. + * This is used to make sure we don't pick siblings in a single path. */ void routerlist_add_family(smartlist_t *sl, routerinfo_t *router) @@ -295,6 +299,7 @@ routerlist_add_family(smartlist_t *sl, routerinfo_t *router) }); }); + /* If the user declared any families locally, honor those too. */ for (cl = get_options()->NodeFamilies; cl; cl = cl->next) { if (router_nickname_is_in_list(router, cl->value)) { add_nickname_list_to_smartlist(sl, cl->value, 0); @@ -302,8 +307,8 @@ routerlist_add_family(smartlist_t *sl, routerinfo_t *router) } } -/** List of string for nicknames we've warned about and haven't yet succeeded. - */ +/** List of strings for nicknames we've already warned about and that are + * still unknown / unavailable. */ static smartlist_t *warned_nicknames = NULL; /** Given a comma-and-whitespace separated list of nicknames, see which @@ -362,7 +367,7 @@ add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int warn_if_do /** Return 1 iff any member of the comma-separated list list is an * acceptable nickname or hexdigest for router. Else return 0. */ -int +static int router_nickname_is_in_list(routerinfo_t *router, const char *list) { smartlist_t *nickname_list; @@ -409,7 +414,8 @@ router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified, } } -/** DOCDOC */ +/** Look through the routerlist until we find a router that has my key. + Return it. */ routerinfo_t * routerlist_find_my_routerinfo(void) { @@ -427,7 +433,11 @@ routerlist_find_my_routerinfo(void) return NULL; } -/** DOCDOC */ +/** Return 1 if router is not suitable for these parameters, else 0. + * If need_uptime is non-zero, we require a minimum uptime. + * If need_capacity is non-zero, we require a minimum advertised + * bandwidth. + */ int router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity) { @@ -438,7 +448,7 @@ router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity) return 0; } -/** DOCDOC */ +/** Remove from routerlist sl all routers who have a low uptime. */ static void routerlist_sl_remove_unreliable_routers(smartlist_t *sl) { @@ -455,7 +465,11 @@ routerlist_sl_remove_unreliable_routers(smartlist_t *sl) } } -/** DOCDOC */ +#define MAX_BELIEVABLE_BANDWIDTH 2000000 /* 2 MB/sec */ + +/** Choose a random element of router list sl, weighted by + * the advertised bandwidth of each router. + */ routerinfo_t * routerlist_sl_choose_by_bandwidth(smartlist_t *sl) { @@ -465,41 +479,40 @@ routerlist_sl_choose_by_bandwidth(smartlist_t *sl) uint32_t this_bw, tmp, total_bw=0, rand_bw; uint32_t *p; + /* First count the total bandwidth weight, and make a smartlist + * of each value. */ bandwidths = smartlist_create(); for (i = 0; i < smartlist_len(sl); ++i) { router = smartlist_get(sl, i); this_bw = (router->bandwidthcapacity < router->bandwidthrate) ? router->bandwidthcapacity : router->bandwidthrate; - if (this_bw > 2000000) - this_bw = 2000000; /* if they claim something huge, don't believe it */ + /* if they claim something huge, don't believe it */ + if (this_bw > MAX_BELIEVABLE_BANDWIDTH) + this_bw = MAX_BELIEVABLE_BANDWIDTH; p = tor_malloc(sizeof(uint32_t)); *p = this_bw; smartlist_add(bandwidths, p); total_bw += this_bw; -// log_fn(LOG_INFO,"Recording bw %d for node %s.", this_bw, router->nickname); } if (!total_bw) { SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p)); smartlist_free(bandwidths); return smartlist_choose(sl); } + /* Second, choose a random value from the bandwidth weights. */ rand_bw = crypto_pseudo_rand_int(total_bw); -// log_fn(LOG_INFO,"Total bw %d. Randomly chose %d.", total_bw, rand_bw); + /* Last, count through sl until we get to the element we picked */ tmp = 0; for (i=0; ; i++) { tor_assert(i < smartlist_len(sl)); p = smartlist_get(bandwidths, i); tmp += *p; - router = smartlist_get(sl, i); -// log_fn(LOG_INFO,"Considering %s. tmp = %d.", router->nickname, tmp); if (tmp >= rand_bw) break; } SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p)); smartlist_free(bandwidths); - router = smartlist_get(sl, i); -// log_fn(LOG_INFO,"Picked %s.", router->nickname); - return router; + return (routerinfo_t *)smartlist_get(sl, i); } /** Return a random running router from the routerlist. If any node @@ -508,6 +521,10 @@ routerlist_sl_choose_by_bandwidth(smartlist_t *sl) * excludedsmartlist, even if they are the only nodes * available. If strict is true, never pick any node besides * those in preferred. + * If need_uptime is non-zero, don't return a router with less + * than a minimum uptime. + * If need_capacity is non-zero, weight your choice by the + * advertised capacity of each router. */ routerinfo_t * router_choose_random_node(const char *preferred, @@ -529,13 +546,6 @@ router_choose_random_node(const char *preferred, smartlist_subtract(sl,excludednodes); if (excludedsmartlist) smartlist_subtract(sl,excludedsmartlist); -#if 0 - if (need_uptime) - routerlist_sl_remove_unreliable_routers(sl); - if (need_capacity) - choice = routerlist_sl_choose_by_bandwidth(sl); - else -#endif choice = smartlist_choose(sl); smartlist_free(sl); if (!choice && !strict) { @@ -561,26 +571,6 @@ router_choose_random_node(const char *preferred, return choice; } -/** Return the router in our routerlist whose address is addr and - * whose OR port is port. Return NULL if no such router is known. - */ -routerinfo_t * -router_get_by_addr_port(uint32_t addr, uint16_t port) -{ - int i; - routerinfo_t *router; - - if (!routerlist) - return NULL; - - for (i=0;irouters);i++) { - router = smartlist_get(routerlist->routers, i); - if ((router->addr == addr) && (router->or_port == port)) - return router; - } - return NULL; -} - /** Return true iff the digest of router's identity key, * encoded in hexadecimal, matches hexdigest (which is * optionally prefixed with a single dollar sign). Return false if @@ -596,21 +586,19 @@ router_hex_digest_matches(routerinfo_t *router, const char *hexdigest) if (strlen(hexdigest) != HEX_DIGEST_LEN || base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0) return 0; - else - return (!memcmp(digest, router->identity_digest, DIGEST_LEN)); + return (!memcmp(digest, router->identity_digest, DIGEST_LEN)); } -/* Return true if router's nickname matches nickname +/** Return true if router's nickname matches nickname * (case-insensitive), or if router's identity key digest * matches a hexadecimal value stored in nickname. Return - * false otherwise.*/ -int + * false otherwise. */ +static int router_nickname_matches(routerinfo_t *router, const char *nickname) { if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname)) return 1; - else - return router_hex_digest_matches(router, nickname); + return router_hex_digest_matches(router, nickname); } /** Return the router in our routerlist whose (case-insensitive) @@ -687,10 +675,7 @@ router_get_by_digest(const char *digest) routerinfo_t *router; tor_assert(digest); - if (server_mode(get_options()) && - (router = router_get_my_routerinfo()) && - !memcmp(digest, router->identity_digest, DIGEST_LEN)) - return router; + if (!routerlist) return NULL; for (i=0;irouters);i++) { @@ -842,7 +827,9 @@ router_mark_as_down(const char *digest) * will either be inserted into the routerlist or freed. Returns 0 if the * router was added; -1 if it was not. * - * DOCDOC msg + * If we're returning -1 and msg is not NULL, then assign to + * *msg a static string describing the reason for refusing the + * routerinfo. */ static int router_add_to_routerlist(routerinfo_t *router, const char **msg) @@ -864,7 +851,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg) if (router->published_on > r->published_on) { 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. */ +//XXXRD /* Remember whether we trust this router as a dirserver. */ /* If the address hasn't changed; no need to re-resolve. */ if (!strcasecmp(r->address, router->address)) router->addr = r->addr; @@ -903,7 +890,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg) log_fn(LOG_DEBUG, "Skipping unverified entry for verified router '%s'", router->nickname); routerinfo_free(router); - if (msg) *msg = "Already have verified router with different key and same nickname"; + if (msg) *msg = "Already have verified router with same nickname and different key"; return -1; } } @@ -920,6 +907,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg) * (This function is just like dirserv_remove_old_servers. One day we should * merge them.) */ +//XXXRD void routerlist_remove_old_routers(int age) { @@ -942,10 +930,14 @@ routerlist_remove_old_routers(int age) } /* - * Code to parse a single router descriptors and insert it into the - * directory. Return -1 if the descriptor was ill-formed; 0 if the + * Code to parse a single router descriptor and insert it into the + * routerlist. Return -1 if the descriptor was ill-formed; 0 if the * descriptor was well-formed but could not be added; and 1 if the * descriptor was added. + * + * If we don't add it and msg is not NULL, then assign to + * *msg a static string describing the reason for refusing the + * descriptor. */ int router_load_single_router(const char *s, const char **msg) @@ -965,7 +957,7 @@ router_load_single_router(const char *s, const char **msg) return 0; } if (router_resolve(ri)<0) { - log_fn(LOG_WARN, "Couldn't resolve router address; dropping."); + log_fn(LOG_WARN, "Couldn't resolve router address '%s'; dropping.", ri->address); *msg = "Couldn't resolve router address."; routerinfo_free(ri); return 0; @@ -978,8 +970,7 @@ router_load_single_router(const char *s, const char **msg) } if (router_add_to_routerlist(ri, msg)<0) { log_fn(LOG_WARN, "Couldn't add router to list; dropping."); - *msg = "Couldn't add router to list."; - /* ri is already freed */ + /* we've already assigned to *msg now, and ri is already freed */ return 0; } else { smartlist_t *changed = smartlist_create(); @@ -993,8 +984,9 @@ router_load_single_router(const char *s, const char **msg) } /** Add to the current routerlist each router stored in the - * signed directory s. If pkey is provided, check the signature against - * pkey; else check against the pkey of the signing directory server. + * signed directory s. If pkey is provided, check the signature + * against pkey; else check against the pkey of the signing directory + * server. * * If dir_is_recent is non-zero, then examine the * Recommended-versions line and take appropriate action. @@ -1016,6 +1008,8 @@ router_load_routerlist_from_directory(const char *s, return -1; } if (routerlist) { + /* Merge the new_list into routerlist, then free new_list. Also + * keep a list of changed descriptors to inform controllers. */ smartlist_t *changed = smartlist_create(); SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r, { @@ -1041,6 +1035,7 @@ router_load_routerlist_from_directory(const char *s, if (get_options()->AuthoritativeDir) { /* Learn about the descriptors in the directory. */ dirserv_load_from_directory_string(s); +//XXXRD } return 0; } @@ -1049,14 +1044,24 @@ router_load_routerlist_from_directory(const char *s, static int router_resolve(routerinfo_t *router) { - if (tor_lookup_hostname(router->address, &router->addr) != 0 - || !router->addr) { - log_fn(LOG_WARN,"Could not resolve address for router '%s' at %s", - router->nickname, router->address); - return -1; + if (authdir_mode(get_options())) { + /* don't let authdirservers do resolves; this is an easy DoS avenue */ + struct in_addr iaddr; + if (!tor_inet_aton(router->address, &iaddr)) { /* not an IP */ + log_fn(LOG_WARN,"Refusing to resolve non-IP address '%s' for router '%s'", + router->address, router->nickname); + return -1; + } + memcpy((void *)router->addr, &iaddr.s_addr, 4); + } else { + if (tor_lookup_hostname(router->address, &router->addr) != 0 + || !router->addr) { + log_fn(LOG_WARN,"Could not resolve address '%s' for router '%s'", + router->address, router->nickname); + return -1; + } } router->addr = ntohl(router->addr); /* get it back into host order */ - return 0; } @@ -1085,8 +1090,8 @@ router_resolve_routerlist(routerlist_t *rl) } else if (r->addr) { /* already resolved. */ } else if (router_resolve(r)) { - log_fn(LOG_WARN, "Couldn't resolve router '%s' at '%s'; not using", - r->nickname, r->address); + log_fn(LOG_WARN, "Couldn't resolve address '%s' for router '%s'; not using", + r->address, r->nickname); remove = 1; } if (remove) { @@ -1126,7 +1131,6 @@ router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port, addr_policy_t *tmpe; for (tmpe=policy; tmpe; tmpe=tmpe->next) { -// log_fn(LOG_DEBUG,"Considering exit policy %s", tmpe->string); maybe = 0; if (!addr) { /* Address is unknown. */ @@ -1160,10 +1164,6 @@ router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port, maybe_accept = 1; } if (match) { -// struct in_addr in; -// in.s_addr = htonl(addr); -// log_fn(LOG_DEBUG,"Address %s:%d matches policy '%s'", -// inet_ntoa(in), port, tmpe->string); if (tmpe->policy_type == ADDR_POLICY_ACCEPT) { /* If we already hit a clause that might trigger a 'reject', than we * can't be sure of this certain 'accept'.*/ @@ -1308,23 +1308,9 @@ running_routers_free(running_routers_t *rr) tor_free(rr); } -/** We've just got a running routers list in rr; update the - * status of the routers in list, and cache rr */ -void -routerlist_set_runningrouters(routerlist_t *list, running_routers_t *rr) -{ - routerlist_update_from_runningrouters(list,rr); - if (list->running_routers != rr) { - running_routers_free(list->running_routers); - list->running_routers = rr; - } -} - /** Update the running/not-running status of every router in list, based * on the contents of rr. */ -/* Note: this function is not yet used, since nobody publishes just - * running-router lists yet. */ -void +static void routerlist_update_from_runningrouters(routerlist_t *list, running_routers_t *rr) { @@ -1349,6 +1335,18 @@ routerlist_update_from_runningrouters(routerlist_t *list, list->running_routers_updated_on = rr->published_on; } +/** We've just got a running routers list in rr; update the + * status of the routers in list, and cache rr */ +void +routerlist_set_runningrouters(routerlist_t *list, running_routers_t *rr) +{ + routerlist_update_from_runningrouters(list,rr); + if (list->running_routers != rr) { + running_routers_free(list->running_routers); + list->running_routers = rr; + } +} + /** Update the is_running and is_verified fields of the router router, * based in its status in the list of strings stored in running_list. * All entries in running_list follow one of these formats: -- 2.11.4.GIT