diff options
Diffstat (limited to 'src/or/router.c')
-rw-r--r-- | src/or/router.c | 147 |
1 files changed, 93 insertions, 54 deletions
diff --git a/src/or/router.c b/src/or/router.c index 2cdbb0c8bb..2ddaa895fc 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2013, The Tor Project, Inc. */ + * Copyright (c) 2007-2015, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE @@ -55,13 +55,11 @@ static crypto_pk_t *onionkey=NULL; /** Previous private onionskin decryption key: used to decode CREATE cells * generated by clients that have an older version of our descriptor. */ static crypto_pk_t *lastonionkey=NULL; -#ifdef CURVE25519_ENABLED /** Current private ntor secret key: used to perform the ntor handshake. */ static curve25519_keypair_t curve25519_onion_key; /** Previous private ntor secret key: used to perform the ntor handshake * with clients that have an older version of our descriptor. */ static curve25519_keypair_t last_curve25519_onion_key; -#endif /** Private server "identity key": used to sign directory info and TLS * certificates. Never changes. */ static crypto_pk_t *server_identitykey=NULL; @@ -134,7 +132,6 @@ dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last) tor_mutex_release(key_lock); } -#ifdef CURVE25519_ENABLED /** Return the current secret onion key for the ntor handshake. Must only * be called from the main thread. */ static const curve25519_keypair_t * @@ -181,7 +178,6 @@ ntor_key_map_free(di_digest256_map_t *map) return; dimap_free(map, ntor_key_map_free_helper); } -#endif /** Return the time when the onion key was last set. This is either the time * when the process launched, or the time of the most recent key rotation since @@ -313,12 +309,11 @@ rotate_onion_key(void) char *fname, *fname_prev; crypto_pk_t *prkey = NULL; or_state_t *state = get_or_state(); -#ifdef CURVE25519_ENABLED curve25519_keypair_t new_curve25519_keypair; -#endif time_t now; fname = get_datadir_fname2("keys", "secret_onion_key"); fname_prev = get_datadir_fname2("keys", "secret_onion_key.old"); + /* There isn't much point replacing an old key with an empty file */ if (file_status(fname) == FN_FILE) { if (replace_file(fname, fname_prev)) goto error; @@ -335,13 +330,13 @@ rotate_onion_key(void) log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname); goto error; } -#ifdef CURVE25519_ENABLED tor_free(fname); tor_free(fname_prev); fname = get_datadir_fname2("keys", "secret_onion_key_ntor"); fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0) goto error; + /* There isn't much point replacing an old key with an empty file */ if (file_status(fname) == FN_FILE) { if (replace_file(fname, fname_prev)) goto error; @@ -351,18 +346,15 @@ rotate_onion_key(void) log_err(LD_FS,"Couldn't write curve25519 onion key to \"%s\".",fname); goto error; } -#endif log_info(LD_GENERAL, "Rotating onion key"); tor_mutex_acquire(key_lock); crypto_pk_free(lastonionkey); lastonionkey = onionkey; onionkey = prkey; -#ifdef CURVE25519_ENABLED memcpy(&last_curve25519_onion_key, &curve25519_onion_key, sizeof(curve25519_keypair_t)); memcpy(&curve25519_onion_key, &new_curve25519_keypair, sizeof(curve25519_keypair_t)); -#endif now = time(NULL); state->LastRotatedOnionKey = onionkey_set_at = now; tor_mutex_release(key_lock); @@ -374,20 +366,40 @@ rotate_onion_key(void) if (prkey) crypto_pk_free(prkey); done: -#ifdef CURVE25519_ENABLED memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair)); -#endif tor_free(fname); tor_free(fname_prev); } +/** Log greeting message that points to new relay lifecycle document the + * first time this function has been called. + */ +static void +log_new_relay_greeting(void) +{ + static int already_logged = 0; + + if (already_logged) + return; + + tor_log(LOG_NOTICE, LD_GENERAL, "You are running a new relay. " + "Thanks for helping the Tor network! If you wish to know " + "what will happen in the upcoming weeks regarding its usage, " + "have a look at https://blog.torproject.org/blog/lifecycle-of" + "-a-new-relay"); + + already_logged = 1; +} + /** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist * and <b>generate</b> is true, create a new RSA key and save it in * <b>fname</b>. Return the read/created key, or NULL on error. Log all - * errors at level <b>severity</b>. + * errors at level <b>severity</b>. If <b>log_greeting</b> is non-zero and a + * new key was created, log_new_relay_greeting() is called. */ crypto_pk_t * -init_key_from_file(const char *fname, int generate, int severity) +init_key_from_file(const char *fname, int generate, int severity, + int log_greeting) { crypto_pk_t *prkey = NULL; @@ -401,7 +413,11 @@ init_key_from_file(const char *fname, int generate, int severity) case FN_ERROR: tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); goto error; + /* treat empty key files as if the file doesn't exist, and, + * if generate is set, replace the empty file in + * crypto_pk_write_private_key_to_filename() */ case FN_NOENT: + case FN_EMPTY: if (generate) { if (!have_lockfile()) { if (try_locking(get_options(), 0)<0) { @@ -425,6 +441,9 @@ init_key_from_file(const char *fname, int generate, int severity) goto error; } log_info(LD_GENERAL, "Generated key seems valid"); + if (log_greeting) { + log_new_relay_greeting(); + } if (crypto_pk_write_private_key_to_filename(prkey, fname)) { tor_log(severity, LD_FS, "Couldn't write generated key to \"%s\".", fname); @@ -450,12 +469,11 @@ init_key_from_file(const char *fname, int generate, int severity) return NULL; } -#ifdef CURVE25519_ENABLED /** Load a curve25519 keypair from the file <b>fname</b>, writing it into - * <b>keys_out</b>. If the file isn't found and <b>generate</b> is true, - * create a new keypair and write it into the file. If there are errors, log - * them at level <b>severity</b>. Generate files using <b>tag</b> in their - * ASCII wrapper. */ + * <b>keys_out</b>. If the file isn't found, or is empty, and <b>generate</b> + * is true, create a new keypair and write it into the file. If there are + * errors, log them at level <b>severity</b>. Generate files using <b>tag</b> + * in their ASCII wrapper. */ static int init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, const char *fname, @@ -468,7 +486,10 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, case FN_ERROR: tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); goto error; + /* treat empty key files as if the file doesn't exist, and, if generate + * is set, replace the empty file in curve25519_keypair_write_to_file() */ case FN_NOENT: + case FN_EMPTY: if (generate) { if (!have_lockfile()) { if (try_locking(get_options(), 0)<0) { @@ -488,7 +509,7 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) { tor_log(severity, LD_FS, "Couldn't write generated key to \"%s\".", fname); - memset(keys_out, 0, sizeof(*keys_out)); + memwipe(keys_out, 0, sizeof(*keys_out)); goto error; } } else { @@ -519,7 +540,6 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, error: return -1; } -#endif /** Try to load the vote-signing private key and certificate for being a v3 * directory authority, and make sure they match. If <b>legacy</b>, load a @@ -538,7 +558,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, fname = get_datadir_fname2("keys", legacy ? "legacy_signing_key" : "authority_signing_key"); - signing_key = init_key_from_file(fname, 0, LOG_INFO); + signing_key = init_key_from_file(fname, 0, LOG_INFO, 0); if (!signing_key) { log_warn(LD_DIR, "No version 3 directory key found in %s", fname); goto done; @@ -821,7 +841,7 @@ init_keys(void) /* 1b. Read identity key. Make it if none is found. */ keydir = get_datadir_fname2("keys", "secret_id_key"); log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir); - prkey = init_key_from_file(keydir, 1, LOG_ERR); + prkey = init_key_from_file(keydir, 1, LOG_ERR, 1); tor_free(keydir); if (!prkey) return -1; set_server_identity_key(prkey); @@ -844,7 +864,7 @@ init_keys(void) /* 2. Read onion key. Make it if none is found. */ keydir = get_datadir_fname2("keys", "secret_onion_key"); log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir); - prkey = init_key_from_file(keydir, 1, LOG_ERR); + prkey = init_key_from_file(keydir, 1, LOG_ERR, 1); tor_free(keydir); if (!prkey) return -1; set_onion_key(prkey); @@ -869,13 +889,14 @@ init_keys(void) keydir = get_datadir_fname2("keys", "secret_onion_key.old"); if (!lastonionkey && file_status(keydir) == FN_FILE) { - prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */ + /* Load keys from non-empty files only. + * Missing old keys won't be replaced with freshly generated keys. */ + prkey = init_key_from_file(keydir, 0, LOG_ERR, 0); if (prkey) lastonionkey = prkey; } tor_free(keydir); -#ifdef CURVE25519_ENABLED { /* 2b. Load curve25519 onion keys. */ int r; @@ -891,12 +912,13 @@ init_keys(void) last_curve25519_onion_key.pubkey.public_key, CURVE25519_PUBKEY_LEN) && file_status(keydir) == FN_FILE) { + /* Load keys from non-empty files only. + * Missing old keys won't be replaced with freshly generated keys. */ init_curve25519_keypair_from_file(&last_curve25519_onion_key, keydir, 0, LOG_ERR, "onion"); } tor_free(keydir); } -#endif /* 3. Initialize link key and TLS context. */ if (router_initialize_tls_context() < 0) { @@ -911,14 +933,13 @@ init_keys(void) const char *m = NULL; routerinfo_t *ri; /* We need to add our own fingerprint so it gets recognized. */ - if (dirserv_add_own_fingerprint(options->Nickname, - get_server_identity_key())) { - log_err(LD_GENERAL,"Error adding own fingerprint to approved set"); + if (dirserv_add_own_fingerprint(get_server_identity_key())) { + log_err(LD_GENERAL,"Error adding own fingerprint to set of relays"); return -1; } if (mydesc) { was_router_added_t added; - ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL); + ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL, NULL); if (!ri) { log_err(LD_GENERAL,"Generated a routerinfo we couldn't parse."); return -1; @@ -1081,6 +1102,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) * they're confused or to get statistics. */ int interval_length = accounting_get_interval_length(); uint32_t effective_bw = get_effective_bwrate(options); + uint64_t acc_bytes; if (!interval_length) { log_warn(LD_BUG, "An accounting interval is not allowed to be zero " "seconds long. Raising to 1."); @@ -1091,8 +1113,12 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) "accounting interval length %d", effective_bw, U64_PRINTF_ARG(options->AccountingMax), interval_length); + + acc_bytes = options->AccountingMax; + if (get_options()->AccountingRule == ACCT_SUM) + acc_bytes /= 2; if (effective_bw >= - options->AccountingMax / interval_length) { + acc_bytes / interval_length) { new_choice = 0; reason = "AccountingMax enabled"; } @@ -1210,6 +1236,11 @@ router_orport_found_reachable(void) " Publishing server descriptor." : ""); can_reach_or_port = 1; mark_my_descriptor_dirty("ORPort found reachable"); + /* This is a significant enough change to upload immediately, + * at least in a test network */ + if (get_options()->TestingTorNetwork == 1) { + reschedule_descriptor_update_check(); + } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d", address, me->or_port); @@ -1227,8 +1258,14 @@ router_dirport_found_reachable(void) log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable " "from the outside. Excellent."); can_reach_dir_port = 1; - if (decide_to_advertise_dirport(get_options(), me->dir_port)) + if (decide_to_advertise_dirport(get_options(), me->dir_port)) { mark_my_descriptor_dirty("DirPort found reachable"); + /* This is a significant enough change to upload immediately, + * at least in a test network */ + if (get_options()->TestingTorNetwork == 1) { + reschedule_descriptor_update_check(); + } + } control_event_server_status(LOG_NOTICE, "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d", address, me->dir_port); @@ -1802,19 +1839,17 @@ router_rebuild_descriptor(int force) ri->cache_info.published_on = time(NULL); ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from * main thread */ -#ifdef CURVE25519_ENABLED ri->onion_curve25519_pkey = tor_memdup(&get_current_curve25519_keypair()->pubkey, sizeof(curve25519_public_key_t)); -#endif /* For now, at most one IPv6 or-address is being advertised. */ { const port_cfg_t *ipv6_orport = NULL; SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { if (p->type == CONN_TYPE_OR_LISTENER && - ! p->no_advertise && - ! p->bind_ipv4_only && + ! p->server_cfg.no_advertise && + ! p->server_cfg.bind_ipv4_only && tor_addr_family(&p->addr) == AF_INET6) { if (! tor_addr_is_internal(&p->addr, 0)) { ipv6_orport = p; @@ -1856,10 +1891,8 @@ router_rebuild_descriptor(int force) /* DNS is screwed up; don't claim to be an exit. */ policies_exit_policy_append_reject_star(&ri->exit_policy); } else { - policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy, - options->IPv6Exit, - options->ExitPolicyRejectPrivate, - ri->addr, !options->BridgeRelay); + policies_parse_exit_policy_from_options(options,ri->addr, + &ri->exit_policy); } ri->policy_is_reject_star = policy_is_reject_star(ri->exit_policy, AF_INET) && @@ -1879,7 +1912,7 @@ router_rebuild_descriptor(int force) family = smartlist_new(); ri->declared_family = smartlist_new(); smartlist_split_string(family, options->MyFamily, ",", - SPLIT_SKIP_SPACE|SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0); SMARTLIST_FOREACH_BEGIN(family, char *, name) { const node_t *member; if (!strcasecmp(name, options->Nickname)) @@ -2063,7 +2096,8 @@ mark_my_descriptor_dirty(const char *reason) } /** How frequently will we republish our descriptor because of large (factor - * of 2) shifts in estimated bandwidth? */ + * of 2) shifts in estimated bandwidth? Note: We don't use this constant + * if our previous bandwidth estimate was exactly 0. */ #define MAX_BANDWIDTH_CHANGE_FREQ (20*60) /** Check whether bandwidth has changed a lot since the last time we announced @@ -2081,7 +2115,7 @@ check_descriptor_bandwidth_changed(time_t now) if ((prev != cur && (!prev || !cur)) || cur > prev*2 || cur < prev/2) { - if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now) { + if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now || !prev) { log_info(LD_GENERAL, "Measured bandwidth has changed; rebuilding descriptor."); mark_my_descriptor_dirty("bandwidth has changed"); @@ -2371,7 +2405,8 @@ router_dump_router_to_string(routerinfo_t *router, has_extra_info_digest ? "extra-info-digest " : "", has_extra_info_digest ? extra_info_digest : "", has_extra_info_digest ? "\n" : "", - options->DownloadExtraInfo ? "caches-extra-info\n" : "", + (options->DownloadExtraInfo || options->V3AuthoritativeDir) ? + "caches-extra-info\n" : "", onion_pkey, identity_pkey, family_line, we_are_hibernating() ? "hibernating 1\n" : "", @@ -2385,7 +2420,6 @@ router_dump_router_to_string(routerinfo_t *router, smartlist_add_asprintf(chunks, "contact %s\n", ci); } -#ifdef CURVE25519_ENABLED if (router->onion_curve25519_pkey) { char kbuf[128]; base64_encode(kbuf, sizeof(kbuf), @@ -2393,7 +2427,6 @@ router_dump_router_to_string(routerinfo_t *router, CURVE25519_PUBKEY_LEN); smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); } -#endif /* Write the exit policy to the end of 's'. */ if (!router->exit_policy || !smartlist_len(router->exit_policy)) { @@ -2443,7 +2476,7 @@ router_dump_router_to_string(routerinfo_t *router, const char *cp; routerinfo_t *ri_tmp; cp = s_dup = tor_strdup(output); - ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL); + ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL, NULL); if (!ri_tmp) { log_err(LD_BUG, "We just generated a router descriptor we can't parse."); @@ -2557,8 +2590,9 @@ router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport) * <b>end_line</b>, ensure that its timestamp is not more than 25 hours in * the past or more than 1 hour in the future with respect to <b>now</b>, * and write the file contents starting with that line to *<b>out</b>. - * Return 1 for success, 0 if the file does not exist, or -1 if the file - * does not contain a line matching these criteria or other failure. */ + * Return 1 for success, 0 if the file does not exist or is empty, or -1 + * if the file does not contain a line matching these criteria or other + * failure. */ static int load_stats_file(const char *filename, const char *end_line, time_t now, char **out) @@ -2592,7 +2626,9 @@ load_stats_file(const char *filename, const char *end_line, time_t now, notfound: tor_free(contents); break; + /* treat empty stats files as if the file doesn't exist */ case FN_NOENT: + case FN_EMPTY: r = 0; break; case FN_ERROR: @@ -2649,6 +2685,11 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, "dirreq-stats-end", now, &contents) > 0) { smartlist_add(chunks, contents); } + if (options->HiddenServiceStatistics && + load_stats_file("stats"PATH_SEPARATOR"hidserv-stats", + "hidserv-stats-end", now, &contents) > 0) { + smartlist_add(chunks, contents); + } if (options->EntryStatistics && load_stats_file("stats"PATH_SEPARATOR"entry-stats", "entry-stats-end", now, &contents) > 0) { @@ -2725,7 +2766,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, s = smartlist_join_strings(chunks, "", 0, NULL); cp = s_dup = tor_strdup(s); - ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL); + ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL, NULL); if (!ei_tmp) { if (write_stats_to_extrainfo) { log_warn(LD_GENERAL, "We just generated an extra-info descriptor " @@ -3069,10 +3110,8 @@ router_free_all(void) crypto_pk_free(legacy_signing_key); authority_cert_free(legacy_key_certificate); -#ifdef CURVE25519_ENABLED memwipe(&curve25519_onion_key, 0, sizeof(curve25519_onion_key)); memwipe(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key)); -#endif if (warned_nonexistent_family) { SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp)); |