/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
#include "or.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "control.h"
#include "crypto_curve25519.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
#include "relay.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
#include "statefile.h"
#include "transports.h"
#include "routerset.h"
/**
* \file router.c
* \brief OR functionality, including key maintenance, generating
* and uploading server descriptors, retrying OR connections.
**/
extern long stats_n_seconds_working;
/************************************************************/
/*****
* Key management: ORs only.
*****/
/** Private keys for this OR. There is also an SSL key managed by tortls.c.
*/
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_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;
/** 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_t *client_identitykey=NULL;
/** Signing key used for v3 directory material; only set for authorities. */
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_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;
/* (Note that v3 authorities also have a separate "authority identity key",
* but this key is never actually loaded by the Tor process. Instead, it's
* used by tor-gencert to sign new signing keys and make new key
* certificates. */
/** Replace the current onion key with k. Does not affect
* lastonionkey; to update lastonionkey correctly, call rotate_onion_key().
*/
static void
set_onion_key(crypto_pk_t *k)
{
if (onionkey && crypto_pk_eq_keys(onionkey, k)) {
/* k is already our onion key; free it and return */
crypto_pk_free(k);
return;
}
tor_mutex_acquire(key_lock);
crypto_pk_free(onionkey);
onionkey = k;
tor_mutex_release(key_lock);
mark_my_descriptor_dirty("set onion key");
}
/** Return the current onion key. Requires that the onion key has been
* loaded or generated. */
crypto_pk_t *
get_onion_key(void)
{
tor_assert(onionkey);
return onionkey;
}
/** Store a full copy of the current onion key into *key, and a full
* copy of the most recent onion key into *last.
*/
void
dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last)
{
tor_assert(key);
tor_assert(last);
tor_mutex_acquire(key_lock);
tor_assert(onionkey);
*key = crypto_pk_copy_full(onionkey);
if (lastonionkey)
*last = crypto_pk_copy_full(lastonionkey);
else
*last = NULL;
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.
*/
time_t
get_onion_key_set_at(void)
{
return onionkey_set_at;
}
/** Set the current server identity key to k.
*/
void
set_server_identity_key(crypto_pk_t *k)
{
crypto_pk_free(server_identitykey);
server_identitykey = k;
crypto_pk_get_digest(server_identitykey, server_identitykey_digest);
}
/** Make sure that we have set up our identity keys to match or not match as
* appropriate, and die with an assertion if we have not. */
static void
assert_identity_keys_ok(void)
{
tor_assert(client_identitykey);
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(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(!crypto_pk_eq_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_t *
get_server_identity_key(void)
{
tor_assert(server_identitykey);
tor_assert(server_mode(get_options()));
assert_identity_keys_ok();
return server_identitykey;
}
/** Return true iff the server identity key has been set. */
int
server_identity_key_is_set(void)
{
return server_identitykey != NULL;
}
/** Set the current client identity key to k.
*/
void
set_client_identity_key(crypto_pk_t *k)
{
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_t *
get_tlsclient_identity_key(void)
{
tor_assert(client_identitykey);
assert_identity_keys_ok();
return client_identitykey;
}
/** Return true iff the client identity key has been set. */
int
client_identity_key_is_set(void)
{
return client_identitykey != NULL;
}
/** Return the key certificate for this v3 (voting) authority, or NULL
* if we have no such certificate. */
authority_cert_t *
get_my_v3_authority_cert(void)
{
return authority_key_certificate;
}
/** Return the v3 signing key for this v3 (voting) authority, or NULL
* if we have no such key. */
crypto_pk_t *
get_my_v3_authority_signing_key(void)
{
return authority_signing_key;
}
/** If we're an authority, and we're using a legacy authority identity key for
* emergency migration purposes, return the certificate associated with that
* key. */
authority_cert_t *
get_my_v3_legacy_cert(void)
{
return legacy_key_certificate;
}
/** If we're an authority, and we're using a legacy authority identity key for
* emergency migration purposes, return that key. */
crypto_pk_t *
get_my_v3_legacy_signing_key(void)
{
return legacy_signing_key;
}
/** Replace the previous onion key with the current onion key, and generate
* a new previous onion key. Immediately after calling this function,
* the OR should:
* - schedule all previous cpuworkers to shut down _after_ processing
* pending work. (This will cause fresh cpuworkers to be generated.)
* - generate and upload a fresh routerinfo.
*/
void
rotate_onion_key(void)
{
char *fname, *fname_prev;
crypto_pk_t *prkey = NULL;
or_state_t *state = get_or_state();
#ifdef CURVE25519_ENABLED
curve25519_keypair_t new_curve25519_keypair;
#endif
time_t now;
fname = get_datadir_fname2("keys", "secret_onion_key");
fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
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;
}
if (crypto_pk_generate_key(prkey)) {
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 (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);
mark_my_descriptor_dirty("rotated onion key");
or_state_mark_dirty(state, get_options()->AvoidDiskWrites ? now+3600 : 0);
goto done;
error:
log_warn(LD_GENERAL, "Couldn't rotate onion key.");
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);
}
/** Try to read an RSA key from fname. If fname doesn't exist
* and generate is true, create a new RSA key and save it in
* fname. Return the read/created key, or NULL on error. Log all
* errors at level severity.
*/
crypto_pk_t *
init_key_from_file(const char *fname, int generate, int severity)
{
crypto_pk_t *prkey = NULL;
if (!(prkey = crypto_pk_new())) {
tor_log(severity, LD_GENERAL,"Error constructing key");
goto error;
}
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 (crypto_pk_generate_key(prkey)) {
tor_log(severity, LD_GENERAL,"Error generating onion key");
goto error;
}
if (crypto_pk_check_key(prkey) <= 0) {
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)) {
tor_log(severity, LD_FS,
"Couldn't write generated key to \"%s\".", fname);
goto error;
}
} else {
log_info(LD_GENERAL, "No key found in \"%s\"", fname);
}
return prkey;
case FN_FILE:
if (crypto_pk_read_private_key_from_filename(prkey, fname)) {
tor_log(severity, LD_GENERAL,"Error loading private key.");
goto error;
}
return prkey;
default:
tor_assert(0);
}
error:
if (prkey)
crypto_pk_free(prkey);
return NULL;
}
#ifdef CURVE25519_ENABLED
/** Load a curve25519 keypair from the file fname, writing it into
* keys_out. If the file isn't found and generate is true,
* create a new keypair and write it into the file. If there are errors, log
* them at level severity. Generate files using tag 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 legacy, load a
* legacy key/cert set for emergency key migration; otherwise load the regular
* key/cert set. On success, store them into *key_out and
* *cert_out respectively, and return 0. On failure, return -1. */
static int
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_t *signing_key = NULL;
authority_cert_t *parsed = NULL;
fname = get_datadir_fname2("keys",
legacy ? "legacy_signing_key" : "authority_signing_key");
signing_key = init_key_from_file(fname, 0, LOG_INFO);
if (!signing_key) {
log_warn(LD_DIR, "No version 3 directory key found in %s", fname);
goto done;
}
tor_free(fname);
fname = get_datadir_fname2("keys",
legacy ? "legacy_certificate" : "authority_certificate");
cert = read_file_to_str(fname, 0, NULL);
if (!cert) {
log_warn(LD_DIR, "Signing key found, but no certificate found in %s",
fname);
goto done;
}
parsed = authority_cert_parse_from_string(cert, &eos);
if (!parsed) {
log_warn(LD_DIR, "Unable to parse certificate in %s", fname);
goto done;
}
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;
}
crypto_pk_free(*key_out);
authority_cert_free(*cert_out);
*key_out = signing_key;
*cert_out = parsed;
r = 0;
signing_key = NULL;
parsed = NULL;
done:
tor_free(fname);
tor_free(cert);
crypto_pk_free(signing_key);
authority_cert_free(parsed);
return r;
}
/** Load the v3 (voting) authority signing key and certificate, if they are
* present. Return -1 if anything is missing, mismatched, or unloadable;
* return 0 on success. */
static int
init_v3_authority_keys(void)
{
if (load_authority_keyset(0, &authority_signing_key,
&authority_key_certificate)<0)
return -1;
if (get_options()->V3AuthUseLegacyKey &&
load_authority_keyset(1, &legacy_signing_key,
&legacy_key_certificate)<0)
return -1;
return 0;
}
/** If we're a v3 authority, check whether we have a certificate that's
* likely to expire soon. Warn if we do, but not too often. */
void
v3_authority_check_key_expiry(void)
{
time_t now, expires;
static time_t last_warned = 0;
int badness, time_left, warn_interval;
if (!authdir_mode_v3(get_options()) || !authority_key_certificate)
return;
now = time(NULL);
expires = authority_key_certificate->expires;
time_left = (int)( expires - now );
if (time_left <= 0) {
badness = LOG_ERR;
warn_interval = 60*60;
} else if (time_left <= 24*60*60) {
badness = LOG_WARN;
warn_interval = 60*60;
} else if (time_left <= 24*60*60*7) {
badness = LOG_WARN;
warn_interval = 24*60*60;
} else if (time_left <= 24*60*60*30) {
badness = LOG_WARN;
warn_interval = 24*60*60*5;
} else {
return;
}
if (last_warned + warn_interval > now)
return;
if (time_left <= 0) {
tor_log(badness, LD_DIR, "Your v3 authority certificate has expired."
" Generate a new one NOW.");
} else if (time_left <= 24*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 {
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;
}
/** Set up Tor's TLS contexts, based on our configuration and keys. Return 0
* on success, and -1 on failure. */
int
router_initialize_tls_context(void)
{
unsigned int flags = 0;
const or_options_t *options = get_options();
int lifetime = options->SSLKeyLifetime;
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;
}
if (!lifetime) { /* we should guess a good ssl cert lifetime */
/* choose between 5 and 365 days, and round to the day */
lifetime = 5*24*3600 + crypto_rand_int(361*24*3600);
lifetime -= lifetime % (24*3600);
if (crypto_rand_int(2)) {
/* Half the time we expire at midnight, and half the time we expire
* one second before midnight. (Some CAs wobble their expiry times a
* bit in practice, perhaps to reduce collision attacks; see ticket
* 8443 for details about observed certs in the wild.) */
lifetime--;
}
}
/* It's ok to pass lifetime in as an unsigned int, since
* config_parse_interval() checked it. */
return tor_tls_context_init(flags,
get_tlsclient_identity_key(),
server_mode(options) ?
get_server_identity_key() : NULL,
(unsigned int)lifetime);
}
/** 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.
*/
int
init_keys(void)
{
char *keydir;
char fingerprint[FINGERPRINT_LEN+1];
/*nicknamefp\n\0 */
char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3];
const char *mydesc;
crypto_pk_t *prkey;
char digest[DIGEST_LEN];
char v3_digest[DIGEST_LEN];
char *cp;
const or_options_t *options = get_options();
dirinfo_type_t type;
time_t now = time(NULL);
dir_server_t *ds;
int v3_digest_set = 0;
authority_cert_t *cert = NULL;
if (!key_lock)
key_lock = tor_mutex_new();
/* There are a couple of paths that put us here before we've asked
* openssl to initialize itself. */
if (crypto_global_init(get_options()->HardwareAccel,
get_options()->AccelName,
get_options()->AccelDir)) {
log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
return -1;
}
/* OP's don't need persistent keys; just make up an identity and
* initialize the TLS context. */
if (!server_mode(options)) {
if (!(prkey = crypto_pk_new()))
return -1;
if (crypto_pk_generate_key(prkey)) {
crypto_pk_free(prkey);
return -1;
}
set_client_identity_key(prkey);
/* Create a TLS context. */
if (router_initialize_tls_context() < 0) {
log_err(LD_GENERAL,"Error creating TLS context for Tor client.");
return -1;
}
return 0;
}
/* Make sure DataDirectory exists, and is private. */
if (check_private_dir(options->DataDirectory, CPD_CREATE, options->User)) {
return -1;
}
/* Check the key directory. */
keydir = get_datadir_fname("keys");
if (check_private_dir(keydir, CPD_CREATE, options->User)) {
tor_free(keydir);
return -1;
}
tor_free(keydir);
/* 1a. Read v3 directory authority key/cert information. */
memset(v3_digest, 0, sizeof(v3_digest));
if (authdir_mode_v3(options)) {
if (init_v3_authority_keys()<0) {
log_err(LD_GENERAL, "We're configured as a V3 authority, but we "
"were unable to load our v3 authority keys and certificate! "
"Use tor-gencert to generate them. Dying.");
return -1;
}
cert = get_my_v3_authority_cert();
if (cert) {
crypto_pk_get_digest(get_my_v3_authority_cert()->identity_key,
v3_digest);
v3_digest_set = 1;
}
}
/* 1b. Read identity key. Make it if none is found. */
keydir = get_datadir_fname2("keys", "secret_id_key");
log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir);
prkey = init_key_from_file(keydir, 1, LOG_ERR);
tor_free(keydir);
if (!prkey) return -1;
set_server_identity_key(prkey);
/* 1c. If we are configured as a bridge, generate a client key;
* otherwise, set the server identity key as our client identity
* key. */
if (public_server_mode(options)) {
set_client_identity_key(crypto_pk_dup_key(prkey)); /* set above */
} else {
if (!(prkey = crypto_pk_new()))
return -1;
if (crypto_pk_generate_key(prkey)) {
crypto_pk_free(prkey);
return -1;
}
set_client_identity_key(prkey);
}
/* 2. Read onion key. Make it if none is found. */
keydir = get_datadir_fname2("keys", "secret_onion_key");
log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir);
prkey = init_key_from_file(keydir, 1, LOG_ERR);
tor_free(keydir);
if (!prkey) return -1;
set_onion_key(prkey);
if (options->command == CMD_RUN_TOR) {
/* only mess with the state file if we're actually running Tor */
or_state_t *state = get_or_state();
if (state->LastRotatedOnionKey > 100 && state->LastRotatedOnionKey < now) {
/* We allow for some parsing slop, but we don't want to risk accepting
* values in the distant future. If we did, we might never rotate the
* onion key. */
onionkey_set_at = state->LastRotatedOnionKey;
} else {
/* We have no LastRotatedOnionKey set; either we just created the key
* or it's a holdover from 0.1.2.4-alpha-dev or earlier. In either case,
* start the clock ticking now so that we will eventually rotate it even
* if we don't stay up for a full MIN_ONION_KEY_LIFETIME. */
state->LastRotatedOnionKey = onionkey_set_at = now;
or_state_mark_dirty(state, options->AvoidDiskWrites ?
time(NULL)+3600 : 0);
}
}
keydir = get_datadir_fname2("keys", "secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */
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");
return -1;
}
/* 4. Build our router descriptor. */
/* Must be called after keys are initialized. */
mydesc = router_get_my_descriptor();
if (authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL)) {
const char *m = NULL;
routerinfo_t *ri;
/* We need to add our own fingerprint so it gets recognized. */
if (dirserv_add_own_fingerprint(options->Nickname,
get_server_identity_key())) {
log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
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;
}
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:"");
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:"");
}
}
}
}
/* 5. Dump fingerprint to 'fingerprint' */
keydir = get_datadir_fname("fingerprint");
log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
if (crypto_pk_get_fingerprint(get_server_identity_key(),
fingerprint, 0) < 0) {
log_err(LD_GENERAL,"Error computing fingerprint");
tor_free(keydir);
return -1;
}
tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN);
if (tor_snprintf(fingerprint_line, sizeof(fingerprint_line),
"%s %s\n",options->Nickname, fingerprint) < 0) {
log_err(LD_GENERAL,"Error writing fingerprint line");
tor_free(keydir);
return -1;
}
/* Check whether we need to write the fingerprint file. */
cp = NULL;
if (file_status(keydir) == FN_FILE)
cp = read_file_to_str(keydir, 0, NULL);
if (!cp || strcmp(cp, fingerprint_line)) {
if (write_str_to_file(keydir, fingerprint_line, 0)) {
log_err(LD_FS, "Error writing fingerprint line to file");
tor_free(keydir);
tor_free(cp);
return -1;
}
}
tor_free(cp);
tor_free(keydir);
log_notice(LD_GENERAL,
"Your Tor server's identity key fingerprint is '%s %s'",
options->Nickname, fingerprint);
if (!authdir_mode(options))
return 0;
/* 6. [authdirserver only] load approved-routers file */
if (dirserv_load_fingerprint_file() < 0) {
log_err(LD_GENERAL,"Error loading fingerprints");
return -1;
}
/* 6b. [authdirserver only] add own key to approved directories. */
crypto_pk_get_digest(get_server_identity_key(), digest);
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) {
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, 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 "
"type in DirServer list. Adjusting. (%d v %d)",
type, ds->type);
ds->type = type;
}
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.");
memcpy(ds->v3_identity_digest, v3_digest, DIGEST_LEN);
}
if (cert) { /* add my own cert to the list of known certs */
log_info(LD_DIR, "adding my own v3 cert");
if (trusted_dirs_load_certs_from_string(
cert->cache_info.signed_descriptor_body,
TRUSTED_DIRS_CERTS_SRC_SELF, 0)<0) {
log_warn(LD_DIR, "Unable to parse my own v3 cert! Failing.");
return -1;
}
}
return 0; /* success */
}
/* Keep track of whether we should upload our server descriptor,
* and what type of server we are.
*/
/** Whether we can reach our ORPort from the outside. */
static int can_reach_or_port = 0;
/** Whether we can reach our DirPort from the outside. */
static int can_reach_dir_port = 0;
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
can_reach_or_port = can_reach_dir_port = 0;
}
/** Return 1 if ORPort is known reachable; else return 0. */
int
check_whether_orport_reachable(void)
{
const or_options_t *options = get_options();
return options->AssumeReachable ||
can_reach_or_port;
}
/** Return 1 if we don't have a dirport configured, or if it's reachable. */
int
check_whether_dirport_reachable(void)
{
const or_options_t *options = get_options();
return !options->DirPort_set ||
options->AssumeReachable ||
net_is_disabled() ||
can_reach_dir_port;
}
/** Look at a variety of factors, and return 0 if we don't want to
* advertise the fact that we have a DirPort open. Else return the
* DirPort we want to advertise.
*
* Log a helpful message if we change our mind about whether to publish
* a DirPort.
*/
static int
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;
const char *reason = NULL;
/* Section one: reasons to publish or not publish that aren't
* worth mentioning to the user, either because they're obvious
* or because they're normal behavior. */
if (!dir_port) /* short circuit the rest of the function */
return 0;
if (authdir_mode(options)) /* always publish */
return dir_port;
if (net_is_disabled())
return 0;
if (!check_whether_dirport_reachable())
return 0;
if (!router_get_advertised_dir_port(options, dir_port))
return 0;
/* Section two: reasons to publish or not publish that the user
* might find surprising. These are generally config options that
* make us choose not to publish. */
if (accounting_is_enabled(options)) {
/* 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 &&
options->RelayBandwidthRate < MIN_BW_TO_ADVERTISE_DIRPORT)) {
/* if we're advertising a small amount */
new_choice = 0;
reason = "BandwidthRate under 50KB";
}
if (advertising != new_choice) {
if (new_choice == 1) {
log_notice(LD_DIR, "Advertising DirPort as %d", dir_port);
} else {
tor_assert(reason);
log_notice(LD_DIR, "Not advertising DirPort (Reason: %s)", reason);
}
advertising = new_choice;
}
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 r. Use the primary
* address of the router unless for_direct_connect 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.
*
* For ORPort, we simply try making a circuit that ends at ourselves.
* Success is noticed in onionskin_answer().
*
* For DirPort, we make a connection via Tor to our DirPort and ask
* for our own server descriptor.
* Success is noticed in connection_dir_client_reached_eof().
*/
void
consider_testing_reachability(int test_or, int test_dir)
{
const routerinfo_t *me = router_get_my_routerinfo();
int orport_reachable = check_whether_orport_reachable();
tor_addr_t addr;
const or_options_t *options = get_options();
if (!me)
return;
if (routerset_contains_router(options->ExcludeNodes, me, -1) &&
options->StrictNodes) {
/* If we've excluded ourself, and StrictNodes is set, we can't test
* ourself. */
if (test_or || test_dir) {
#define SELF_EXCLUDED_WARN_INTERVAL 3600
static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
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.");
}
return;
}
if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
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);
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);
if (test_dir && !check_whether_dirport_reachable() &&
!connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, &addr, me->dir_port,
DIR_PURPOSE_FETCH_SERVERDESC)) {
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command(me->address, &addr,
me->or_port, me->dir_port,
me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
DIRIND_ANON_DIRPORT, "authority.z", NULL, 0, 0);
}
}
/** Annotate that we found our ORPort reachable. */
void
router_orport_found_reachable(void)
{
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_DIRINFO ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty("ORPort found reachable");
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
me->address, me->or_port);
}
}
/** Annotate that we found our DirPort reachable. */
void
router_dirport_found_reachable(void)
{
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.");
can_reach_dir_port = 1;
if (decide_to_advertise_dirport(get_options(), me->dir_port))
mark_my_descriptor_dirty("DirPort found reachable");
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
me->address, me->dir_port);
}
}
/** We have enough testing circuits open. Send a bunch of "drop"
* cells down each of them, to exercise our bandwidth. */
void
router_perform_bandwidth_test(int num_circs, time_t now)
{
int num_cells = (int)(get_options()->BandwidthRate * 10 /
CELL_MAX_NETWORK_SIZE);
int max_cells = num_cells < CIRCWINDOW_START ?
num_cells : CIRCWINDOW_START;
int cells_per_circuit = max_cells / num_circs;
origin_circuit_t *circ = NULL;
log_notice(LD_OR,"Performing bandwidth self-test...done.");
while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL,
CIRCUIT_PURPOSE_TESTING))) {
/* dump cells_per_circuit drop cells onto this circ */
int i = cells_per_circuit;
if (circ->base_.state != CIRCUIT_STATE_OPEN)
continue;
circ->base_.timestamp_dirty = now;
while (i-- > 0) {
if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
RELAY_COMMAND_DROP,
NULL, 0, circ->cpath->prev)<0) {
return; /* stop if error */
}
}
}
}
/** 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(const or_options_t *options)
{
return options->AuthoritativeDir != 0;
}
/** Return true iff we believe ourselves to be a v1 authoritative
* directory server.
*/
int
authdir_mode_v1(const or_options_t *options)
{
return authdir_mode(options) && options->V1AuthoritativeDir != 0;
}
/** Return true iff we believe ourselves to be a v2 authoritative
* directory server.
*/
int
authdir_mode_v2(const or_options_t *options)
{
return authdir_mode(options) && options->V2AuthoritativeDir != 0;
}
/** Return true iff we believe ourselves to be a v3 authoritative
* directory server.
*/
int
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(const or_options_t *options)
{
return options->V1AuthoritativeDir ||
options->V2AuthoritativeDir ||
options->V3AuthoritativeDir;
}
/** Return true if we believe ourselves to be any kind of
* authoritative directory beyond just a hidserv authority. */
int
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
* purpose on its dirport. Use -1 for "any purpose". */
int
authdir_mode_handles_descs(const or_options_t *options, int purpose)
{
if (purpose < 0)
return authdir_mode_any_nonhidserv(options);
else if (purpose == ROUTER_PURPOSE_GENERAL)
return authdir_mode_any_main(options);
else if (purpose == ROUTER_PURPOSE_BRIDGE)
return (options->BridgeAuthoritativeDir);
else
return 0;
}
/** Return true iff we are an authoritative directory server that
* publishes its own network statuses.
*/
int
authdir_mode_publishes_statuses(const or_options_t *options)
{
if (authdir_mode_bridge(options))
return 0;
return authdir_mode_any_nonhidserv(options);
}
/** Return true iff we are an authoritative directory server that
* tests reachability of the descriptors it learns about.
*/
int
authdir_mode_tests_reachability(const or_options_t *options)
{
return authdir_mode_handles_descs(options, -1);
}
/** Return true iff we believe ourselves to be a bridge authoritative
* directory server.
*/
int
authdir_mode_bridge(const or_options_t *options)
{
return authdir_mode(options) && options->BridgeAuthoritativeDir != 0;
}
/** Return true iff we are trying to be a server.
*/
int
server_mode(const or_options_t *options)
{
if (options->ClientOnly) return 0;
/* XXXX024 I believe we can kill off ORListenAddress here.*/
return (options->ORPort_set || options->ORListenAddress);
}
/** Return true iff we are trying to be a non-bridge server.
*/
int
public_server_mode(const or_options_t *options)
{
if (!server_mode(options)) return 0;
return (!options->BridgeRelay);
}
/** Return true iff the combination of options in options and parameters
* 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(const or_options_t *options)
{
if (options->RefuseUnknownExits != -1) {
return options->RefuseUnknownExits;
} else {
return networkstatus_get_param(NULL, "refuseunknownexits", 1, 0, 1);
}
}
/** Remember if we've advertised ourselves to the dirservers. */
static int server_is_advertised=0;
/** Return true iff we have published our descriptor lately.
*/
int
advertised_server_mode(void)
{
return server_is_advertised;
}
/**
* Called with a boolean: set whether we have recently published our
* descriptor.
*/
static void
set_server_advertised(int s)
{
server_is_advertised = s;
}
/** Return true iff we are trying to proxy client connections. */
int
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:
* - We don't have the ClientOnly option set
* and
* - We have the PublishServerDescriptor option set to non-empty
* and
* - We have ORPort set
* and
* - We believe we are reachable from the outside; or
* - We are an authoritative directory server.
*/
static int
decide_if_publishable_server(void)
{
const or_options_t *options = get_options();
if (options->ClientOnly)
return 0;
if (options->PublishServerDescriptor_ == NO_DIRINFO)
return 0;
if (!server_mode(options))
return 0;
if (authdir_mode(options))
return 1;
if (!router_get_advertised_or_port(options))
return 0;
return check_whether_orport_reachable();
}
/** Initiate server descriptor upload as reasonable (if server is publishable,
* etc). force is as for router_upload_dir_desc_to_dirservers.
*
* We need to rebuild the descriptor if it's dirty even if we're not
* uploading, because our reachability testing *uses* our descriptor to
* determine what IP address and ports to test.
*/
void
consider_publishable_server(int force)
{
int rebuilt;
if (!server_mode(get_options()))
return;
rebuilt = router_rebuild_descriptor(0);
if (decide_if_publishable_server()) {
set_server_advertised(1);
if (rebuilt == 0)
router_upload_dir_desc_to_dirservers(force);
} else {
set_server_advertised(0);
}
}
/** Return the port of the first active listener of type
* listener_type. */
/** XXX not a very good interface. it's not reliable when there are
multiple listeners. */
uint16_t
router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family)
{
/* Iterate all connections, find one of the right kind and return
the port. Not very sophisticated or fast, but effective. */
smartlist_t *conns = get_connection_array();
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (conn->type == listener_type && !conn->marked_for_close &&
conn->socket_family == family) {
return conn->port;
}
} SMARTLIST_FOREACH_END(conn);
return 0;
}
/** 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".
*/
uint16_t
router_get_advertised_or_port(const or_options_t *options)
{
return router_get_advertised_or_port_by_af(options, AF_INET);
}
/** As router_get_advertised_or_port(), but allows an address family argument.
*/
uint16_t
router_get_advertised_or_port_by_af(const or_options_t *options,
sa_family_t family)
{
int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
family);
(void)options;
/* If the port is in 'auto' mode, we have to use
router_get_listener_port_by_type(). */
if (port == CFG_AUTO_PORT)
return router_get_active_listener_port_by_type_af(CONN_TYPE_OR_LISTENER,
family);
return port;
}
/** Return the port that we should advertise as our DirPort;
* this is one of three possibilities:
* The one that is passed as dirport if the DirPort option is 0, or
* 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(const or_options_t *options, uint16_t dirport)
{
int dirport_configured = get_primary_dir_port();
(void)options;
if (!dirport_configured)
return dirport;
if (dirport_configured == CFG_AUTO_PORT)
return router_get_active_listener_port_by_type_af(CONN_TYPE_DIR_LISTENER,
AF_INET);
return dirport_configured;
}
/*
* OR descriptor generation.
*/
/** My routerinfo. */
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;
/** OR only: If force is true, or we haven't uploaded this
* descriptor successfully yet, try to upload our signed descriptor to
* all the directory servers we know about.
*/
void
router_upload_dir_desc_to_dirservers(int force)
{
const routerinfo_t *ri;
extrainfo_t *ei;
char *msg;
size_t desc_len, extra_len = 0, total_len;
dirinfo_type_t auth = get_options()->PublishServerDescriptor_;
ri = router_get_my_routerinfo();
if (!ri) {
log_info(LD_GENERAL, "No descriptor; skipping upload");
return;
}
ei = router_get_my_extrainfo();
if (auth == NO_DIRINFO)
return;
if (!force && !desc_needs_upload)
return;
log_info(LD_OR, "Uploading relay descriptor to directory authorities%s",
force ? " (forced)" : "");
desc_needs_upload = 0;
desc_len = ri->cache_info.signed_descriptor_len;
extra_len = ei ? ei->cache_info.signed_descriptor_len : 0;
total_len = desc_len + extra_len + 1;
msg = tor_malloc(total_len);
memcpy(msg, ri->cache_info.signed_descriptor_body, desc_len);
if (ei) {
memcpy(msg+desc_len, ei->cache_info.signed_descriptor_body, extra_len);
}
msg[desc_len+extra_len] = 0;
directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_DIR,
(auth & BRIDGE_DIRINFO) ?
ROUTER_PURPOSE_BRIDGE :
ROUTER_PURPOSE_GENERAL,
auth, msg, desc_len, extra_len);
tor_free(msg);
}
/** OR only: Check whether my exit policy says to allow connection to
* conn. Return 0 if we accept; non-0 if we reject.
*/
int
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(addr))
return -1;
/* 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 true iff my exit policy is reject *:*. Return -1 if we don't
* have a descriptor */
int
router_my_exit_policy_is_reject_star(void)
{
if (!router_get_my_routerinfo()) /* make sure desc_routerinfo exists */
return -1;
return desc_routerinfo->policy_is_reject_star;
}
/** Return true iff I'm a server and digest is equal to
* my server identity key digest. */
int
router_digest_is_me(const char *digest)
{
return (server_identitykey &&
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 digest is equal to
* my identity digest. */
int
router_extrainfo_digest_is_me(const char *digest)
{
extrainfo_t *ei = router_get_my_extrainfo();
if (!ei)
return 0;
return tor_memeq(digest,
ei->cache_info.signed_descriptor_digest,
DIGEST_LEN);
}
/** A wrapper around router_digest_is_me(). */
int
router_is_me(const routerinfo_t *router)
{
return router_digest_is_me(router->cache_info.identity_digest);
}
/** Return true iff fp is a hex fingerprint of my identity digest. */
int
router_fingerprint_is_me(const char *fp)
{
char digest[DIGEST_LEN];
if (strlen(fp) == HEX_DIGEST_LEN &&
base16_decode(digest, sizeof(digest), fp, HEX_DIGEST_LEN) == 0)
return router_digest_is_me(digest);
return 0;
}
/** Return a routerinfo for this OR, rebuilding a fresh one if
* necessary. Return NULL on error, or if called on an OP. */
const routerinfo_t *
router_get_my_routerinfo(void)
{
if (!server_mode(get_options()))
return NULL;
if (router_rebuild_descriptor(0))
return NULL;
return desc_routerinfo;
}
/** OR only: Return a signed server descriptor for this OR, rebuilding a fresh
* one if necessary. Return NULL on error.
*/
const char *
router_get_my_descriptor(void)
{
const char *body;
if (!router_get_my_routerinfo())
return NULL;
/* Make sure this is nul-terminated. */
tor_assert(desc_routerinfo->cache_info.saved_location == SAVED_NOWHERE);
body = signed_descriptor_get_body(&desc_routerinfo->cache_info);
tor_assert(!body[desc_routerinfo->cache_info.signed_descriptor_len]);
log_debug(LD_GENERAL,"my desc is '%s'", body);
return body;
}
/** Return the extrainfo document for this OR, or NULL if we have none.
* Rebuilt it (and the server descriptor) if necessary. */
extrainfo_t *
router_get_my_extrainfo(void)
{
if (!server_mode(get_options()))
return NULL;
if (router_rebuild_descriptor(0))
return NULL;
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;
static int router_guess_address_from_dir_headers(uint32_t *guess);
/** Make a current best guess at our address, either because
* it's configured in torrc, or because we've learned it from
* dirserver headers. Place the answer in *addr and return
* 0 on success, else return -1 if we have no guess. */
int
router_pick_published_address(const or_options_t *options, uint32_t *addr)
{
*addr = get_last_resolved_addr();
if (!*addr &&
resolve_my_address(LOG_INFO, options, addr, NULL, NULL) < 0) {
log_info(LD_CONFIG, "Could not determine our address locally. "
"Checking if directory headers provide any hints.");
if (router_guess_address_from_dir_headers(addr) < 0) {
log_info(LD_CONFIG, "No hints from directory headers either. "
"Will try again later.");
return -1;
}
}
log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
return 0;
}
/** If force is true, or our descriptor is out-of-date, rebuild a fresh
* routerinfo, signed server descriptor, and extra-info document for this OR.
* Return 0 on success, -1 on temporary error.
*/
int
router_rebuild_descriptor(int force)
{
routerinfo_t *ri;
extrainfo_t *ei;
uint32_t addr;
char platform[256];
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
if (desc_clean_since && !force)
return 0;
if (router_pick_published_address(options, &addr) < 0 ||
router_get_advertised_or_port(options) == 0) {
/* Stop trying to rebuild our descriptor every second. We'll
* learn that it's time to try again when ip_address_changed()
* marks it dirty. */
desc_clean_since = time(NULL);
return -1;
}
log_info(LD_OR, "Rebuilding relay descriptor%s", force ? " (forced)" : "");
ri = tor_malloc_zero(sizeof(routerinfo_t));
ri->cache_info.routerlist_index = -1;
ri->address = tor_dup_ip(addr);
ri->nickname = tor_strdup(options->Nickname);
ri->addr = addr;
ri->or_port = router_get_advertised_or_port(options);
ri->dir_port = router_get_advertised_dir_port(options, 0);
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
#ifdef CURVE25519_ENABLED
ri->onion_curve25519_pkey =
tor_memdup(&get_current_curve25519_keypair()->pubkey,
sizeof(curve25519_public_key_t));
#endif
/* For now, at most one IPv6 or-address is being advertised. */
{
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
! p->no_advertise &&
! p->bind_ipv4_only &&
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) {
routerinfo_free(ri);
return -1;
}
get_platform_str(platform, sizeof(platform));
ri->platform = tor_strdup(platform);
/* compute ri->bandwidthrate as the min of various options */
ri->bandwidthrate = get_effective_bwrate(options);
/* and compute ri->bandwidthburst similarly */
ri->bandwidthburst = get_effective_bwburst(options);
ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
if (dns_seems_to_be_broken() || has_dns_init_failed()) {
/* DNS is screwed up; don't claim to be an exit. */
policies_exit_policy_append_reject_star(&ri->exit_policy);
} else {
policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
options->IPv6Exit,
options->ExitPolicyRejectPrivate,
ri->address, !options->BridgeRelay);
}
ri->policy_is_reject_star =
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 */
if (authdir_mode(options))
ri->is_valid = ri->is_named = 1; /* believe in yourself */
#endif
if (options->MyFamily && ! options->BridgeRelay) {
smartlist_t *family;
if (!warned_nonexistent_family)
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_BEGIN(family, char *, name) {
const node_t *member;
if (!strcasecmp(name, options->Nickname))
goto skip; /* Don't list ourself, that's redundant */
else
member = node_get_by_nickname(name, 1);
if (!member) {
int is_legal = is_legal_nickname_or_hexdigest(name);
if (!smartlist_contains_string(warned_nonexistent_family, name) &&
!is_legal_hexdigest(name)) {
if (is_legal)
log_warn(LD_CONFIG,
"I have no descriptor for the router named \"%s\" in my "
"declared family; I'll use the nickname as is, but "
"this may confuse clients.", name);
else
log_warn(LD_CONFIG, "There is a router named \"%s\" in my "
"declared family, but that isn't a legal nickname. "
"Skipping it.", escaped(name));
smartlist_add(warned_nonexistent_family, tor_strdup(name));
}
if (is_legal) {
smartlist_add(ri->declared_family, name);
name = NULL;
}
} 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->identity, DIGEST_LEN);
smartlist_add(ri->declared_family, fp);
if (smartlist_contains_string(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);
smartlist_uniq_strings(ri->declared_family);
smartlist_free(family);
}
/* Now generate the extrainfo. */
ei = tor_malloc_zero(sizeof(extrainfo_t));
ei->cache_info.is_extrainfo = 1;
strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
ei->cache_info.published_on = ri->cache_info.published_on;
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
DIGEST_LEN);
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
ei, get_server_identity_key()) < 0) {
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
extrainfo_free(ei);
ei = NULL;
} else {
ei->cache_info.signed_descriptor_len =
strlen(ei->cache_info.signed_descriptor_body);
router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
ei->cache_info.signed_descriptor_len,
ei->cache_info.signed_descriptor_digest);
}
/* Now finish the router descriptor. */
if (ei) {
memcpy(ri->cache_info.extra_info_digest,
ei->cache_info.signed_descriptor_digest,
DIGEST_LEN);
} else {
/* ri was allocated with tor_malloc_zero, so there is no need to
* zero ri->cache_info.extra_info_digest here. */
}
if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(
ri, get_server_identity_key()))) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
routerinfo_free(ri);
extrainfo_free(ei);
return -1;
}
ri->cache_info.signed_descriptor_len =
strlen(ri->cache_info.signed_descriptor_body);
ri->purpose =
options->BridgeRelay ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
if (options->BridgeRelay) {
/* Bridges shouldn't be able to send their descriptors unencrypted,
anyway, since they don't have a DirPort, and always connect to the
bridge authority anonymously. But just in case they somehow think of
sending them on an unencrypted connection, don't allow them to try. */
ri->cache_info.send_unencrypted = 0;
if (ei)
ei->cache_info.send_unencrypted = 0;
} else {
ri->cache_info.send_unencrypted = 1;
if (ei)
ei->cache_info.send_unencrypted = 1;
}
router_get_router_hash(ri->cache_info.signed_descriptor_body,
strlen(ri->cache_info.signed_descriptor_body),
ri->cache_info.signed_descriptor_digest);
if (ei) {
tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL));
}
routerinfo_free(desc_routerinfo);
desc_routerinfo = ri;
extrainfo_free(desc_extrainfo);
desc_extrainfo = ei;
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;
}
/** 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_too_old(time_t now)
{
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;
if (!desc_dirty_reason)
desc_dirty_reason = reason;
}
/** How frequently will we republish our descriptor because of large (factor
* of 2) shifts in estimated bandwidth? */
#define MAX_BANDWIDTH_CHANGE_FREQ (20*60)
/** Check whether bandwidth has changed a lot since the last time we announced
* bandwidth. If so, mark our descriptor dirty. */
void
check_descriptor_bandwidth_changed(time_t now)
{
static time_t last_changed = 0;
uint64_t prev, cur;
if (!desc_routerinfo)
return;
prev = desc_routerinfo->bandwidthcapacity;
cur = we_are_hibernating() ? 0 : rep_hist_bandwidth_assess();
if ((prev != cur && (!prev || !cur)) ||
cur > prev*2 ||
cur < prev/2) {
if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now) {
log_info(LD_GENERAL,
"Measured bandwidth has changed; rebuilding descriptor.");
mark_my_descriptor_dirty("bandwidth has changed");
last_changed = now;
}
}
}
/** Note at log level severity that our best guess of address has changed from
* prev to cur. */
static void
log_addr_has_changed(int severity,
const tor_addr_t *prev,
const tor_addr_t *cur,
const char *source)
{
char addrbuf_prev[TOR_ADDR_BUF_LEN];
char addrbuf_cur[TOR_ADDR_BUF_LEN];
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 (!tor_addr_is_null(prev))
log_fn(severity, LD_GENERAL,
"Our IP Address has changed from %s to %s; "
"rebuilding descriptor (source: %s).",
addrbuf_prev, addrbuf_cur, source);
else
log_notice(LD_GENERAL,
"Guessed our IP address as %s (source: %s).",
addrbuf_cur, source);
}
/** Check whether our own address as defined by the Address configuration
* has changed. This is for routers that get their address from a service
* like dyndns. If our address has changed, mark our descriptor dirty. */
void
check_descriptor_ipaddress_changed(time_t now)
{
uint32_t prev, cur;
const or_options_t *options = get_options();
const char *method = NULL;
char *hostname = NULL;
(void) now;
if (!desc_routerinfo)
return;
/* XXXX ipv6 */
prev = desc_routerinfo->addr;
if (resolve_my_address(LOG_INFO, options, &cur, &method, &hostname) < 0) {
log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
return;
}
if (prev != cur) {
char *source;
tor_addr_t tmp_prev, tmp_cur;
tor_addr_from_ipv4h(&tmp_prev, prev);
tor_addr_from_ipv4h(&tmp_cur, cur);
tor_asprintf(&source, "METHOD=%s%s%s", method,
hostname ? " HOSTNAME=" : "",
hostname ? hostname : "");
log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, source);
tor_free(source);
ip_address_changed(0);
}
tor_free(hostname);
}
/** The most recently guessed value of our IP address, based on directory
* headers. */
static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
/** A directory server d_conn told us our IP address is
* suggestion.
* If this address is different from the one we think we are now, and
* if our computer doesn't actually know its IP address, then switch. */
void
router_new_address_suggestion(const char *suggestion,
const dir_connection_t *d_conn)
{
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_addr_parse(&addr, suggestion) == -1) {
log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
escaped(suggestion));
return;
}
log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
if (!server_mode(options)) {
tor_addr_copy(&last_guessed_ip, &addr);
return;
}
/* XXXX ipv6 */
cur = get_last_resolved_addr();
if (cur ||
resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
/* We're all set -- we already know our address. Great. */
tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
need it later */
return;
}
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(&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.",
suggestion);
return;
}
/* 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 (!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,
d_conn->base_.address);
ip_address_changed(0);
tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
will fetch it */
}
}
/** We failed to resolve our address locally, but we'd like to build
* a descriptor and publish / test reachability. If we have a guess
* about our address based on directory headers, answer it and return
* 0; else return -1. */
static int
router_guess_address_from_dir_headers(uint32_t *guess)
{
if (!tor_addr_is_null(&last_guessed_ip)) {
*guess = tor_addr_to_ipv4h(&last_guessed_ip);
return 0;
}
return -1;
}
/** Set platform (max length len) to a NUL-terminated short
* string describing the version of Tor and the operating system we're
* currently running on.
*/
STATIC void
get_platform_str(char *platform, size_t len)
{
tor_snprintf(platform, len, "Tor %s on %s",
get_short_version(), get_uname());
}
/* XXX need to audit this thing and count fenceposts. maybe
* refactor so we don't have to keep asking if we're
* near the end of maxlen?
*/
#define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
/** OR only: Given a routerinfo for this router, and an identity key to sign
* with, encode the routerinfo as a signed server descriptor and return a new
* string encoding the result, or NULL on failure.
*/
char *
router_dump_router_to_string(routerinfo_t *router,
crypto_pk_t *ident_key)
{
/* XXXX025 Make this look entirely at its arguments, and not at globals.
*/
char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
char *identity_pkey = NULL; /* Identity key, PEM-encoded. */
char digest[DIGEST_LEN];
char published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1];
int has_extra_info_digest;
char extra_info_digest[HEX_DIGEST_LEN+1];
size_t onion_pkeylen, identity_pkeylen;
char *family_line = NULL;
char *extra_or_address = NULL;
const or_options_t *options = get_options();
smartlist_t *chunks = NULL;
char *output = NULL;
/* Make sure the identity key matches the one in the routerinfo. */
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!");
goto err;
}
/* record our fingerprint, so we can include it in the descriptor */
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
log_err(LD_BUG,"Error computing fingerprint");
goto err;
}
/* PEM-encode the onion key */
if (crypto_pk_write_public_key_to_string(router->onion_pkey,
&onion_pkey,&onion_pkeylen)<0) {
log_warn(LD_BUG,"write onion_pkey to string failed!");
goto err;
}
/* PEM-encode the identity key */
if (crypto_pk_write_public_key_to_string(router->identity_pkey,
&identity_pkey,&identity_pkeylen)<0) {
log_warn(LD_BUG,"write identity_pkey to string failed!");
goto err;
}
/* Encode the publication time. */
format_iso_time(published, router->cache_info.published_on);
if (router->declared_family && smartlist_len(router->declared_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("");
}
has_extra_info_digest =
! tor_digest_is_zero(router->cache_info.extra_info_digest);
if (has_extra_info_digest) {
base16_encode(extra_info_digest, sizeof(extra_info_digest),
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);
}
}
chunks = smartlist_new();
/* Generate the easy portion of the router descriptor. */
smartlist_add_asprintf(chunks,
"router %s %s %d 0 %d\n"
"%s"
"platform %s\n"
"protocols Link 1 2 Circuit 1\n"
"published %s\n"
"fingerprint %s\n"
"uptime %ld\n"
"bandwidth %d %d %d\n"
"%s%s%s%s"
"onion-key\n%s"
"signing-key\n%s"
"%s%s%s%s",
router->nickname,
router->address,
router->or_port,
decide_to_advertise_dirport(options, router->dir_port),
extra_or_address ? extra_or_address : "",
router->platform,
published,
fingerprint,
stats_n_seconds_working,
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
has_extra_info_digest ? "extra-info-digest " : "",
has_extra_info_digest ? extra_info_digest : "",
has_extra_info_digest ? "\n" : "",
options->DownloadExtraInfo ? "caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
we_are_hibernating() ? "hibernating 1\n" : "",
options->HidServDirectoryV2 ? "hidden-service-dir\n" : "",
options->AllowSingleHopExits ? "allow-single-hop-exits\n" : "");
if (options->ContactInfo && strlen(options->ContactInfo)) {
const char *ci = options->ContactInfo;
if (strchr(ci, '\n') || strchr(ci, '\r'))
ci = escaped(ci);
smartlist_add_asprintf(chunks, "contact %s\n", ci);
}
#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);
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
}
#endif
/* Write the exit policy to the end of 's'. */
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
smartlist_add(chunks, tor_strdup("reject *:*\n"));
} else if (router->exit_policy) {
int i;
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
char pbuf[POLICY_BUF_LEN];
addr_policy_t *tmpe = smartlist_get(router->exit_policy, i);
int result;
if (tor_addr_family(&tmpe->addr) == AF_INET6)
continue; /* Don't include IPv6 parts of address policy */
result = policy_write_item(pbuf, POLICY_BUF_LEN, tmpe, 1);
if (result < 0) {
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
goto err;
}
smartlist_add_asprintf(chunks, "%s\n", pbuf);
}
}
if (router->ipv6_exit_policy) {
char *p6 = write_short_policy(router->ipv6_exit_policy);
if (p6 && strcmp(p6, "reject 1-65535")) {
smartlist_add_asprintf(chunks,
"ipv6-policy %s\n", p6);
}
tor_free(p6);
}
/* Sign the descriptor */
smartlist_add(chunks, tor_strdup("router-signature\n"));
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
note_crypto_pk_op(SIGN_RTR);
{
char *sig;
if (!(sig = router_get_dirobj_signature(digest, DIGEST_LEN, ident_key))) {
log_warn(LD_BUG, "Couldn't sign router descriptor");
goto err;
}
smartlist_add(chunks, sig);
}
/* include a last '\n' */
smartlist_add(chunks, tor_strdup("\n"));
output = smartlist_join_strings(chunks, "", 0, NULL);
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
{
char *s_dup;
const char *cp;
routerinfo_t *ri_tmp;
cp = s_dup = tor_strdup(output);
ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL);
if (!ri_tmp) {
log_err(LD_BUG,
"We just generated a router descriptor we can't parse.");
log_err(LD_BUG, "Descriptor was: <<%s>>", output);
goto err;
}
tor_free(s_dup);
routerinfo_free(ri_tmp);
}
#endif
goto done;
err:
tor_free(output); /* sets output to NULL */
done:
if (chunks) {
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
smartlist_free(chunks);
}
tor_free(family_line);
tor_free(onion_pkey);
tor_free(identity_pkey);
tor_free(extra_or_address);
return output;
}
/** Copy the primary (IPv4) OR port (IP address and TCP port) for
* router into *ap_out. */
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 any of router's addresses are addr.
* Otherwise return 0. */
int
router_has_addr(const routerinfo_t *router, const tor_addr_t *addr)
{
return
tor_addr_eq_ipv4h(addr, router->addr) ||
tor_addr_eq(&router->ipv6_addr, addr);
}
int
router_has_orport(const routerinfo_t *router, const tor_addr_port_t *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 filename, find the last line starting with
* end_line, ensure that its timestamp is not more than 25 hours in
* the past or more than 1 hour in the future with respect to now,
* and write the file contents starting with that line to *out.
* Return 1 for success, 0 if the file does not exist, or -1 if the file
* does not contain a line matching these criteria or other failure. */
static int
load_stats_file(const char *filename, const char *end_line, time_t now,
char **out)
{
int r = -1;
char *fname = get_datadir_fname(filename);
char *contents, *start = NULL, *tmp, timestr[ISO_TIME_LEN+1];
time_t written;
switch (file_status(fname)) {
case FN_FILE:
/* X022 Find an alternative to reading the whole file to memory. */
if ((contents = read_file_to_str(fname, 0, NULL))) {
tmp = strstr(contents, end_line);
/* Find last block starting with end_line */
while (tmp) {
start = tmp;
tmp = strstr(tmp + 1, end_line);
}
if (!start)
goto notfound;
if (strlen(start) < strlen(end_line) + 1 + sizeof(timestr))
goto notfound;
strlcpy(timestr, start + 1 + strlen(end_line), sizeof(timestr));
if (parse_iso_time(timestr, &written) < 0)
goto notfound;
if (written < now - (25*60*60) || written > now + (1*60*60))
goto notfound;
*out = tor_strdup(start);
r = 1;
}
notfound:
tor_free(contents);
break;
case FN_NOENT:
r = 0;
break;
case FN_ERROR:
case FN_DIR:
default:
break;
}
tor_free(fname);
return r;
}
/** Write the contents of extrainfo and aggregated statistics to
* *s_out, signing them with ident_key. Return 0 on
* success, negative on failure. */
int
extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
crypto_pk_t *ident_key)
{
const or_options_t *options = get_options();
char identity[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
char digest[DIGEST_LEN];
char *bandwidth_usage;
int result;
static int write_stats_to_extrainfo = 1;
char sig[DIROBJ_MAX_SIG_LEN+1];
char *s, *pre, *contents, *cp, *s_dup = NULL;
time_t now = time(NULL);
smartlist_t *chunks = smartlist_new();
extrainfo_t *ei_tmp = NULL;
base16_encode(identity, sizeof(identity),
extrainfo->cache_info.identity_digest, DIGEST_LEN);
format_iso_time(published, extrainfo->cache_info.published_on);
bandwidth_usage = rep_hist_get_bandwidth_lines();
tor_asprintf(&pre, "extra-info %s %s\npublished %s\n%s",
extrainfo->nickname, identity,
published, bandwidth_usage);
tor_free(bandwidth_usage);
smartlist_add(chunks, pre);
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.");
if (options->DirReqStatistics &&
load_stats_file("stats"PATH_SEPARATOR"dirreq-stats",
"dirreq-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
if (options->EntryStatistics &&
load_stats_file("stats"PATH_SEPARATOR"entry-stats",
"entry-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
if (options->CellStatistics &&
load_stats_file("stats"PATH_SEPARATOR"buffer-stats",
"cell-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
if (options->ExitPortStatistics &&
load_stats_file("stats"PATH_SEPARATOR"exit-stats",
"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);
}
}
/* 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) {
smartlist_add(chunks, tor_strdup(bridge_stats));
}
}
smartlist_add(chunks, tor_strdup("router-signature\n"));
s = smartlist_join_strings(chunks, "", 0, NULL);
while (strlen(s) > MAX_EXTRAINFO_UPLOAD_SIZE - DIROBJ_MAX_SIG_LEN) {
/* So long as there are at least two chunks (one for the initial
* extra-info line and one for the router-signature), we can keep removing
* things. */
if (smartlist_len(chunks) > 2) {
/* We remove the next-to-last element (remember, len-1 is the last
element), since we need to keep the router-signature element. */
int idx = smartlist_len(chunks) - 2;
char *e = smartlist_get(chunks, idx);
smartlist_del_keeporder(chunks, idx);
log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
"with statistics that exceeds the 50 KB "
"upload limit. Removing last added "
"statistics.");
tor_free(e);
tor_free(s);
s = smartlist_join_strings(chunks, "", 0, NULL);
} else {
log_warn(LD_BUG, "We just generated an extra-info descriptors that "
"exceeds the 50 KB upload limit.");
goto err;
}
}
memset(sig, 0, sizeof(sig));
if (router_get_extrainfo_hash(s, strlen(s), digest) < 0 ||
router_append_dirobj_signature(sig, sizeof(sig), digest, DIGEST_LEN,
ident_key) < 0) {
log_warn(LD_BUG, "Could not append signature to extra-info "
"descriptor.");
goto err;
}
smartlist_add(chunks, tor_strdup(sig));
tor_free(s);
s = smartlist_join_strings(chunks, "", 0, NULL);
cp = s_dup = tor_strdup(s);
ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL);
if (!ei_tmp) {
if (write_stats_to_extrainfo) {
log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
"with statistics that we can't parse. Not "
"adding statistics to this or any future "
"extra-info descriptors.");
write_stats_to_extrainfo = 0;
result = extrainfo_dump_to_string(s_out, extrainfo, ident_key);
goto done;
} else {
log_warn(LD_BUG, "We just generated an extrainfo descriptor we "
"can't parse.");
goto err;
}
}
*s_out = s;
s = NULL; /* prevent free */
result = 0;
goto done;
err:
result = -1;
done:
tor_free(s);
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
smartlist_free(chunks);
tor_free(s_dup);
extrainfo_free(ei_tmp);
return result;
}
/** Return true iff s is a valid server nickname. (That is, a string
* containing between 1 and MAX_NICKNAME_LEN characters from
* LEGAL_NICKNAME_CHARACTERS.) */
int
is_legal_nickname(const char *s)
{
size_t len;
tor_assert(s);
len = strlen(s);
return len > 0 && len <= MAX_NICKNAME_LEN &&
strspn(s,LEGAL_NICKNAME_CHARACTERS) == len;
}
/** Return true iff s is a valid server nickname or
* hex-encoded identity-key digest. */
int
is_legal_nickname_or_hexdigest(const char *s)
{
if (*s!='$')
return is_legal_nickname(s);
else
return is_legal_hexdigest(s);
}
/** Return true iff s is a valid hex-encoded identity-key
* digest. (That is, an optional $, followed by 40 hex characters,
* followed by either nothing, or = or ~ followed by a nickname, or
* a character other than =, ~, or a hex character.)
*/
int
is_legal_hexdigest(const char *s)
{
size_t len;
tor_assert(s);
if (s[0] == '$') s++;
len = strlen(s);
if (len > HEX_DIGEST_LEN) {
if (s[HEX_DIGEST_LEN] == '=' ||
s[HEX_DIGEST_LEN] == '~') {
if (!is_legal_nickname(s+HEX_DIGEST_LEN+1))
return 0;
} else {
return 0;
}
}
return (len >= HEX_DIGEST_LEN &&
strspn(s,HEX_CHARACTERS)==HEX_DIGEST_LEN);
}
/** Use buf (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of a node with identity digest
* id_digest, named-status is_named, nickname nickname,
* and address addr or addr32h.
*
* The nickname and addr fields are optional and may be set to
* NULL. The addr32h field is optional and may be set to 0.
*
* Return a pointer to the front of buf.
*/
const char *
format_node_description(char *buf,
const char *id_digest,
int is_named,
const char *nickname,
const tor_addr_t *addr,
uint32_t addr32h)
{
char *cp;
if (!buf)
return "";
buf[0] = '$';
base16_encode(buf+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN);
cp = buf+1+HEX_DIGEST_LEN;
if (nickname) {
buf[1+HEX_DIGEST_LEN] = is_named ? '=' : '~';
strlcpy(buf+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1);
cp += strlen(cp);
}
if (addr32h || addr) {
memcpy(cp, " at ", 4);
cp += 4;
if (addr) {
tor_addr_to_str(cp, addr, TOR_ADDR_BUF_LEN, 0);
} else {
struct in_addr in;
in.s_addr = htonl(addr32h);
tor_inet_ntoa(&in, cp, INET_NTOA_BUF_LEN);
}
}
return buf;
}
/** Use buf (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of ri.
*
*
* Return a pointer to the front of buf.
*/
const char *
router_get_description(char *buf, const routerinfo_t *ri)
{
if (!ri)
return "";
return format_node_description(buf,
ri->cache_info.identity_digest,
router_is_named(ri),
ri->nickname,
NULL,
ri->addr);
}
/** Use buf (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of node.
*
* Return a pointer to the front of buf.
*/
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 "";
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 buf (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of rs.
*
* Return a pointer to the front of buf.
*/
const char *
routerstatus_get_description(char *buf, const routerstatus_t *rs)
{
if (!rs)
return "";
return format_node_description(buf,
rs->identity_digest,
rs->is_named,
rs->nickname,
NULL,
rs->addr);
}
/** Use buf (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of ei.
*
* Return a pointer to the front of buf.
*/
const char *
extend_info_get_description(char *buf, const extend_info_t *ei)
{
if (!ei)
return "";
return format_node_description(buf,
ei->identity_digest,
0,
ei->nickname,
&ei->addr,
0);
}
/** Return a human-readable description of the routerinfo_t ri.
*
* This function is not thread-safe. Each call to this function invalidates
* previous values returned by this function.
*/
const char *
router_describe(const routerinfo_t *ri)
{
static char buf[NODE_DESC_BUF_LEN];
return router_get_description(buf, ri);
}
/** Return a human-readable description of the node_t node.
*
* 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 rs.
*
* This function is not thread-safe. Each call to this function invalidates
* previous values returned by this function.
*/
const char *
routerstatus_describe(const routerstatus_t *rs)
{
static char buf[NODE_DESC_BUF_LEN];
return routerstatus_get_description(buf, rs);
}
/** Return a human-readable description of the extend_info_t ri.
*
* This function is not thread-safe. Each call to this function invalidates
* previous values returned by this function.
*/
const char *
extend_info_describe(const extend_info_t *ei)
{
static char buf[NODE_DESC_BUF_LEN];
return extend_info_get_description(buf, ei);
}
/** Set buf (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
* verbose representation of the identity of router. The format is:
* A dollar sign.
* The upper-case hexadecimal encoding of the SHA1 hash of router's identity.
* A "=" if the router is named; a "~" if it is not.
* The router's nickname.
**/
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] = is_named ? '=' : '~';
strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1);
}
/** Forget that we have issued any router-related warnings, so that we'll
* warn again if we see the same errors. */
void
router_reset_warnings(void)
{
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
smartlist_clear(warned_nonexistent_family);
}
}
/** Given a router purpose, convert it to a string. Don't call this on
* ROUTER_PURPOSE_UNKNOWN: The whole point of that value is that we don't
* know its string representation. */
const char *
router_purpose_to_string(uint8_t p)
{
switch (p)
{
case ROUTER_PURPOSE_GENERAL: return "general";
case ROUTER_PURPOSE_BRIDGE: return "bridge";
case ROUTER_PURPOSE_CONTROLLER: return "controller";
default:
tor_assert(0);
}
return NULL;
}
/** Given a string, convert it to a router purpose. */
uint8_t
router_purpose_from_string(const char *s)
{
if (!strcmp(s, "general"))
return ROUTER_PURPOSE_GENERAL;
else if (!strcmp(s, "bridge"))
return ROUTER_PURPOSE_BRIDGE;
else if (!strcmp(s, "controller"))
return ROUTER_PURPOSE_CONTROLLER;
else
return ROUTER_PURPOSE_UNKNOWN;
}
/** Release all static resources held in router.c */
void
router_free_all(void)
{
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_pk_free(authority_signing_key);
authority_cert_free(authority_key_certificate);
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
ri. 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;
}