📄 router.c
字号:
router_pick_published_address(or_options_t *options, uint32_t *addr)
{
if (resolve_my_address(LOG_INFO, options, addr, NULL) < 0) {
log_info(LD_CONFIG, "Could not determine our address locally. "
"Checking if directory headers provide any hints.");
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;
}
}
return 0;
}
/** If <b>force</b> 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();
or_options_t *options = get_options();
if (desc_clean_since && !force)
return 0;
if (router_pick_published_address(options, &addr) < 0) {
/* Stop trying to rebuild our descriptor every second. We'll
* learn that it's time to try again when server_has_changed_ip()
* marks it dirty. */
desc_clean_since = time(NULL);
return -1;
}
ri = tor_malloc_zero(sizeof(routerinfo_t));
ri->cache_info.routerlist_index = -1;
ri->address = tor_dup_addr(addr);
ri->nickname = tor_strdup(options->Nickname);
ri->addr = addr;
ri->or_port = options->ORPort;
ri->dir_port = options->DirPort;
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
ri->identity_pkey = crypto_pk_dup_key(get_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 = (int)options->BandwidthRate;
if (ri->bandwidthrate > options->MaxAdvertisedBandwidth)
ri->bandwidthrate = (int)options->MaxAdvertisedBandwidth;
if (options->RelayBandwidthRate > 0 &&
ri->bandwidthrate > options->RelayBandwidthRate)
ri->bandwidthrate = (int)options->RelayBandwidthRate;
/* and compute ri->bandwidthburst similarly */
ri->bandwidthburst = (int)options->BandwidthBurst;
if (options->RelayBandwidthBurst > 0 &&
ri->bandwidthburst > options->RelayBandwidthBurst)
ri->bandwidthburst = (int)options->RelayBandwidthBurst;
ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
options->ExitPolicyRejectPrivate,
ri->address);
if (desc_routerinfo) { /* inherit values */
ri->is_valid = desc_routerinfo->is_valid;
ri->is_running = desc_routerinfo->is_running;
ri->is_named = desc_routerinfo->is_named;
}
if (authdir_mode(options))
ri->is_valid = ri->is_named = 1; /* believe in yourself */
if (options->MyFamily) {
smartlist_t *family;
if (!warned_nonexistent_family)
warned_nonexistent_family = smartlist_create();
family = smartlist_create();
ri->declared_family = smartlist_create();
smartlist_split_string(family, options->MyFamily, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH(family, char *, name,
{
routerinfo_t *member;
if (!strcasecmp(name, options->Nickname))
member = ri;
else
member = router_get_by_nickname(name, 1);
if (!member) {
int is_legal = is_legal_nickname_or_hexdigest(name);
if (!smartlist_string_isin(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_is_me(member)) {
/* Don't list ourself in our own family; that's redundant */
} else {
char *fp = tor_malloc(HEX_DIGEST_LEN+2);
fp[0] = '$';
base16_encode(fp+1,HEX_DIGEST_LEN+1,
member->cache_info.identity_digest, DIGEST_LEN);
smartlist_add(ri->declared_family, fp);
if (smartlist_string_isin(warned_nonexistent_family, name))
smartlist_string_remove(warned_nonexistent_family, name);
}
tor_free(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);
ei->cache_info.signed_descriptor_body = tor_malloc(8192);
if (extrainfo_dump_to_string(ei->cache_info.signed_descriptor_body, 8192,
ei, get_identity_key()) < 0) {
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
extrainfo_free(ei);
return -1;
}
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_digest);
/* Now finish the router descriptor. */
memcpy(ri->cache_info.extra_info_digest,
ei->cache_info.signed_descriptor_digest,
DIGEST_LEN);
ri->cache_info.signed_descriptor_body = tor_malloc(8192);
if (router_dump_router_to_string(ri->cache_info.signed_descriptor_body, 8192,
ri, get_identity_key())<0) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
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) {
ri->cache_info.send_unencrypted = 1;
ei->cache_info.send_unencrypted = 1;
}
router_get_router_hash(ri->cache_info.signed_descriptor_body,
ri->cache_info.signed_descriptor_digest);
tor_assert(! routerinfo_incompatible_with_extrainfo(ri, ei, NULL, NULL));
if (desc_routerinfo)
routerinfo_free(desc_routerinfo);
desc_routerinfo = ri;
if (desc_extrainfo)
extrainfo_free(desc_extrainfo);
desc_extrainfo = ei;
desc_clean_since = time(NULL);
desc_needs_upload = 1;
control_event_my_descriptor_changed();
return 0;
}
/** Mark descriptor out of date if it's older than <b>when</b> */
void
mark_my_descriptor_dirty_if_older_than(time_t when)
{
if (desc_clean_since < when)
mark_my_descriptor_dirty();
}
/** Call when the current descriptor is out of date. */
void
mark_my_descriptor_dirty(void)
{
desc_clean_since = 0;
}
/** 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();
last_changed = now;
}
}
}
/** Note at log level severity that our best guess of address has changed from
* <b>prev</b> to <b>cur</b>. */
static void
log_addr_has_changed(int severity, uint32_t prev, uint32_t cur)
{
char addrbuf_prev[INET_NTOA_BUF_LEN];
char addrbuf_cur[INET_NTOA_BUF_LEN];
struct in_addr in_prev;
struct in_addr in_cur;
in_prev.s_addr = htonl(prev);
tor_inet_ntoa(&in_prev, addrbuf_prev, sizeof(addrbuf_prev));
in_cur.s_addr = htonl(cur);
tor_inet_ntoa(&in_cur, addrbuf_cur, sizeof(addrbuf_cur));
if (prev)
log_fn(severity, LD_GENERAL,
"Our IP Address has changed from %s to %s; "
"rebuilding descriptor.",
addrbuf_prev, addrbuf_cur);
else
log_notice(LD_GENERAL,
"Guessed our IP address as %s.",
addrbuf_cur);
}
/** 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;
or_options_t *options = get_options();
(void) now;
if (!desc_routerinfo)
return;
prev = desc_routerinfo->addr;
if (resolve_my_address(LOG_INFO, options, &cur, NULL) < 0) {
log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
return;
}
if (prev != cur) {
log_addr_has_changed(LOG_INFO, prev, cur);
ip_address_changed(0);
}
}
/** The most recently guessed value of our IP address, based on directory
* headers. */
static uint32_t last_guessed_ip = 0;
/** A directory server <b>d_conn</b> told us our IP address is
* <b>suggestion</b>.
* 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)
{
uint32_t addr, cur = 0;
struct in_addr in;
or_options_t *options = get_options();
/* first, learn what the IP address actually is */
if (!tor_inet_aton(suggestion, &in)) {
log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
escaped(suggestion));
return;
}
addr = ntohl(in.s_addr);
log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
if (!server_mode(options)) {
last_guessed_ip = addr; /* store it in case we need it later */
return;
}
if (resolve_my_address(LOG_INFO, options, &cur, NULL) >= 0) {
/* We're all set -- we already know our address. Great. */
last_guessed_ip = cur; /* store it in case we need it later */
return;
}
if (is_internal_IP(addr, 0)) {
/* Don't believe anybody who says our IP is, say, 127.0.0.1. */
return;
}
if (addr == d_conn->_base.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 (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);
ip_address_changed(0);
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 (last_guessed_ip) {
*guess = last_guessed_ip;
return 0;
}
return -1;
}
extern const char tor_svn_revision[]; /* from main.c */
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
* string describing the version of Tor and the operating system we're
* currently running on.
*/
void
get_platform_str(char *platform, size_t len)
{
tor_snprintf(platform, len, "Tor %s on %s", get_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 write the
* result into <b>s</b>, using at most <b>maxlen</b> bytes. Return -1 on
* failure, and the number of bytes used on success.
*/
int
router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
crypto_pk_env_t *ident_key)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -