diff options
Diffstat (limited to 'src/or/router.c')
-rw-r--r-- | src/or/router.c | 513 |
1 files changed, 405 insertions, 108 deletions
diff --git a/src/or/router.c b/src/or/router.c index 38f1cdd49..3fd8b3c07 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-2012, The Tor Project, Inc. */ + * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE @@ -13,6 +13,7 @@ #include "config.h" #include "connection.h" #include "control.h" +#include "crypto_curve25519.h" #include "directory.h" #include "dirserv.h" #include "dns.h" @@ -27,6 +28,9 @@ #include "router.h" #include "routerlist.h" #include "routerparse.h" +#include "statefile.h" +#include "transports.h" +#include "routerset.h" /** * \file router.c @@ -51,6 +55,13 @@ 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; @@ -84,7 +95,7 @@ static authority_cert_t *legacy_key_certificate = NULL; static void set_onion_key(crypto_pk_t *k) { - if (onionkey && !crypto_pk_cmp_keys(onionkey, k)) { + if (onionkey && crypto_pk_eq_keys(onionkey, k)) { /* k is already our onion key; free it and return */ crypto_pk_free(k); return; @@ -123,6 +134,55 @@ 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 * +get_current_curve25519_keypair(void) +{ + return &curve25519_onion_key; +} +/** Return a map from KEYID (the key itself) to keypairs for use in the ntor + * handshake. Must only be called from the main thread. */ +di_digest256_map_t * +construct_ntor_key_map(void) +{ + di_digest256_map_t *m = NULL; + + dimap_add_entry(&m, + curve25519_onion_key.pubkey.public_key, + tor_memdup(&curve25519_onion_key, + sizeof(curve25519_keypair_t))); + if (!tor_mem_is_zero((const char*) + last_curve25519_onion_key.pubkey.public_key, + CURVE25519_PUBKEY_LEN)) { + dimap_add_entry(&m, + last_curve25519_onion_key.pubkey.public_key, + tor_memdup(&last_curve25519_onion_key, + sizeof(curve25519_keypair_t))); + } + + return m; +} +/** Helper used to deallocate a di_digest256_map_t returned by + * construct_ntor_key_map. */ +static void +ntor_key_map_free_helper(void *arg) +{ + curve25519_keypair_t *k = arg; + memwipe(k, 0, sizeof(*k)); + tor_free(k); +} +/** Release all storage from a keymap returned by construct_ntor_key_map. */ +void +ntor_key_map_free(di_digest256_map_t *map) +{ + if (!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 * the process launched. @@ -152,12 +212,11 @@ assert_identity_keys_ok(void) if (public_server_mode(get_options())) { /* assert that we have set the client and server keys to be equal */ tor_assert(server_identitykey); - tor_assert(0==crypto_pk_cmp_keys(client_identitykey, server_identitykey)); + tor_assert(crypto_pk_eq_keys(client_identitykey, server_identitykey)); } 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(!crypto_pk_eq_keys(client_identitykey, server_identitykey)); } } @@ -251,11 +310,18 @@ void rotate_onion_key(void) { char *fname, *fname_prev; - crypto_pk_t *prkey; + 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"); + if (file_status(fname) == FN_FILE) { + if (replace_file(fname, fname_prev)) + goto error; + } if (!(prkey = crypto_pk_new())) { log_err(LD_GENERAL,"Error constructing rotated onion key"); goto error; @@ -264,19 +330,38 @@ rotate_onion_key(void) log_err(LD_BUG,"Error generating onion key"); goto error; } + if (crypto_pk_write_private_key_to_filename(prkey, fname)) { + 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; if (file_status(fname) == FN_FILE) { if (replace_file(fname, fname_prev)) goto error; } - if (crypto_pk_write_private_key_to_filename(prkey, fname)) { - log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname); + if (curve25519_keypair_write_to_file(&new_curve25519_keypair, fname, + "onion") < 0) { + 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); @@ -288,6 +373,9 @@ 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); } @@ -303,14 +391,14 @@ init_key_from_file(const char *fname, int generate, int severity) crypto_pk_t *prkey = NULL; if (!(prkey = crypto_pk_new())) { - log(severity, LD_GENERAL,"Error constructing key"); + tor_log(severity, LD_GENERAL,"Error constructing key"); goto error; } switch (file_status(fname)) { case FN_DIR: case FN_ERROR: - log(severity, LD_FS,"Can't read key from \"%s\"", fname); + tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); goto error; case FN_NOENT: if (generate) { @@ -318,8 +406,8 @@ init_key_from_file(const char *fname, int generate, int severity) if (try_locking(get_options(), 0)<0) { /* Make sure that --list-fingerprint only creates new keys * if there is no possibility for a deadlock. */ - log(severity, LD_FS, "Another Tor process has locked \"%s\". Not " - "writing any new keys.", fname); + tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". " + "Not writing any new keys.", fname); /*XXXX The 'other process' might make a key in a second or two; * maybe we should wait for it. */ goto error; @@ -328,16 +416,16 @@ init_key_from_file(const char *fname, int generate, int severity) log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.", fname); if (crypto_pk_generate_key(prkey)) { - log(severity, LD_GENERAL,"Error generating onion key"); + tor_log(severity, LD_GENERAL,"Error generating onion key"); goto error; } if (crypto_pk_check_key(prkey) <= 0) { - log(severity, LD_GENERAL,"Generated key seems invalid"); + tor_log(severity, LD_GENERAL,"Generated key seems invalid"); goto error; } log_info(LD_GENERAL, "Generated key seems valid"); if (crypto_pk_write_private_key_to_filename(prkey, fname)) { - log(severity, LD_FS, + tor_log(severity, LD_FS, "Couldn't write generated key to \"%s\".", fname); goto error; } @@ -347,7 +435,7 @@ init_key_from_file(const char *fname, int generate, int severity) return prkey; case FN_FILE: if (crypto_pk_read_private_key_from_filename(prkey, fname)) { - log(severity, LD_GENERAL,"Error loading private key."); + tor_log(severity, LD_GENERAL,"Error loading private key."); goto error; } return prkey; @@ -361,6 +449,77 @@ 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. */ +static int +init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out, + const char *fname, + int generate, + int severity, + const char *tag) +{ + switch (file_status(fname)) { + case FN_DIR: + case FN_ERROR: + tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); + goto error; + case FN_NOENT: + if (generate) { + if (!have_lockfile()) { + if (try_locking(get_options(), 0)<0) { + /* Make sure that --list-fingerprint only creates new keys + * if there is no possibility for a deadlock. */ + tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". " + "Not writing any new keys.", fname); + /*XXXX The 'other process' might make a key in a second or two; + * maybe we should wait for it. */ + goto error; + } + } + log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.", + fname); + if (curve25519_keypair_generate(keys_out, 1) < 0) + goto error; + 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)); + goto error; + } + } else { + log_info(LD_GENERAL, "No key found in \"%s\"", fname); + } + return 0; + case FN_FILE: + { + char *tag_in=NULL; + if (curve25519_keypair_read_from_file(keys_out, &tag_in, fname) < 0) { + tor_log(severity, LD_GENERAL,"Error loading private key."); + tor_free(tag_in); + goto error; + } + if (!tag_in || strcmp(tag_in, tag)) { + tor_log(severity, LD_GENERAL,"Unexpected tag %s on private key.", + escaped(tag_in)); + tor_free(tag_in); + goto error; + } + tor_free(tag_in); + return 0; + } + default: + tor_assert(0); + } + + 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 * legacy key/cert set for emergency key migration; otherwise load the regular @@ -397,7 +556,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, log_warn(LD_DIR, "Unable to parse certificate in %s", fname); goto done; } - if (crypto_pk_cmp_keys(signing_key, parsed->signing_key) != 0) { + if (!crypto_pk_eq_keys(signing_key, parsed->signing_key)) { log_warn(LD_DIR, "Stored signing key does not match signing key in " "certificate"); goto done; @@ -472,14 +631,14 @@ v3_authority_check_key_expiry(void) return; if (time_left <= 0) { - log(badness, LD_DIR, "Your v3 authority certificate has expired." - " Generate a new one NOW."); + tor_log(badness, LD_DIR, "Your v3 authority certificate has expired." + " Generate a new one NOW."); } else if (time_left <= 24*60*60) { - log(badness, LD_DIR, "Your v3 authority certificate expires in %d hours;" - " Generate a new one NOW.", time_left/(60*60)); + tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d " + "hours; Generate a new one NOW.", time_left/(60*60)); } else { - log(badness, LD_DIR, "Your v3 authority certificate expires in %d days;" - " Generate a new one soon.", time_left/(24*60*60)); + tor_log(badness, LD_DIR, "Your v3 authority certificate expires in %d " + "days; Generate a new one soon.", time_left/(24*60*60)); } last_warned = now; } @@ -489,7 +648,18 @@ v3_authority_check_key_expiry(void) int router_initialize_tls_context(void) { - return tor_tls_context_init(public_server_mode(get_options()), + unsigned int flags = 0; + const or_options_t *options = get_options(); + if (public_server_mode(options)) + flags |= TOR_TLS_CTX_IS_PUBLIC_SERVER; + if (options->TLSECGroup) { + if (!strcasecmp(options->TLSECGroup, "P256")) + flags |= TOR_TLS_CTX_USE_ECDHE_P256; + else if (!strcasecmp(options->TLSECGroup, "P224")) + flags |= TOR_TLS_CTX_USE_ECDHE_P224; + } + + return tor_tls_context_init(flags, get_tlsclient_identity_key(), server_mode(get_options()) ? get_server_identity_key() : NULL, @@ -515,7 +685,7 @@ init_keys(void) const or_options_t *options = get_options(); dirinfo_type_t type; time_t now = time(NULL); - trusted_dir_server_t *ds; + dir_server_t *ds; int v3_digest_set = 0; authority_cert_t *cert = NULL; @@ -628,12 +798,35 @@ 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); + prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */ if (prkey) lastonionkey = prkey; } tor_free(keydir); +#ifdef CURVE25519_ENABLED + { + /* 2b. Load curve25519 onion keys. */ + int r; + keydir = get_datadir_fname2("keys", "secret_onion_key_ntor"); + r = init_curve25519_keypair_from_file(&curve25519_onion_key, + keydir, 1, LOG_ERR, "onion"); + tor_free(keydir); + if (r<0) + return -1; + + keydir = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); + if (tor_mem_is_zero((const char *) + last_curve25519_onion_key.pubkey.public_key, + CURVE25519_PUBKEY_LEN) && + file_status(keydir) == FN_FILE) { + 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) { log_err(LD_GENERAL,"Error initializing TLS context"); @@ -671,7 +864,7 @@ init_keys(void) * 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.", + "after key init: %s This is usually not a problem.", m?m:"<unknown error>"); } } @@ -709,7 +902,7 @@ init_keys(void) tor_free(cp); tor_free(keydir); - log(LOG_NOTICE, LD_GENERAL, + log_notice(LD_GENERAL, "Your Tor server's identity key fingerprint is '%s %s'", options->Nickname, fingerprint); if (!authdir_mode(options)) @@ -730,17 +923,18 @@ init_keys(void) ds = router_get_trusteddirserver_by_digest(digest); if (!ds) { - ds = add_trusted_dir_server(options->Nickname, NULL, + ds = trusted_dir_server_new(options->Nickname, NULL, router_get_advertised_dir_port(options, 0), router_get_advertised_or_port(options), digest, v3_digest, - type); + type, 0.0); if (!ds) { log_err(LD_GENERAL,"We want to be a directory authority, but we " "couldn't add ourselves to the authority list. Failing."); return -1; } + dir_server_add(ds); } if (ds->type != type) { log_warn(LD_DIR, "Configured authority type does not match authority " @@ -868,10 +1062,10 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) if (advertising != new_choice) { if (new_choice == 1) { - log(LOG_NOTICE, LD_DIR, "Advertising DirPort as %d", dir_port); + log_notice(LD_DIR, "Advertising DirPort as %d", dir_port); } else { tor_assert(reason); - log(LOG_NOTICE, LD_DIR, "Not advertising DirPort (Reason: %s)", reason); + log_notice(LD_DIR, "Not advertising DirPort (Reason: %s)", reason); } advertising = new_choice; } @@ -879,6 +1073,22 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port) return advertising ? dir_port : 0; } +/** Allocate and return a new extend_info_t that can be used to build + * a circuit to or through the router <b>r</b>. Use the primary + * address of the router unless <b>for_direct_connect</b> is true, in + * which case the preferred address is used instead. */ +static extend_info_t * +extend_info_from_router(const routerinfo_t *r) +{ + tor_addr_port_t ap; + tor_assert(r); + + router_get_prim_orport(r, &ap); + return extend_info_new(r->nickname, r->cache_info.identity_digest, + r->onion_pkey, r->onion_curve25519_pkey, + &ap.addr, ap.port); +} + /** Some time has passed, or we just got new directory information. * See if we currently believe our ORPort or DirPort to be * unreachable. If so, launch a new test for it. @@ -907,25 +1117,21 @@ consider_testing_reachability(int test_or, int test_dir) if (test_or || test_dir) { #define SELF_EXCLUDED_WARN_INTERVAL 3600 static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL); - char *msg; - if ((msg = rate_limit_log(&warning_limit, approx_time()))) { - log_warn(LD_CIRC, "Can't peform self-tests for this relay: we have " + log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC, + "Can't peform self-tests for this relay: we have " "listed ourself in ExcludeNodes, and StrictNodes is set. " "We cannot learn whether we are usable, and will not " - "be able to advertise ourself.%s", msg); - tor_free(msg); - } + "be able to advertise ourself."); } return; } if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) { - extend_info_t *ei; + extend_info_t *ei = extend_info_from_router(me); + /* XXX IPv6 self testing */ log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.", !orport_reachable ? "reachability" : "bandwidth", me->address, me->or_port); - /* 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); @@ -939,11 +1145,10 @@ consider_testing_reachability(int test_or, int test_dir) /* ask myself, via tor, for my server descriptor. */ directory_initiate_command(me->address, &addr, me->or_port, me->dir_port, - 0, /* does not matter */ - 0, me->cache_info.identity_digest, + me->cache_info.identity_digest, DIR_PURPOSE_FETCH_SERVERDESC, ROUTER_PURPOSE_GENERAL, - 1, "authority.z", NULL, 0, 0); + DIRIND_ANON_DIRPORT, "authority.z", NULL, 0, 0); } } @@ -955,7 +1160,7 @@ router_orport_found_reachable(void) 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_DIRINFO ? + get_options()->PublishServerDescriptor_ != NO_DIRINFO ? " Publishing server descriptor." : ""); can_reach_or_port = 1; mark_my_descriptor_dirty("ORPort found reachable"); @@ -998,9 +1203,9 @@ router_perform_bandwidth_test(int num_circs, time_t now) CIRCUIT_PURPOSE_TESTING))) { /* dump cells_per_circuit drop cells onto this circ */ int i = cells_per_circuit; - if (circ->_base.state != CIRCUIT_STATE_OPEN) + if (circ->base_.state != CIRCUIT_STATE_OPEN) continue; - circ->_base.timestamp_dirty = now; + circ->base_.timestamp_dirty = now; while (i-- > 0) { if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), RELAY_COMMAND_DROP, @@ -1194,7 +1399,7 @@ decide_if_publishable_server(void) if (options->ClientOnly) return 0; - if (options->_PublishServerDescriptor == NO_DIRINFO) + if (options->PublishServerDescriptor_ == NO_DIRINFO) return 0; if (!server_mode(options)) return 0; @@ -1315,7 +1520,7 @@ router_upload_dir_desc_to_dirservers(int force) extrainfo_t *ei; char *msg; size_t desc_len, extra_len = 0, total_len; - dirinfo_type_t auth = get_options()->_PublishServerDescriptor; + dirinfo_type_t auth = get_options()->PublishServerDescriptor_; ri = router_get_my_routerinfo(); if (!ri) { @@ -1355,22 +1560,34 @@ router_upload_dir_desc_to_dirservers(int force) * conn. Return 0 if we accept; non-0 if we reject. */ int -router_compare_to_my_exit_policy(edge_connection_t *conn) +router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port) { if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */ return -1; /* make sure it's resolved to something. this way we can't get a 'maybe' below. */ - if (tor_addr_is_null(&conn->_base.addr)) + if (tor_addr_is_null(addr)) return -1; - /* XXXX IPv6 */ - if (tor_addr_family(&conn->_base.addr) != AF_INET) + /* look at desc_routerinfo->exit_policy for both the v4 and the v6 + * policies. The exit_policy field in desc_routerinfo is a bit unusual, + * in that it contains IPv6 and IPv6 entries. We don't want to look + * at desc_routerinfio->ipv6_exit_policy, since that's a port summary. */ + if ((tor_addr_family(addr) == AF_INET || + tor_addr_family(addr) == AF_INET6)) { + return compare_tor_addr_to_addr_policy(addr, port, + desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; +#if 0 + } else if (tor_addr_family(addr) == AF_INET6) { + return get_options()->IPv6Exit && + desc_routerinfo->ipv6_exit_policy && + compare_tor_addr_to_short_policy(addr, port, + desc_routerinfo->ipv6_exit_policy) != ADDR_POLICY_ACCEPTED; +#endif + } else { return -1; - - return compare_tor_addr_to_addr_policy(&conn->_base.addr, conn->_base.port, - desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED; + } } /** Return true iff my exit policy is reject *:*. Return -1 if we don't @@ -1393,6 +1610,13 @@ router_digest_is_me(const char *digest) tor_memeq(server_identitykey_digest, digest, DIGEST_LEN)); } +/** Return my identity digest. */ +const uint8_t * +router_get_my_id_digest(void) +{ + return (const uint8_t *)server_identitykey_digest; +} + /** Return true iff I'm a server and <b>digest</b> is equal to * my identity digest. */ int @@ -1539,13 +1763,19 @@ 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. */ +#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->ipv4_only && + ! p->bind_ipv4_only && tor_addr_family(&p->addr) == AF_INET6) { if (! tor_addr_is_internal(&p->addr, 0)) { ipv6_orport = p; @@ -1565,6 +1795,7 @@ router_rebuild_descriptor(int force) 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) { @@ -1587,11 +1818,20 @@ router_rebuild_descriptor(int force) policies_exit_policy_append_reject_star(&ri->exit_policy); } else { policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy, + options->IPv6Exit, options->ExitPolicyRejectPrivate, ri->address, !options->BridgeRelay); } ri->policy_is_reject_star = - policy_is_reject_star(ri->exit_policy); + policy_is_reject_star(ri->exit_policy, AF_INET) && + policy_is_reject_star(ri->exit_policy, AF_INET6); + + if (options->IPv6Exit) { + char *p_tmp = policy_summarize(ri->exit_policy, AF_INET6); + if (p_tmp) + ri->ipv6_exit_policy = parse_short_policy(p_tmp); + tor_free(p_tmp); + } #if 0 /* XXXX NM NM I belive this is safe to remove */ @@ -1615,7 +1855,7 @@ router_rebuild_descriptor(int force) 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) && + if (!smartlist_contains_string(warned_nonexistent_family, name) && !is_legal_hexdigest(name)) { if (is_legal) log_warn(LD_CONFIG, @@ -1641,7 +1881,7 @@ router_rebuild_descriptor(int force) base16_encode(fp+1,HEX_DIGEST_LEN+1, member->identity, DIGEST_LEN); smartlist_add(ri->declared_family, fp); - if (smartlist_string_isin(warned_nonexistent_family, name)) + if (smartlist_contains_string(warned_nonexistent_family, name)) smartlist_string_remove(warned_nonexistent_family, name); } skip: @@ -1779,7 +2019,7 @@ void mark_my_descriptor_dirty(const char *reason) { const or_options_t *options = get_options(); - if (server_mode(options) && options->_PublishServerDescriptor) + if (server_mode(options) && options->PublishServerDescriptor_) log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason); desc_clean_since = 0; if (!desc_dirty_reason) @@ -1911,7 +2151,7 @@ router_new_address_suggestion(const char *suggestion, /* Don't believe anybody who says our IP is, say, 127.0.0.1. */ return; } - if (tor_addr_eq(&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.", @@ -1927,7 +2167,7 @@ router_new_address_suggestion(const char *suggestion, "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV", suggestion); log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr, - d_conn->_base.address); + d_conn->base_.address); ip_address_changed(0); tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor() will fetch it */ @@ -1984,13 +2224,12 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, size_t onion_pkeylen, identity_pkeylen; size_t written; int result=0; - addr_policy_t *tmpe; char *family_line; 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)) { + if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) { log_warn(LD_BUG,"Tried to sign a router with a private key that didn't " "match router's public key!"); return -1; @@ -2054,9 +2293,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, "router %s %s %d 0 %d\n" "%s" "platform %s\n" - "opt protocols Link 1 2 Circuit 1\n" + "protocols Link 1 2 Circuit 1\n" "published %s\n" - "opt fingerprint %s\n" + "fingerprint %s\n" "uptime %ld\n" "bandwidth %d %d %d\n" "%s%s%s%s" @@ -2075,15 +2314,15 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, (int) router->bandwidthrate, (int) router->bandwidthburst, (int) router->bandwidthcapacity, - has_extra_info_digest ? "opt extra-info-digest " : "", + has_extra_info_digest ? "extra-info-digest " : "", has_extra_info_digest ? extra_info_digest : "", has_extra_info_digest ? "\n" : "", - options->DownloadExtraInfo ? "opt caches-extra-info\n" : "", + options->DownloadExtraInfo ? "caches-extra-info\n" : "", onion_pkey, identity_pkey, family_line, - we_are_hibernating() ? "opt hibernating 1\n" : "", - options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "", - options->AllowSingleHopExits ? "opt allow-single-hop-exits\n" : ""); + we_are_hibernating() ? "hibernating 1\n" : "", + options->HidServDirectoryV2 ? "hidden-service-dir\n" : "", + options->AllowSingleHopExits ? "allow-single-hop-exits\n" : ""); tor_free(family_line); tor_free(onion_pkey); @@ -2109,15 +2348,32 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, written += result; } +#ifdef CURVE25519_ENABLED + if (router->onion_curve25519_pkey) { + char kbuf[128]; + base64_encode(kbuf, sizeof(kbuf), + (const char *)router->onion_curve25519_pkey->public_key, + CURVE25519_PUBKEY_LEN); + result = tor_snprintf(s+written,maxlen-written, "ntor-onion-key %s", + kbuf); + if (result<0) { + log_warn(LD_BUG,"descriptor snprintf ran out of room!"); + return -1; + } + written += result; + } +#endif + /* Write the exit policy to the end of 's'. */ if (!router->exit_policy || !smartlist_len(router->exit_policy)) { strlcat(s+written, "reject *:*\n", maxlen-written); written += strlen("reject *:*\n"); - tmpe = NULL; } else if (router->exit_policy) { int i; for (i = 0; i < smartlist_len(router->exit_policy); ++i) { - tmpe = smartlist_get(router->exit_policy, i); + addr_policy_t *tmpe = smartlist_get(router->exit_policy, i); + if (tor_addr_family(&tmpe->addr) == AF_INET6) + continue; /* Don't include IPv6 parts of address policy */ result = policy_write_item(s+written, maxlen-written, tmpe, 1); if (result < 0) { log_warn(LD_BUG,"descriptor policy_write_item ran out of room!"); @@ -2133,6 +2389,21 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, } } + if (router->ipv6_exit_policy) { + char *p6 = write_short_policy(router->ipv6_exit_policy); + if (p6 && strcmp(p6, "reject 1-65535")) { + result = tor_snprintf(s+written, maxlen-written, + "ipv6-policy %s\n", p6); + if (result<0) { + log_warn(LD_BUG,"Descriptor printf of policy ran out of room"); + tor_free(p6); + return -1; + } + written += result; + } + tor_free(p6); + } + if (written + DIROBJ_MAX_SIG_LEN > maxlen) { /* Not enough room for signature. */ log_warn(LD_BUG,"not enough room left in descriptor for signature!"); @@ -2194,40 +2465,24 @@ router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out) 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. */ +/** Return 1 if any of <b>router</b>'s addresses are <b>addr</b>. + * Otherwise return 0. */ 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) +router_has_addr(const routerinfo_t *router, const tor_addr_t *addr) { - if (router_ipv6_preferred(router)) - router_get_pref_ipv6_orport(router, ap_out); - else - router_get_prim_orport(router, ap_out); + return + tor_addr_eq_ipv4h(addr, router->addr) || + tor_addr_eq(&router->ipv6_addr, addr); } -/** 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) +int +router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport) { - tor_assert(ap_out != NULL); - tor_addr_copy(&ap_out->addr, &router->ipv6_addr); - ap_out->port = router->ipv6_orport; + return + (tor_addr_eq_ipv4h(&orport->addr, router->addr) && + orport->port == router->or_port) || + (tor_addr_eq(&orport->addr, &router->ipv6_addr) && + orport->port == router->ipv6_orport); } /** Load the contents of <b>filename</b>, find the last line starting with @@ -2312,9 +2567,12 @@ 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 (geoip_is_loaded(AF_INET)) + smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", + geoip_db_digest(AF_INET)); + if (geoip_is_loaded(AF_INET6)) + smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n", + geoip_db_digest(AF_INET6)); if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); @@ -2345,6 +2603,13 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo, } } + /* Add information about the pluggable transports we support. */ + if (options->ServerTransportPlugin) { + char *pluggable_transports = pt_get_extra_info_descriptor_string(); + if (pluggable_transports) + smartlist_add(chunks, pluggable_transports); + } + if (should_record_bridge_info(options) && write_stats_to_extrainfo) { const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); if (bridge_stats) { @@ -2748,9 +3013,41 @@ 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)); smartlist_free(warned_nonexistent_family); } } +/** Return a smartlist of tor_addr_port_t's with all the OR ports of + <b>ri</b>. Note that freeing of the items in the list as well as + the smartlist itself is the callers responsibility. + + XXX duplicating code from node_get_all_orports(). */ +smartlist_t * +router_get_all_orports(const routerinfo_t *ri) +{ + smartlist_t *sl = smartlist_new(); + tor_assert(ri); + + if (ri->addr != 0) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_from_ipv4h(&ap->addr, ri->addr); + ap->port = ri->or_port; + smartlist_add(sl, ap); + } + if (!tor_addr_is_null(&ri->ipv6_addr)) { + tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); + tor_addr_copy(&ap->addr, &ri->ipv6_addr); + ap->port = ri->or_port; + smartlist_add(sl, ap); + } + + return sl; +} + |