📄 router.c
字号:
/* OP's don't need persistent keys; just make up an identity and
* initialize the TLS context. */
if (!server_mode(options)) {
if (!(prkey = crypto_new_pk_env()))
return -1;
if (crypto_pk_generate_key(prkey)) {
crypto_free_pk_env(prkey);
return -1;
}
set_identity_key(prkey);
/* Create a TLS context; default the client nickname to "client". */
if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 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)) {
return -1;
}
/* Check the key directory. */
keydir = get_datadir_fname("keys");
if (check_private_dir(keydir, CPD_CREATE)) {
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;
}
}
/* 1. 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_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);
if (prkey)
lastonionkey = prkey;
}
tor_free(keydir);
/* 3. Initialize link key and TLS context. */
if (tor_tls_context_new(get_identity_key(), MAX_SSL_KEY_LIFETIME) < 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(options)) {
const char *m;
routerinfo_t *ri;
/* We need to add our own fingerprint so it gets recognized. */
if (dirserv_add_own_fingerprint(options->Nickname, get_identity_key())) {
log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
return -1;
}
if (mydesc) {
ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL);
if (!ri) {
log_err(LD_GENERAL,"Generated a routerinfo we couldn't parse.");
return -1;
}
if (dirserv_add_descriptor(ri, &m) < 0) {
log_err(LD_GENERAL,"Unable to add own descriptor to directory: %s",
m?m:"<unknown error>");
return -1;
}
}
}
/* 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_identity_key(), fingerprint, 1)<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);
return -1;
}
}
tor_free(cp);
tor_free(keydir);
log(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_identity_key(), digest);
type = ((options->V1AuthoritativeDir ? V1_AUTHORITY : NO_AUTHORITY) |
(options->V2AuthoritativeDir ? V2_AUTHORITY : NO_AUTHORITY) |
(options->V3AuthoritativeDir ? V3_AUTHORITY : NO_AUTHORITY) |
(options->BridgeAuthoritativeDir ? BRIDGE_AUTHORITY : NO_AUTHORITY) |
(options->HSAuthoritativeDir ? HIDSERV_AUTHORITY : NO_AUTHORITY));
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
ds = add_trusted_dir_server(options->Nickname, NULL,
(uint16_t)options->DirPort,
(uint16_t)options->ORPort,
digest,
v3_digest,
type);
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;
}
}
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_AUTHORITY) &&
memcmp(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, 0, 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)
{
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)
{
or_options_t *options = get_options();
return !options->DirPort ||
options->AssumeReachable ||
we_are_hibernating() ||
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(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 (we_are_hibernating())
return 0;
if (!check_whether_dirport_reachable())
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)) {
/* if we might potentially hibernate */
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(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);
}
advertising = new_choice;
}
return advertising ? dir_port : 0;
}
/** 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)
{
routerinfo_t *me = router_get_my_routerinfo();
int orport_reachable = check_whether_orport_reachable();
if (!me)
return;
if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
!orport_reachable ? "reachability" : "bandwidth",
me->address, me->or_port);
circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me,
CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
control_event_server_status(LOG_NOTICE,
"CHECKING_REACHABILITY ORADDRESS=%s:%d",
me->address, me->or_port);
}
if (test_dir && !check_whether_dirport_reachable() &&
!connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, me->addr, me->dir_port,
DIR_PURPOSE_FETCH_SERVERDESC)) {
/* ask myself, via tor, for my server descriptor. */
directory_initiate_command(me->address, me->addr,
me->or_port, me->dir_port,
0, /* does not matter */
0, me->cache_info.identity_digest,
DIR_PURPOSE_FETCH_SERVERDESC,
ROUTER_PURPOSE_GENERAL,
1, "authority.z", NULL, 0, 0);
control_event_server_status(LOG_NOTICE,
"CHECKING_REACHABILITY DIRADDRESS=%s:%d",
me->address, me->dir_port);
}
}
/** Annotate that we found our ORPort reachable. */
void
router_orport_found_reachable(void)
{
if (!can_reach_or_port) {
routerinfo_t *me = router_get_my_routerinfo();
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
get_options()->_PublishServerDescriptor != NO_AUTHORITY ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty();
if (!me)
return;
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)
{
if (!can_reach_dir_port) {
routerinfo_t *me = router_get_my_routerinfo();
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.");
can_reach_dir_port = 1;
if (!me || decide_to_advertise_dirport(get_options(), me->dir_port))
mark_my_descriptor_dirty();
if (!me)
return;
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_NETWORK_SIZE);
int max_cells = num_cells < CIRCWINDOW_START ?
num_cells : CIRCWINDOW_START;
int cells_per_circuit = max_cells / num_circs;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -