aboutsummaryrefslogtreecommitdiff
path: root/src/or/router.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/router.c')
-rw-r--r--src/or/router.c513
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;
+}
+