diff options
Diffstat (limited to 'src/or/router.c')
-rw-r--r-- | src/or/router.c | 642 |
1 files changed, 454 insertions, 188 deletions
diff --git a/src/or/router.c b/src/or/router.c index 365e888af9..c51bb5dc4d 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -7,6 +7,7 @@ #define ROUTER_PRIVATE #include "or.h" +#include "circuitbuild.h" #include "circuitlist.h" #include "circuituse.h" #include "config.h" @@ -19,6 +20,7 @@ #include "hibernate.h" #include "main.h" #include "networkstatus.h" +#include "nodelist.h" #include "policies.h" #include "relay.h" #include "rephist.h" @@ -45,28 +47,28 @@ extern long stats_n_seconds_working; static tor_mutex_t *key_lock=NULL; static time_t onionkey_set_at=0; /**< When was onionkey last changed? */ /** Current private onionskin decryption key: used to decode CREATE cells. */ -static crypto_pk_env_t *onionkey=NULL; +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_env_t *lastonionkey=NULL; +static crypto_pk_t *lastonionkey=NULL; /** Private server "identity key": used to sign directory info and TLS * certificates. Never changes. */ -static crypto_pk_env_t *server_identitykey=NULL; +static crypto_pk_t *server_identitykey=NULL; /** Digest of server_identitykey. */ static char server_identitykey_digest[DIGEST_LEN]; /** Private client "identity key": used to sign bridges' and clients' * outbound TLS certificates. Regenerated on startup and on IP address * change. */ -static crypto_pk_env_t *client_identitykey=NULL; +static crypto_pk_t *client_identitykey=NULL; /** Signing key used for v3 directory material; only set for authorities. */ -static crypto_pk_env_t *authority_signing_key = NULL; +static crypto_pk_t *authority_signing_key = NULL; /** Key certificate to authenticate v3 directory material; only set for * authorities. */ static authority_cert_t *authority_key_certificate = NULL; /** For emergency V3 authority key migration: An extra signing key that we use * with our old (obsolete) identity key for a while. */ -static crypto_pk_env_t *legacy_signing_key = NULL; +static crypto_pk_t *legacy_signing_key = NULL; /** For emergency V3 authority key migration: An extra certificate to * authenticate legacy_signing_key with our obsolete identity key.*/ static authority_cert_t *legacy_key_certificate = NULL; @@ -80,10 +82,15 @@ static authority_cert_t *legacy_key_certificate = NULL; * lastonionkey; to update lastonionkey correctly, call rotate_onion_key(). */ static void -set_onion_key(crypto_pk_env_t *k) +set_onion_key(crypto_pk_t *k) { + if (onionkey && !crypto_pk_cmp_keys(onionkey, k)) { + /* k is already our onion key; free it and return */ + crypto_pk_free(k); + return; + } tor_mutex_acquire(key_lock); - crypto_free_pk_env(onionkey); + crypto_pk_free(onionkey); onionkey = k; tor_mutex_release(key_lock); mark_my_descriptor_dirty("set onion key"); @@ -91,7 +98,7 @@ set_onion_key(crypto_pk_env_t *k) /** Return the current onion key. Requires that the onion key has been * loaded or generated. */ -crypto_pk_env_t * +crypto_pk_t * get_onion_key(void) { tor_assert(onionkey); @@ -102,7 +109,7 @@ get_onion_key(void) * copy of the most recent onion key into *<b>last</b>. */ void -dup_onion_keys(crypto_pk_env_t **key, crypto_pk_env_t **last) +dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last) { tor_assert(key); tor_assert(last); @@ -129,9 +136,9 @@ get_onion_key_set_at(void) /** Set the current server identity key to <b>k</b>. */ void -set_server_identity_key(crypto_pk_env_t *k) +set_server_identity_key(crypto_pk_t *k) { - crypto_free_pk_env(server_identitykey); + crypto_pk_free(server_identitykey); server_identitykey = k; crypto_pk_get_digest(server_identitykey, server_identitykey_digest); } @@ -149,15 +156,15 @@ assert_identity_keys_ok(void) } else { /* assert that we have set the client and server keys to be unequal */ if (server_identitykey) - tor_assert(0!=crypto_pk_cmp_keys(client_identitykey, - server_identitykey)); + tor_assert(0!=crypto_pk_cmp_keys(client_identitykey, + server_identitykey)); } } /** Returns the current server identity key; requires that the key has * been set, and that we are running as a Tor server. */ -crypto_pk_env_t * +crypto_pk_t * get_server_identity_key(void) { tor_assert(server_identitykey); @@ -176,16 +183,16 @@ server_identity_key_is_set(void) /** Set the current client identity key to <b>k</b>. */ void -set_client_identity_key(crypto_pk_env_t *k) +set_client_identity_key(crypto_pk_t *k) { - crypto_free_pk_env(client_identitykey); + crypto_pk_free(client_identitykey); client_identitykey = k; } /** Returns the current client identity key for use on outgoing TLS * connections; requires that the key has been set. */ -crypto_pk_env_t * +crypto_pk_t * get_tlsclient_identity_key(void) { tor_assert(client_identitykey); @@ -210,7 +217,7 @@ get_my_v3_authority_cert(void) /** Return the v3 signing key for this v3 (voting) authority, or NULL * if we have no such key. */ -crypto_pk_env_t * +crypto_pk_t * get_my_v3_authority_signing_key(void) { return authority_signing_key; @@ -227,7 +234,7 @@ get_my_v3_legacy_cert(void) /** If we're an authority, and we're using a legacy authority identity key for * emergency migration purposes, return that key. */ -crypto_pk_env_t * +crypto_pk_t * get_my_v3_legacy_signing_key(void) { return legacy_signing_key; @@ -244,12 +251,12 @@ void rotate_onion_key(void) { char *fname, *fname_prev; - crypto_pk_env_t *prkey; + crypto_pk_t *prkey; or_state_t *state = get_or_state(); time_t now; fname = get_datadir_fname2("keys", "secret_onion_key"); fname_prev = get_datadir_fname2("keys", "secret_onion_key.old"); - if (!(prkey = crypto_new_pk_env())) { + if (!(prkey = crypto_pk_new())) { log_err(LD_GENERAL,"Error constructing rotated onion key"); goto error; } @@ -267,7 +274,7 @@ rotate_onion_key(void) } log_info(LD_GENERAL, "Rotating onion key"); tor_mutex_acquire(key_lock); - crypto_free_pk_env(lastonionkey); + crypto_pk_free(lastonionkey); lastonionkey = onionkey; onionkey = prkey; now = time(NULL); @@ -279,7 +286,7 @@ rotate_onion_key(void) error: log_warn(LD_GENERAL, "Couldn't rotate onion key."); if (prkey) - crypto_free_pk_env(prkey); + crypto_pk_free(prkey); done: tor_free(fname); tor_free(fname_prev); @@ -290,12 +297,12 @@ rotate_onion_key(void) * <b>fname</b>. Return the read/created key, or NULL on error. Log all * errors at level <b>severity</b>. */ -crypto_pk_env_t * +crypto_pk_t * init_key_from_file(const char *fname, int generate, int severity) { - crypto_pk_env_t *prkey = NULL; + crypto_pk_t *prkey = NULL; - if (!(prkey = crypto_new_pk_env())) { + if (!(prkey = crypto_pk_new())) { log(severity, LD_GENERAL,"Error constructing key"); goto error; } @@ -350,7 +357,7 @@ init_key_from_file(const char *fname, int generate, int severity) error: if (prkey) - crypto_free_pk_env(prkey); + crypto_pk_free(prkey); return NULL; } @@ -360,13 +367,13 @@ init_key_from_file(const char *fname, int generate, int severity) * key/cert set. On success, store them into *<b>key_out</b> and * *<b>cert_out</b> respectively, and return 0. On failure, return -1. */ static int -load_authority_keyset(int legacy, crypto_pk_env_t **key_out, +load_authority_keyset(int legacy, crypto_pk_t **key_out, authority_cert_t **cert_out) { int r = -1; char *fname = NULL, *cert = NULL; const char *eos = NULL; - crypto_pk_env_t *signing_key = NULL; + crypto_pk_t *signing_key = NULL; authority_cert_t *parsed = NULL; fname = get_datadir_fname2("keys", @@ -396,7 +403,7 @@ load_authority_keyset(int legacy, crypto_pk_env_t **key_out, goto done; } - crypto_free_pk_env(*key_out); + crypto_pk_free(*key_out); authority_cert_free(*cert_out); *key_out = signing_key; @@ -408,7 +415,7 @@ load_authority_keyset(int legacy, crypto_pk_env_t **key_out, done: tor_free(fname); tor_free(cert); - crypto_free_pk_env(signing_key); + crypto_pk_free(signing_key); authority_cert_free(parsed); return r; } @@ -477,6 +484,16 @@ v3_authority_check_key_expiry(void) last_warned = now; } +int +router_initialize_tls_context(void) +{ + return tor_tls_context_init(public_server_mode(get_options()), + get_tlsclient_identity_key(), + server_mode(get_options()) ? + get_server_identity_key() : NULL, + MAX_SSL_KEY_LIFETIME_ADVERTISED); +} + /** Initialize all OR private keys, and the TLS context, as necessary. * On OPs, this only initializes the tls context. Return 0 on success, * or -1 if Tor should die. @@ -489,12 +506,12 @@ init_keys(void) /*nickname<space>fp\n\0 */ char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3]; const char *mydesc; - crypto_pk_env_t *prkey; + crypto_pk_t *prkey; char digest[DIGEST_LEN]; char v3_digest[DIGEST_LEN]; char *cp; - or_options_t *options = get_options(); - authority_type_t type; + const or_options_t *options = get_options(); + dirinfo_type_t type; time_t now = time(NULL); trusted_dir_server_t *ds; int v3_digest_set = 0; @@ -515,18 +532,15 @@ init_keys(void) /* OP's don't need persistent keys; just make up an identity and * initialize the TLS context. */ if (!server_mode(options)) { - if (!(prkey = crypto_new_pk_env())) + if (!(prkey = crypto_pk_new())) return -1; if (crypto_pk_generate_key(prkey)) { - crypto_free_pk_env(prkey); + crypto_pk_free(prkey); return -1; } set_client_identity_key(prkey); /* Create a TLS context. */ - if (tor_tls_context_init(0, - get_tlsclient_identity_key(), - NULL, - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (router_initialize_tls_context() < 0) { log_err(LD_GENERAL,"Error creating TLS context for Tor client."); return -1; } @@ -575,10 +589,10 @@ init_keys(void) if (public_server_mode(options)) { set_client_identity_key(crypto_pk_dup_key(prkey)); /* set above */ } else { - if (!(prkey = crypto_new_pk_env())) + if (!(prkey = crypto_pk_new())) return -1; if (crypto_pk_generate_key(prkey)) { - crypto_free_pk_env(prkey); + crypto_pk_free(prkey); return -1; } set_client_identity_key(prkey); @@ -619,13 +633,11 @@ init_keys(void) tor_free(keydir); /* 3. Initialize link key and TLS context. */ - if (tor_tls_context_init(public_server_mode(options), - get_tlsclient_identity_key(), - get_server_identity_key(), - MAX_SSL_KEY_LIFETIME_ADVERTISED) < 0) { + if (router_initialize_tls_context() < 0) { log_err(LD_GENERAL,"Error initializing TLS context"); return -1; } + /* 4. Build our router descriptor. */ /* Must be called after keys are initialized. */ mydesc = router_get_my_descriptor(); @@ -639,15 +651,27 @@ init_keys(void) return -1; } if (mydesc) { + was_router_added_t added; ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL); if (!ri) { log_err(LD_GENERAL,"Generated a routerinfo we couldn't parse."); return -1; } - if (!WRA_WAS_ADDED(dirserv_add_descriptor(ri, &m, "self"))) { - log_err(LD_GENERAL,"Unable to add own descriptor to directory: %s", - m?m:"<unknown error>"); - return -1; + added = dirserv_add_descriptor(ri, &m, "self"); + if (!WRA_WAS_ADDED(added)) { + if (!WRA_WAS_OUTDATED(added)) { + log_err(LD_GENERAL, "Unable to add own descriptor to directory: %s", + m?m:"<unknown error>"); + return -1; + } else { + /* If the descriptor was outdated, that's ok. This can happen + * when some config options are toggled that affect workers, but + * we don't really need new keys yet so the descriptor doesn't + * change and the old one is still fresh. */ + log_info(LD_GENERAL, "Couldn't add own descriptor to directory " + "after key init: %s. This is usually not a problem.", + m?m:"<unknown error>"); + } } } } @@ -695,11 +719,12 @@ init_keys(void) } /* 6b. [authdirserver only] add own key to approved directories. */ crypto_pk_get_digest(get_server_identity_key(), digest); - type = ((options->V1AuthoritativeDir ? V1_AUTHORITY : NO_AUTHORITY) | - (options->V2AuthoritativeDir ? V2_AUTHORITY : NO_AUTHORITY) | - (options->V3AuthoritativeDir ? V3_AUTHORITY : NO_AUTHORITY) | - (options->BridgeAuthoritativeDir ? BRIDGE_AUTHORITY : NO_AUTHORITY) | - (options->HSAuthoritativeDir ? HIDSERV_AUTHORITY : NO_AUTHORITY)); + type = ((options->V1AuthoritativeDir ? V1_DIRINFO : NO_DIRINFO) | + (options->V2AuthoritativeDir ? V2_DIRINFO : NO_DIRINFO) | + (options->V3AuthoritativeDir ? + (V3_DIRINFO|MICRODESC_DIRINFO|EXTRAINFO_DIRINFO) : NO_DIRINFO) | + (options->BridgeAuthoritativeDir ? BRIDGE_DIRINFO : NO_DIRINFO) | + (options->HSAuthoritativeDir ? HIDSERV_DIRINFO : NO_DIRINFO)); ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { @@ -721,7 +746,7 @@ init_keys(void) type, ds->type); ds->type = type; } - if (v3_digest_set && (ds->type & V3_AUTHORITY) && + if (v3_digest_set && (ds->type & V3_DIRINFO) && tor_memneq(v3_digest, ds->v3_identity_digest, DIGEST_LEN)) { log_warn(LD_DIR, "V3 identity key does not match identity declared in " "DirServer line. Adjusting."); @@ -760,7 +785,7 @@ router_reset_reachability(void) int check_whether_orport_reachable(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); return options->AssumeReachable || can_reach_or_port; } @@ -769,10 +794,10 @@ check_whether_orport_reachable(void) int check_whether_dirport_reachable(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); return !options->DirPort || options->AssumeReachable || - we_are_hibernating() || + net_is_disabled() || can_reach_dir_port; } @@ -784,7 +809,7 @@ check_whether_dirport_reachable(void) * a DirPort. */ static int -decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) +decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) { static int advertising=1; /* start out assuming we will advertise */ int new_choice=1; @@ -798,7 +823,7 @@ decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) return 0; if (authdir_mode(options)) /* always publish */ return dir_port; - if (we_are_hibernating()) + if (net_is_disabled()) return 0; if (!check_whether_dirport_reachable()) return 0; @@ -810,9 +835,26 @@ decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) * make us choose not to publish. */ if (accounting_is_enabled(options)) { - /* if we might potentially hibernate */ - new_choice = 0; - reason = "AccountingMax enabled"; + /* Don't spend bytes for directory traffic if we could end up hibernating, + * but allow DirPort otherwise. Some people set AccountingMax because + * they're confused or to get statistics. */ + int interval_length = accounting_get_interval_length(); + uint32_t effective_bw = get_effective_bwrate(options); + if (!interval_length) { + log_warn(LD_BUG, "An accounting interval is not allowed to be zero " + "seconds long. Raising to 1."); + interval_length = 1; + } + log_info(LD_GENERAL, "Calculating whether to disable dirport: effective " + "bwrate: %u, AccountingMax: "U64_FORMAT", " + "accounting interval length %d", effective_bw, + U64_PRINTF_ARG(options->AccountingMax), + interval_length); + if (effective_bw >= + options->AccountingMax / interval_length) { + new_choice = 0; + reason = "AccountingMax enabled"; + } #define MIN_BW_TO_ADVERTISE_DIRPORT 51200 } else if (options->BandwidthRate < MIN_BW_TO_ADVERTISE_DIRPORT || (options->RelayBandwidthRate > 0 && @@ -849,14 +891,14 @@ decide_to_advertise_dirport(or_options_t *options, uint16_t dir_port) void consider_testing_reachability(int test_or, int test_dir) { - routerinfo_t *me = router_get_my_routerinfo(); + const routerinfo_t *me = router_get_my_routerinfo(); int orport_reachable = check_whether_orport_reachable(); tor_addr_t addr; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (!me) return; - if (routerset_contains_router(options->ExcludeNodes, me) && + if (routerset_contains_router(options->ExcludeNodes, me, -1) && options->StrictNodes) { /* If we've excluded ourself, and StrictNodes is set, we can't test * ourself. */ @@ -876,11 +918,15 @@ consider_testing_reachability(int test_or, int test_dir) } if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) { + extend_info_t *ei; log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.", !orport_reachable ? "reachability" : "bandwidth", me->address, me->or_port); - circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me, - CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + /* XXX IPv6 self testing IPv6 orports will need pref_addr */ + ei = extend_info_from_router(me, 0); + circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei, + CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); + extend_info_free(ei); } tor_addr_from_ipv4h(&addr, me->addr); @@ -903,11 +949,11 @@ consider_testing_reachability(int test_or, int test_dir) void router_orport_found_reachable(void) { - routerinfo_t *me = router_get_my_routerinfo(); + const routerinfo_t *me = router_get_my_routerinfo(); if (!can_reach_or_port && me) { log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from " "the outside. Excellent.%s", - get_options()->_PublishServerDescriptor != NO_AUTHORITY ? + get_options()->_PublishServerDescriptor != NO_DIRINFO ? " Publishing server descriptor." : ""); can_reach_or_port = 1; mark_my_descriptor_dirty("ORPort found reachable"); @@ -921,7 +967,7 @@ router_orport_found_reachable(void) void router_dirport_found_reachable(void) { - routerinfo_t *me = router_get_my_routerinfo(); + const routerinfo_t *me = router_get_my_routerinfo(); if (!can_reach_dir_port && me) { log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable " "from the outside. Excellent."); @@ -963,11 +1009,19 @@ router_perform_bandwidth_test(int num_circs, time_t now) } } +/** Return true iff our network is in some sense disabled: either we're + * hibernating, entering hibernation, or */ +int +net_is_disabled(void) +{ + return get_options()->DisableNetwork || we_are_hibernating(); +} + /** Return true iff we believe ourselves to be an authoritative * directory server. */ int -authdir_mode(or_options_t *options) +authdir_mode(const or_options_t *options) { return options->AuthoritativeDir != 0; } @@ -975,7 +1029,7 @@ authdir_mode(or_options_t *options) * directory server. */ int -authdir_mode_v1(or_options_t *options) +authdir_mode_v1(const or_options_t *options) { return authdir_mode(options) && options->V1AuthoritativeDir != 0; } @@ -983,7 +1037,7 @@ authdir_mode_v1(or_options_t *options) * directory server. */ int -authdir_mode_v2(or_options_t *options) +authdir_mode_v2(const or_options_t *options) { return authdir_mode(options) && options->V2AuthoritativeDir != 0; } @@ -991,13 +1045,13 @@ authdir_mode_v2(or_options_t *options) * directory server. */ int -authdir_mode_v3(or_options_t *options) +authdir_mode_v3(const or_options_t *options) { return authdir_mode(options) && options->V3AuthoritativeDir != 0; } /** Return true iff we are a v1, v2, or v3 directory authority. */ int -authdir_mode_any_main(or_options_t *options) +authdir_mode_any_main(const or_options_t *options) { return options->V1AuthoritativeDir || options->V2AuthoritativeDir || @@ -1006,16 +1060,16 @@ authdir_mode_any_main(or_options_t *options) /** Return true if we believe ourselves to be any kind of * authoritative directory beyond just a hidserv authority. */ int -authdir_mode_any_nonhidserv(or_options_t *options) +authdir_mode_any_nonhidserv(const or_options_t *options) { return options->BridgeAuthoritativeDir || authdir_mode_any_main(options); } /** Return true iff we are an authoritative directory server that is * authoritative about receiving and serving descriptors of type - * <b>purpose</b> its dirport. Use -1 for "any purpose". */ + * <b>purpose</b> on its dirport. Use -1 for "any purpose". */ int -authdir_mode_handles_descs(or_options_t *options, int purpose) +authdir_mode_handles_descs(const or_options_t *options, int purpose) { if (purpose < 0) return authdir_mode_any_nonhidserv(options); @@ -1030,7 +1084,7 @@ authdir_mode_handles_descs(or_options_t *options, int purpose) * publishes its own network statuses. */ int -authdir_mode_publishes_statuses(or_options_t *options) +authdir_mode_publishes_statuses(const or_options_t *options) { if (authdir_mode_bridge(options)) return 0; @@ -1040,7 +1094,7 @@ authdir_mode_publishes_statuses(or_options_t *options) * tests reachability of the descriptors it learns about. */ int -authdir_mode_tests_reachability(or_options_t *options) +authdir_mode_tests_reachability(const or_options_t *options) { return authdir_mode_handles_descs(options, -1); } @@ -1048,7 +1102,7 @@ authdir_mode_tests_reachability(or_options_t *options) * directory server. */ int -authdir_mode_bridge(or_options_t *options) +authdir_mode_bridge(const or_options_t *options) { return authdir_mode(options) && options->BridgeAuthoritativeDir != 0; } @@ -1056,16 +1110,16 @@ authdir_mode_bridge(or_options_t *options) /** Return true iff we are trying to be a server. */ int -server_mode(or_options_t *options) +server_mode(const or_options_t *options) { if (options->ClientOnly) return 0; - return (options->ORPort != 0 || options->ORListenAddress); + return (options->ORPort || options->ORListenAddress); } /** Return true iff we are trying to be a non-bridge server. */ int -public_server_mode(or_options_t *options) +public_server_mode(const or_options_t *options) { if (!server_mode(options)) return 0; return (!options->BridgeRelay); @@ -1075,10 +1129,10 @@ public_server_mode(or_options_t *options) * in the consensus mean that we don't want to allow exits from circuits * we got from addresses not known to be servers. */ int -should_refuse_unknown_exits(or_options_t *options) +should_refuse_unknown_exits(const or_options_t *options) { - if (options->RefuseUnknownExits_ != -1) { - return options->RefuseUnknownExits_; + if (options->RefuseUnknownExits != -1) { + return options->RefuseUnknownExits; } else { return networkstatus_get_param(NULL, "refuseunknownexits", 1, 0, 1); } @@ -1105,14 +1159,19 @@ set_server_advertised(int s) server_is_advertised = s; } -/** Return true iff we are trying to be a socks proxy. */ +/** Return true iff we are trying to proxy client connections. */ int -proxy_mode(or_options_t *options) -{ - return (options->SocksPort != 0 || - options->TransPort != 0 || - options->NATDPort != 0 || - options->DNSPort != 0); +proxy_mode(const or_options_t *options) +{ + (void)options; + SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { + if (p->type == CONN_TYPE_AP_LISTENER || + p->type == CONN_TYPE_AP_TRANS_LISTENER || + p->type == CONN_TYPE_AP_DNS_LISTENER || + p->type == CONN_TYPE_AP_NATD_LISTENER) + return 1; + } SMARTLIST_FOREACH_END(p); + return 0; } /** Decide if we're a publishable server. We are a publishable server if: @@ -1128,11 +1187,11 @@ proxy_mode(or_options_t *options) static int decide_if_publishable_server(void) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (options->ClientOnly) return 0; - if (options->_PublishServerDescriptor == NO_AUTHORITY) + if (options->_PublishServerDescriptor == NO_DIRINFO) return 0; if (!server_mode(options)) return 0; @@ -1171,17 +1230,21 @@ consider_publishable_server(int force) /** Return the port that we should advertise as our ORPort; this is either * the one configured in the ORPort option, or the one we actually bound to - * if ORPort is "auto". */ + * if ORPort is "auto". + */ uint16_t -router_get_advertised_or_port(or_options_t *options) +router_get_advertised_or_port(const or_options_t *options) { - if (options->ORPort == CFG_AUTO_PORT) { + int port = get_primary_or_port(); + (void)options; + + if (port == CFG_AUTO_PORT) { connection_t *c = connection_get_by_type(CONN_TYPE_OR_LISTENER); if (c) return c->port; return 0; } - return options->ORPort; + return port; } /** Return the port that we should advertise as our DirPort; @@ -1190,17 +1253,20 @@ router_get_advertised_or_port(or_options_t *options) * the one configured in the DirPort option, * or the one we actually bound to if DirPort is "auto". */ uint16_t -router_get_advertised_dir_port(or_options_t *options, uint16_t dirport) +router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport) { - if (!options->DirPort) + int dirport_configured = get_primary_dir_port(); + (void)options; + + if (!dirport_configured) return dirport; - if (options->DirPort == CFG_AUTO_PORT) { + if (dirport_configured == CFG_AUTO_PORT) { connection_t *c = connection_get_by_type(CONN_TYPE_DIR_LISTENER); if (c) return c->port; return 0; } - return options->DirPort; + return dirport_configured; } /* @@ -1211,9 +1277,14 @@ router_get_advertised_dir_port(or_options_t *options, uint16_t dirport) static routerinfo_t *desc_routerinfo = NULL; /** My extrainfo */ static extrainfo_t *desc_extrainfo = NULL; +/** Why did we most recently decide to regenerate our descriptor? Used to + * tell the authorities why we're sending it to them. */ +static const char *desc_gen_reason = NULL; /** Since when has our descriptor been "clean"? 0 if we need to regenerate it * now. */ static time_t desc_clean_since = 0; +/** Why did we mark the descriptor dirty? */ +static const char *desc_dirty_reason = NULL; /** Boolean: do we need to regenerate the above? */ static int desc_needs_upload = 0; @@ -1224,11 +1295,11 @@ static int desc_needs_upload = 0; void router_upload_dir_desc_to_dirservers(int force) { - routerinfo_t *ri; + const routerinfo_t *ri; extrainfo_t *ei; char *msg; size_t desc_len, extra_len = 0, total_len; - authority_type_t auth = get_options()->_PublishServerDescriptor; + dirinfo_type_t auth = get_options()->_PublishServerDescriptor; ri = router_get_my_routerinfo(); if (!ri) { @@ -1236,7 +1307,7 @@ router_upload_dir_desc_to_dirservers(int force) return; } ei = router_get_my_extrainfo(); - if (auth == NO_AUTHORITY) + if (auth == NO_DIRINFO) return; if (!force && !desc_needs_upload) return; @@ -1257,7 +1328,7 @@ router_upload_dir_desc_to_dirservers(int force) msg[desc_len+extra_len] = 0; directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_DIR, - (auth & BRIDGE_AUTHORITY) ? + (auth & BRIDGE_DIRINFO) ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL, auth, msg, desc_len, extra_len); @@ -1322,7 +1393,7 @@ router_extrainfo_digest_is_me(const char *digest) /** A wrapper around router_digest_is_me(). */ int -router_is_me(routerinfo_t *router) +router_is_me(const routerinfo_t *router) { return router_digest_is_me(router->cache_info.identity_digest); } @@ -1341,7 +1412,7 @@ router_fingerprint_is_me(const char *fp) /** Return a routerinfo for this OR, rebuilding a fresh one if * necessary. Return NULL on error, or if called on an OP. */ -routerinfo_t * +const routerinfo_t * router_get_my_routerinfo(void) { if (!server_mode(get_options())) @@ -1380,6 +1451,14 @@ router_get_my_extrainfo(void) return desc_extrainfo; } +/** Return a human-readable string describing what triggered us to generate + * our current descriptor, or NULL if we don't know. */ +const char * +router_get_descriptor_gen_reason(void) +{ + return desc_gen_reason; +} + /** A list of nicknames that we've warned about including in our family * declaration verbatim rather than as digests. */ static smartlist_t *warned_nonexistent_family = NULL; @@ -1391,10 +1470,8 @@ static int router_guess_address_from_dir_headers(uint32_t *guess); * dirserver headers. Place the answer in *<b>addr</b> and return * 0 on success, else return -1 if we have no guess. */ int -router_pick_published_address(or_options_t *options, uint32_t *addr) +router_pick_published_address(const or_options_t *options, uint32_t *addr) { - char buf[INET_NTOA_BUF_LEN]; - struct in_addr a; if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) { log_info(LD_CONFIG, "Could not determine our address locally. " "Checking if directory headers provide any hints."); @@ -1404,9 +1481,7 @@ router_pick_published_address(or_options_t *options, uint32_t *addr) return -1; } } - a.s_addr = htonl(*addr); - tor_inet_ntoa(&a, buf, sizeof(buf)); - log_info(LD_CONFIG,"Success: chose address '%s'.", buf); + log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr)); return 0; } @@ -1422,7 +1497,7 @@ router_rebuild_descriptor(int force) uint32_t addr; char platform[256]; int hibernating = we_are_hibernating(); - or_options_t *options = get_options(); + const or_options_t *options = get_options(); if (desc_clean_since && !force) return 0; @@ -1448,6 +1523,32 @@ 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 */ + if (options->BridgeRelay) { + /* For now, only bridges advertise an ipv6 or-address. And only one. */ + 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->ipv4_only && + tor_addr_family(&p->addr) == AF_INET6) { + if (! tor_addr_is_internal(&p->addr, 0)) { + ipv6_orport = p; + break; + } else { + char addrbuf[TOR_ADDR_BUF_LEN]; + log_warn(LD_CONFIG, + "Unable to use configured IPv6 address \"%s\" in a " + "descriptor. Skipping it. " + "Try specifying a globally reachable address explicitly. ", + tor_addr_to_str(addrbuf, &p->addr, sizeof(addrbuf), 1)); + } + } + } SMARTLIST_FOREACH_END(p); + if (ipv6_orport) { + tor_addr_copy(&ri->ipv6_addr, &ipv6_orport->addr); + ri->ipv6_orport = ipv6_orport->port; + } + } ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key()); if (crypto_pk_get_digest(ri->identity_pkey, ri->cache_info.identity_digest)<0) { @@ -1476,28 +1577,26 @@ router_rebuild_descriptor(int force) ri->policy_is_reject_star = policy_is_reject_star(ri->exit_policy); - if (desc_routerinfo) { /* inherit values */ - ri->is_valid = desc_routerinfo->is_valid; - ri->is_running = desc_routerinfo->is_running; - ri->is_named = desc_routerinfo->is_named; - } +#if 0 + /* XXXX NM NM I belive this is safe to remove */ if (authdir_mode(options)) ri->is_valid = ri->is_named = 1; /* believe in yourself */ +#endif + if (options->MyFamily) { smartlist_t *family; if (!warned_nonexistent_family) - warned_nonexistent_family = smartlist_create(); - family = smartlist_create(); - ri->declared_family = smartlist_create(); + warned_nonexistent_family = smartlist_new(); + family = smartlist_new(); + ri->declared_family = smartlist_new(); smartlist_split_string(family, options->MyFamily, ",", SPLIT_SKIP_SPACE|SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH(family, char *, name, - { - routerinfo_t *member; + SMARTLIST_FOREACH_BEGIN(family, char *, name) { + const node_t *member; if (!strcasecmp(name, options->Nickname)) - member = ri; + goto skip; /* Don't list ourself, that's redundant */ else - member = router_get_by_nickname(name, 1); + member = node_get_by_nickname(name, 1); if (!member) { int is_legal = is_legal_nickname_or_hexdigest(name); if (!smartlist_string_isin(warned_nonexistent_family, name) && @@ -1517,19 +1616,21 @@ router_rebuild_descriptor(int force) smartlist_add(ri->declared_family, name); name = NULL; } - } else if (router_is_me(member)) { + } else if (router_digest_is_me(member->identity)) { /* Don't list ourself in our own family; that's redundant */ + /* XXX shouldn't be possible */ } else { char *fp = tor_malloc(HEX_DIGEST_LEN+2); fp[0] = '$'; base16_encode(fp+1,HEX_DIGEST_LEN+1, - member->cache_info.identity_digest, DIGEST_LEN); + member->identity, DIGEST_LEN); smartlist_add(ri->declared_family, fp); if (smartlist_string_isin(warned_nonexistent_family, name)) smartlist_string_remove(warned_nonexistent_family, name); } + skip: tor_free(name); - }); + } SMARTLIST_FOREACH_END(name); /* remove duplicates from the list */ smartlist_sort_strings(ri->declared_family); @@ -1590,8 +1691,6 @@ router_rebuild_descriptor(int force) strlen(ri->cache_info.signed_descriptor_body), ri->cache_info.signed_descriptor_digest); - routerinfo_set_country(ri); - if (ei) { tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL)); } @@ -1603,24 +1702,68 @@ router_rebuild_descriptor(int force) desc_clean_since = time(NULL); desc_needs_upload = 1; + desc_gen_reason = desc_dirty_reason; + desc_dirty_reason = NULL; control_event_my_descriptor_changed(); return 0; } -/** Mark descriptor out of date if it's older than <b>when</b> */ +/** If our router descriptor ever goes this long without being regenerated + * because something changed, we force an immediate regenerate-and-upload. */ +#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60) + +/** If our router descriptor seems to be missing or unacceptable according + * to the authorities, regenerate and reupload it _this_ often. */ +#define FAST_RETRY_DESCRIPTOR_INTERVAL (90*60) + +/** Mark descriptor out of date if it's been "too long" since we last tried + * to upload one. */ void -mark_my_descriptor_dirty_if_older_than(time_t when) +mark_my_descriptor_dirty_if_too_old(time_t now) { - if (desc_clean_since < when) + networkstatus_t *ns; + const routerstatus_t *rs; + const char *retry_fast_reason = NULL; /* Set if we should retry frequently */ + const time_t slow_cutoff = now - FORCE_REGENERATE_DESCRIPTOR_INTERVAL; + const time_t fast_cutoff = now - FAST_RETRY_DESCRIPTOR_INTERVAL; + + /* If it's already dirty, don't mark it. */ + if (! desc_clean_since) + return; + + /* If it's older than FORCE_REGENERATE_DESCRIPTOR_INTERVAL, it's always + * time to rebuild it. */ + if (desc_clean_since < slow_cutoff) { mark_my_descriptor_dirty("time for new descriptor"); + return; + } + /* Now we see whether we want to be retrying frequently or no. The + * rule here is that we'll retry frequently if we aren't listed in the + * live consensus we have, or if the publication time of the + * descriptor listed for us in the consensus is very old. */ + ns = networkstatus_get_live_consensus(now); + if (ns) { + rs = networkstatus_vote_find_entry(ns, server_identitykey_digest); + if (rs == NULL) + retry_fast_reason = "not listed in consensus"; + else if (rs->published_on < slow_cutoff) + retry_fast_reason = "version listed in consensus is quite old"; + } + + if (retry_fast_reason && desc_clean_since < fast_cutoff) + mark_my_descriptor_dirty(retry_fast_reason); } /** Call when the current descriptor is out of date. */ void mark_my_descriptor_dirty(const char *reason) { + const or_options_t *options = get_options(); + if (server_mode(options) && options->_PublishServerDescriptor) + log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); desc_clean_since = 0; - log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); + if (!desc_dirty_reason) + desc_dirty_reason = reason; } /** How frequently will we republish our descriptor because of large (factor @@ -1654,21 +1797,20 @@ check_descriptor_bandwidth_changed(time_t now) /** Note at log level severity that our best guess of address has changed from * <b>prev</b> to <b>cur</b>. */ static void -log_addr_has_changed(int severity, uint32_t prev, uint32_t cur, +log_addr_has_changed(int severity, + const tor_addr_t *prev, + const tor_addr_t *cur, const char *source) { - char addrbuf_prev[INET_NTOA_BUF_LEN]; - char addrbuf_cur[INET_NTOA_BUF_LEN]; - struct in_addr in_prev; - struct in_addr in_cur; - - in_prev.s_addr = htonl(prev); - tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev)); + char addrbuf_prev[TOR_ADDR_BUF_LEN]; + char addrbuf_cur[TOR_ADDR_BUF_LEN]; - in_cur.s_addr = htonl(cur); - tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur)); + if (tor_addr_to_str(addrbuf_prev, prev, sizeof(addrbuf_prev), 1) == NULL) + strlcpy(addrbuf_prev, "???", TOR_ADDR_BUF_LEN); + if (tor_addr_to_str(addrbuf_cur, cur, sizeof(addrbuf_cur), 1) == NULL) + strlcpy(addrbuf_cur, "???", TOR_ADDR_BUF_LEN); - if (prev) + if (!tor_addr_is_null(prev)) log_fn(severity, LD_GENERAL, "Our IP Address has changed from %s to %s; " "rebuilding descriptor (source: %s).", @@ -1686,12 +1828,13 @@ void check_descriptor_ipaddress_changed(time_t now) { uint32_t prev, cur; - or_options_t *options = get_options(); + const or_options_t *options = get_options(); (void) now; if (!desc_routerinfo) return; + /* XXXX ipv6 */ prev = desc_routerinfo->addr; if (resolve_my_address(LOG_INFO, options, &cur, NULL) < 0) { log_info(LD_CONFIG,"options->Address didn't resolve into an IP."); @@ -1699,14 +1842,17 @@ check_descriptor_ipaddress_changed(time_t now) } if (prev != cur) { - log_addr_has_changed(LOG_NOTICE, prev, cur, "resolve"); + tor_addr_t tmp_prev, tmp_cur; + tor_addr_from_ipv4h(&tmp_prev, prev); + tor_addr_from_ipv4h(&tmp_cur, cur); + log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, "resolve"); ip_address_changed(0); } } /** The most recently guessed value of our IP address, based on directory * headers. */ -static uint32_t last_guessed_ip = 0; +static tor_addr_t last_guessed_ip = TOR_ADDR_NULL; /** A directory server <b>d_conn</b> told us our IP address is * <b>suggestion</b>. @@ -1716,35 +1862,36 @@ void router_new_address_suggestion(const char *suggestion, const dir_connection_t *d_conn) { - uint32_t addr, cur = 0; - struct in_addr in; - or_options_t *options = get_options(); + tor_addr_t addr; + uint32_t cur = 0; /* Current IPv4 address. */ + const or_options_t *options = get_options(); /* first, learn what the IP address actually is */ - if (!tor_inet_aton(suggestion, &in)) { + if (tor_addr_parse(&addr, suggestion) == -1) { log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.", escaped(suggestion)); return; } - addr = ntohl(in.s_addr); log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion); if (!server_mode(options)) { - last_guessed_ip = addr; /* store it in case we need it later */ + tor_addr_copy(&last_guessed_ip, &addr); return; } + /* XXXX ipv6 */ if (resolve_my_address(LOG_INFO, options, &cur, NULL) >= 0) { /* We're all set -- we already know our address. Great. */ - last_guessed_ip = cur; /* store it in case we need it later */ + tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we + need it later */ return; } - if (is_internal_IP(addr, 0)) { + if (tor_addr_is_internal(&addr, 0)) { /* Don't believe anybody who says our IP is, say, 127.0.0.1. */ return; } - if (tor_addr_eq_ipv4h(&d_conn->_base.addr, addr)) { + if (tor_addr_eq(&d_conn->_base.addr, &addr)) { /* Don't believe anybody who says our IP is their IP. */ log_debug(LD_DIR, "A directory server told us our IP address is %s, " "but he's just reporting his own IP address. Ignoring.", @@ -1755,14 +1902,15 @@ router_new_address_suggestion(const char *suggestion, /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving * us an answer different from what we had the last time we managed to * resolve it. */ - if (last_guessed_ip != addr) { + if (!tor_addr_eq(&last_guessed_ip, &addr)) { control_event_server_status(LOG_NOTICE, "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV", suggestion); - log_addr_has_changed(LOG_NOTICE, last_guessed_ip, addr, + log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr, d_conn->_base.address); ip_address_changed(0); - last_guessed_ip = addr; /* router_rebuild_descriptor() will fetch it */ + tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor() + will fetch it */ } } @@ -1773,8 +1921,8 @@ router_new_address_suggestion(const char *suggestion, static int router_guess_address_from_dir_headers(uint32_t *guess) { - if (last_guessed_ip) { - *guess = last_guessed_ip; + if (!tor_addr_is_null(&last_guessed_ip)) { + *guess = tor_addr_to_ipv4h(&last_guessed_ip); return 0; } return -1; @@ -1803,7 +1951,7 @@ get_platform_str(char *platform, size_t len) */ int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, - crypto_pk_env_t *ident_key) + crypto_pk_t *ident_key) { char *onion_pkey; /* Onion key, PEM-encoded. */ char *identity_pkey; /* Identity key, PEM-encoded. */ @@ -1817,7 +1965,8 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, int result=0; addr_policy_t *tmpe; char *family_line; - or_options_t *options = get_options(); + char *extra_or_address = NULL; + const or_options_t *options = get_options(); /* Make sure the identity key matches the one in the routerinfo. */ if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) { @@ -1851,11 +2000,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, format_iso_time(published, router->cache_info.published_on); if (router->declared_family && smartlist_len(router->declared_family)) { - size_t n; - char *family = smartlist_join_strings(router->declared_family, " ", 0, &n); - n += strlen("family ") + 2; /* 1 for \n, 1 for \0. */ - family_line = tor_malloc(n); - tor_snprintf(family_line, n, "family %s\n", family); + char *family = smartlist_join_strings(router->declared_family, + " ", 0, NULL); + tor_asprintf(&family_line, "family %s\n", family); tor_free(family); } else { family_line = tor_strdup(""); @@ -1869,9 +2016,22 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, router->cache_info.extra_info_digest, DIGEST_LEN); } + if (router->ipv6_orport && + tor_addr_family(&router->ipv6_addr) == AF_INET6) { + char addr[TOR_ADDR_BUF_LEN]; + const char *a; + a = tor_addr_to_str(addr, &router->ipv6_addr, sizeof(addr), 1); + if (a) { + tor_asprintf(&extra_or_address, + "or-address %s:%d\n", a, router->ipv6_orport); + log_debug(LD_OR, "My or-address line is <%s>", extra_or_address); + } + } + /* Generate the easy portion of the router descriptor. */ result = tor_snprintf(s, maxlen, "router %s %s %d 0 %d\n" + "%s" "platform %s\n" "opt protocols Link 1 2 Circuit 1\n" "published %s\n" @@ -1886,6 +2046,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, router->address, router->or_port, decide_to_advertise_dirport(options, router->dir_port), + extra_or_address ? extra_or_address : "", router->platform, published, fingerprint, @@ -1906,6 +2067,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, tor_free(family_line); tor_free(onion_pkey); tor_free(identity_pkey); + tor_free(extra_or_address); if (result < 0) { log_warn(LD_BUG,"descriptor snprintf #1 ran out of room!"); @@ -2001,6 +2163,52 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, return (int)written+1; } +/** Copy the primary (IPv4) OR port (IP address and TCP port) for + * <b>router</b> into *<b>ap_out</b>. */ +void +router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out) +{ + tor_assert(ap_out != NULL); + tor_addr_from_ipv4h(&ap_out->addr, router->addr); + ap_out->port = router->or_port; +} + +/** Return 1 if we prefer the IPv6 address and OR TCP port of + * <b>router</b>, else 0. + * + * We prefer the IPv6 address if the router has one and + * i) the routerinfo_t says so + * or + * ii) the router has no IPv4 address. */ +int +router_ipv6_preferred(const routerinfo_t *router) +{ + return (!tor_addr_is_null(&router->ipv6_addr) + && (router->ipv6_preferred || router->addr == 0)); +} + +/** Copy the preferred OR port (IP address and TCP port) for + * <b>router</b> into *<b>addr_out</b>. */ +void +router_get_pref_orport(const routerinfo_t *router, tor_addr_port_t *ap_out) +{ + if (router_ipv6_preferred(router)) + router_get_pref_ipv6_orport(router, ap_out); + else + router_get_prim_orport(router, ap_out); +} + +/** Copy the preferred IPv6 OR port (IP address and TCP port) for + * <b>router</b> into *<b>ap_out</b>. */ +void +router_get_pref_ipv6_orport(const routerinfo_t *router, + tor_addr_port_t *ap_out) +{ + tor_assert(ap_out != NULL); + tor_addr_copy(&ap_out->addr, &router->ipv6_addr); + ap_out->port = router->ipv6_orport; +} + /** Load the contents of <b>filename</b>, find the last line starting with * <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>, @@ -2057,9 +2265,9 @@ load_stats_file(const char *filename, const char *end_line, time_t now, * success, negative on failure. */ int extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, - crypto_pk_env_t *ident_key) + crypto_pk_t *ident_key) { - or_options_t *options = get_options(); + const or_options_t *options = get_options(); char identity[HEX_DIGEST_LEN+1]; char published[ISO_TIME_LEN+1]; char digest[DIGEST_LEN]; @@ -2069,7 +2277,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, char sig[DIROBJ_MAX_SIG_LEN+1]; char *s, *pre, *contents, *cp, *s_dup = NULL; time_t now = time(NULL); - smartlist_t *chunks = smartlist_create(); + smartlist_t *chunks = smartlist_new(); extrainfo_t *ei_tmp = NULL; base16_encode(identity, sizeof(identity), @@ -2083,6 +2291,10 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, tor_free(bandwidth_usage); smartlist_add(chunks, pre); + if (geoip_is_loaded()) { + smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", geoip_db_digest()); + } + if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); if (options->DirReqStatistics && @@ -2105,6 +2317,11 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, "exit-stats-end", now, &contents) > 0) { smartlist_add(chunks, contents); } + if (options->ConnDirectionStatistics && + load_stats_file("stats"PATH_SEPARATOR"conn-stats", + "conn-bi-direct", now, &contents) > 0) { + smartlist_add(chunks, contents); + } } if (should_record_bridge_info(options) && write_stats_to_extrainfo) { @@ -2291,13 +2508,45 @@ router_get_description(char *buf, const routerinfo_t *ri) return "<null>"; return format_node_description(buf, ri->cache_info.identity_digest, - ri->is_named, + router_is_named(ri), ri->nickname, NULL, ri->addr); } /** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to + * hold a human-readable description of <b>node</b>. + * + * Return a pointer to the front of <b>buf</b>. + */ +const char * +node_get_description(char *buf, const node_t *node) +{ + const char *nickname = NULL; + uint32_t addr32h = 0; + int is_named = 0; + + if (!node) + return "<null>"; + + if (node->rs) { + nickname = node->rs->nickname; + is_named = node->rs->is_named; + addr32h = node->rs->addr; + } else if (node->ri) { + nickname = node->ri->nickname; + addr32h = node->ri->addr; + } + + return format_node_description(buf, + node->identity, + is_named, + nickname, + NULL, + addr32h); +} + +/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to * hold a human-readable description of <b>rs</b>. * * Return a pointer to the front of <b>buf</b>. @@ -2345,6 +2594,18 @@ router_describe(const routerinfo_t *ri) return router_get_description(buf, ri); } +/** Return a human-readable description of the node_t <b>node</b>. + * + * This function is not thread-safe. Each call to this function invalidates + * previous values returned by this function. + */ +const char * +node_describe(const node_t *node) +{ + static char buf[NODE_DESC_BUF_LEN]; + return node_get_description(buf, node); +} + /** Return a human-readable description of the routerstatus_t <b>rs</b>. * * This function is not thread-safe. Each call to this function invalidates @@ -2379,10 +2640,15 @@ extend_info_describe(const extend_info_t *ei) void router_get_verbose_nickname(char *buf, const routerinfo_t *router) { + const char *good_digest = networkstatus_get_router_digest_by_nickname( + router->nickname); + int is_named = good_digest && tor_memeq(good_digest, + router->cache_info.identity_digest, + DIGEST_LEN); buf[0] = '$'; base16_encode(buf+1, HEX_DIGEST_LEN+1, router->cache_info.identity_digest, DIGEST_LEN); - buf[1+HEX_DIGEST_LEN] = router->is_named ? '=' : '~'; + buf[1+HEX_DIGEST_LEN] = is_named ? '=' : '~'; strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1); } @@ -2449,16 +2715,16 @@ router_purpose_from_string(const char *s) void router_free_all(void) { - crypto_free_pk_env(onionkey); - crypto_free_pk_env(lastonionkey); - crypto_free_pk_env(server_identitykey); - crypto_free_pk_env(client_identitykey); + crypto_pk_free(onionkey); + crypto_pk_free(lastonionkey); + crypto_pk_free(server_identitykey); + crypto_pk_free(client_identitykey); tor_mutex_free(key_lock); routerinfo_free(desc_routerinfo); extrainfo_free(desc_extrainfo); - crypto_free_pk_env(authority_signing_key); + crypto_pk_free(authority_signing_key); authority_cert_free(authority_key_certificate); - crypto_free_pk_env(legacy_signing_key); + crypto_pk_free(legacy_signing_key); authority_cert_free(legacy_key_certificate); if (warned_nonexistent_family) { |