📄 router.c
字号:
char *onion_pkey; /* Onion key, PEM-encoded. */
char *identity_pkey; /* Identity key, PEM-encoded. */
char digest[DIGEST_LEN];
char published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1];
char extra_info_digest[HEX_DIGEST_LEN+1];
size_t onion_pkeylen, identity_pkeylen;
size_t written;
int result=0;
addr_policy_t *tmpe;
char *family_line;
or_options_t *options = get_options();
/* Make sure the identity key matches the one in the routerinfo. */
if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
log_warn(LD_BUG,"Tried to sign a router with a private key that didn't "
"match router's public key!");
return -1;
}
/* 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");
return -1;
}
/* 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!");
return -1;
}
/* PEM-encode the identity key 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!");
tor_free(onion_pkey);
return -1;
}
/* Encode the publication time. */
format_iso_time(published, router->cache_info.published_on);
if (router->declared_family && smartlist_len(router->declared_family)) {
size_t n;
char *family = smartlist_join_strings(router->declared_family, " ", 0, &n);
n += strlen("family ") + 2; /* 1 for \n, 1 for \0. */
family_line = tor_malloc(n);
tor_snprintf(family_line, n, "family %s\n", family);
tor_free(family);
} else {
family_line = tor_strdup("");
}
base16_encode(extra_info_digest, sizeof(extra_info_digest),
router->cache_info.extra_info_digest, DIGEST_LEN);
/* Generate the easy portion of the router descriptor. */
result = tor_snprintf(s, maxlen,
"router %s %s %d 0 %d\n"
"platform %s\n"
"opt protocols Link 1 2 Circuit 1\n"
"published %s\n"
"opt fingerprint %s\n"
"uptime %ld\n"
"bandwidth %d %d %d\n"
"opt extra-info-digest %s\n%s"
"onion-key\n%s"
"signing-key\n%s"
"%s%s%s",
router->nickname,
router->address,
router->or_port,
decide_to_advertise_dirport(options, router->dir_port),
router->platform,
published,
fingerprint,
stats_n_seconds_working,
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
extra_info_digest,
options->DownloadExtraInfo ? "opt caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
we_are_hibernating() ? "opt hibernating 1\n" : "",
options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "");
tor_free(family_line);
tor_free(onion_pkey);
tor_free(identity_pkey);
if (result < 0) {
log_warn(LD_BUG,"descriptor snprintf #1 ran out of room!");
return -1;
}
/* From now on, we use 'written' to remember the current length of 's'. */
written = result;
if (options->ContactInfo && strlen(options->ContactInfo)) {
const char *ci = options->ContactInfo;
if (strchr(ci, '\n') || strchr(ci, '\r'))
ci = escaped(ci);
result = tor_snprintf(s+written,maxlen-written, "contact %s\n", ci);
if (result<0) {
log_warn(LD_BUG,"descriptor snprintf #2 ran out of room!");
return -1;
}
written += result;
}
/* Write the exit policy to the end of 's'. */
if (dns_seems_to_be_broken() ||
!router->exit_policy || !smartlist_len(router->exit_policy)) {
/* DNS is screwed up; don't claim to be an exit. */
strlcat(s+written, "reject *:*\n", maxlen-written);
written += strlen("reject *:*\n");
tmpe = NULL;
} else if (router->exit_policy) {
int i;
for (i = 0; i < smartlist_len(router->exit_policy); ++i) {
tmpe = smartlist_get(router->exit_policy, i);
result = policy_write_item(s+written, maxlen-written, tmpe);
if (result < 0) {
log_warn(LD_BUG,"descriptor policy_write_item ran out of room!");
return -1;
}
tor_assert(result == (int)strlen(s+written));
written += result;
if (written+2 > maxlen) {
log_warn(LD_BUG,"descriptor policy_write_item ran out of room (2)!");
return -1;
}
s[written++] = '\n';
}
}
if (written+256 > maxlen) { /* Not enough room for signature. */
log_warn(LD_BUG,"not enough room left in descriptor for signature!");
return -1;
}
/* Sign the directory */
strlcpy(s+written, "router-signature\n", maxlen-written);
written += strlen(s+written);
s[written] = '\0';
if (router_get_router_hash(s, digest) < 0) {
return -1;
}
note_crypto_pk_op(SIGN_RTR);
if (router_append_dirobj_signature(s+written,maxlen-written,
digest,ident_key)<0) {
log_warn(LD_BUG, "Couldn't sign router descriptor");
return -1;
}
written += strlen(s+written);
if (written+2 > maxlen) {
log_warn(LD_BUG,"Not enough room to finish descriptor.");
return -1;
}
/* include a last '\n' */
s[written] = '\n';
s[written+1] = 0;
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
{
char *s_dup;
const char *cp;
routerinfo_t *ri_tmp;
cp = s_dup = tor_strdup(s);
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>>", s);
return -1;
}
tor_free(s_dup);
routerinfo_free(ri_tmp);
}
#endif
return (int)written+1;
}
/** Write the contents of <b>extrainfo</b> to the <b>maxlen</b>-byte string
* <b>s</b>, signing them with <b>ident_key</b>. Return 0 on success,
* negative on failure. */
int
extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
crypto_pk_env_t *ident_key)
{
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;
size_t len;
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(1);
result = tor_snprintf(s, maxlen,
"extra-info %s %s\n"
"published %s\n%s",
extrainfo->nickname, identity,
published, bandwidth_usage);
tor_free(bandwidth_usage);
if (result<0)
return -1;
if (options->BridgeRelay && options->BridgeRecordUsageByCountry) {
char *geoip_summary = geoip_get_client_history(time(NULL));
if (geoip_summary) {
char geoip_start[ISO_TIME_LEN+1];
format_iso_time(geoip_start, geoip_get_history_start());
result = tor_snprintf(s+strlen(s), maxlen-strlen(s),
"geoip-start-time %s\n"
"geoip-client-origins %s\n",
geoip_start, geoip_summary);
tor_free(geoip_summary);
if (result<0)
return -1;
}
}
len = strlen(s);
strlcat(s+len, "router-signature\n", maxlen-len);
len += strlen(s+len);
if (router_get_extrainfo_hash(s, digest)<0)
return -1;
if (router_append_dirobj_signature(s+len, maxlen-len, digest, ident_key)<0)
return -1;
#ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
{
char *cp, *s_dup;
extrainfo_t *ei_tmp;
cp = s_dup = tor_strdup(s);
ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL);
if (!ei_tmp) {
log_err(LD_BUG,
"We just generated an extrainfo descriptor we can't parse.");
log_err(LD_BUG, "Descriptor was: <<%s>>", s);
return -1;
}
tor_free(s_dup);
extrainfo_free(ei_tmp);
}
#endif
return (int)strlen(s)+1;
}
/** Return true iff <b>s</b> is a legally valid server nickname. */
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 <b>s</b> is a legally 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 <b>s</b> is a legally valid hex-encoded identity-key
* digest. */
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);
}
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
* verbose representation of the identity of <b>router</b>. 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, routerinfo_t *router)
{
buf[0] = '$';
base16_encode(buf+1, HEX_DIGEST_LEN+1, router->cache_info.identity_digest,
DIGEST_LEN);
buf[1+HEX_DIGEST_LEN] = router->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)
{
if (onionkey)
crypto_free_pk_env(onionkey);
if (lastonionkey)
crypto_free_pk_env(lastonionkey);
if (identitykey)
crypto_free_pk_env(identitykey);
if (key_lock)
tor_mutex_free(key_lock);
if (desc_routerinfo)
routerinfo_free(desc_routerinfo);
if (desc_extrainfo)
extrainfo_free(desc_extrainfo);
if (authority_signing_key)
crypto_free_pk_env(authority_signing_key);
if (authority_key_certificate)
authority_cert_free(authority_key_certificate);
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
smartlist_free(warned_nonexistent_family);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -