📄 dirserv.c
字号:
{
char *s=NULL;
char digest[DIGEST_LEN];
char published[ISO_TIME_LEN+1];
size_t len;
crypto_pk_env_t *private_key = get_identity_key();
char *identity_pkey; /* Identity key, DER64-encoded. */
size_t identity_pkey_len;
if (crypto_pk_write_public_key_to_string(private_key,&identity_pkey,
&identity_pkey_len)<0) {
log_warn(LD_BUG,"write identity_pkey to string failed!");
goto err;
}
format_iso_time(published, time(NULL));
len = 2048;
s = tor_malloc_zero(len);
tor_snprintf(s, len,
"network-status\n"
"published %s\n"
"router-status %s\n"
"dir-signing-key\n%s"
"directory-signature %s\n",
published, "", identity_pkey,
get_options()->Nickname);
tor_free(identity_pkey);
if (router_get_runningrouters_hash(s,digest)) {
log_warn(LD_BUG,"couldn't compute digest");
goto err;
}
note_crypto_pk_op(SIGN_DIR);
if (router_append_dirobj_signature(s, len, digest, private_key)<0)
goto err;
set_cached_dir(&the_runningrouters, s, time(NULL));
runningrouters_is_dirty = 0;
return &the_runningrouters;
err:
tor_free(s);
return NULL;
}
/** Set *<b>rr</b> to the most recently generated encoded signed
* running-routers list, generating a new one as necessary. Return the
* size of the directory on success, and 0 on failure. */
cached_dir_t *
dirserv_get_runningrouters(void)
{
return dirserv_pick_cached_dir_obj(
&cached_runningrouters, &the_runningrouters,
runningrouters_is_dirty,
generate_runningrouters,
"v1 network status list", V1_AUTHORITY);
}
cached_dir_t *
dirserv_get_consensus(void)
{
return cached_v3_networkstatus;
}
/** For authoritative directories: the current (v2) network status. */
static cached_dir_t *the_v2_networkstatus = NULL;
/** Return true iff our opinion of the routers has been stale for long
* enough that we should generate a new v2 network status doc. */
static int
should_generate_v2_networkstatus(void)
{
return authdir_mode_v2(get_options()) &&
the_v2_networkstatus_is_dirty &&
the_v2_networkstatus_is_dirty + DIR_REGEN_SLACK_TIME < time(NULL);
}
/** If a router's uptime is at least this value, then it is always
* considered stable, regardless of the rest of the network. This
* way we resist attacks where an attacker doubles the size of the
* network using allegedly high-uptime nodes, displacing all the
* current guards. */
#define UPTIME_TO_GUARANTEE_STABLE (3600*24*30)
/** If a router's MTBF is at least this value, then it is always stable.
* See above. (Corresponds to about 7 days for current decay rates.) */
#define MTBF_TO_GUARANTEE_STABLE (60*60*24*5)
/** Similarly, we protect sufficiently fast nodes from being pushed
* out of the set of Fast nodes. */
#define BANDWIDTH_TO_GUARANTEE_FAST (100*1024)
/** Similarly, every node with sufficient bandwidth can be considered
* for Guard status. */
#define BANDWIDTH_TO_GUARANTEE_GUARD (250*1024)
/** Similarly, every node with at least this much weighted time known can be
* considered familiar enough to be a guard. Corresponds to about 20 days for
* current decay rates.
*/
#define TIME_KNOWN_TO_GUARANTEE_FAMILIAR (8*24*60*60)
/** Similarly, every node with sufficient WFU is around enough to be a guard.
*/
#define WFU_TO_GUARANTEE_GUARD (0.995)
/* Thresholds for server performance: set by
* dirserv_compute_performance_thresholds, and used by
* generate_v2_networkstatus */
/* XXXX stick these all in a struct. */
static uint32_t stable_uptime = 0; /* start at a safe value */
static double stable_mtbf = 0.0;
static int enough_mtbf_info = 0;
static double guard_wfu = 0.0;
static long guard_tk = 0;
static uint32_t fast_bandwidth = 0;
static uint32_t guard_bandwidth_including_exits = 0;
static uint32_t guard_bandwidth_excluding_exits = 0;
static uint64_t total_bandwidth = 0;
static uint64_t total_exit_bandwidth = 0;
/** Helper: estimate the uptime of a router given its stated uptime and the
* amount of time since it last stated its stated uptime. */
static INLINE long
real_uptime(routerinfo_t *router, time_t now)
{
if (now < router->cache_info.published_on)
return router->uptime;
else
return router->uptime + (now - router->cache_info.published_on);
}
/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
* If <b>need_uptime</b> is non-zero, we require a minimum uptime.
* If <b>need_capacity</b> is non-zero, we require a minimum advertised
* bandwidth.
*/
static int
dirserv_thinks_router_is_unreliable(time_t now,
routerinfo_t *router,
int need_uptime, int need_capacity)
{
if (need_uptime) {
if (!enough_mtbf_info) {
/* XXXX Once most authorities are on v3, we should change the rule from
* "use uptime if we don't have mtbf data" to "don't advertise Stable on
* v3 if we don't have enough mtbf data." */
long uptime = real_uptime(router, now);
if ((unsigned)uptime < stable_uptime &&
(unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE)
return 1;
} else {
double mtbf =
rep_hist_get_stability(router->cache_info.identity_digest, now);
if (mtbf < stable_mtbf)
return 1;
}
}
if (need_capacity) {
uint32_t bw = router_get_advertised_bandwidth(router);
if (bw < fast_bandwidth)
return 1;
}
return 0;
}
/** Return true iff <b>router</b> should be assigned the "HSDir" flag.
* Right now this means it advertises support for it, it has a high
* uptime, and it's currently considered Running.
*
* This function needs to be called after router-\>is_running has
* been set.
*/
static int
dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now)
{
long uptime = real_uptime(router, now);
return (router->wants_to_be_hs_dir &&
uptime > get_options()->MinUptimeHidServDirectoryV2 &&
router->is_running);
}
/** Look through the routerlist, the Mean Time Between Failure history, and
* the Weighted Fractional Uptime history, and use them to set thresholds for
* the Stable, Fast, and Guard flags. Update the fields stable_uptime,
* stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth,
* guard_bandwidh_including_exits, guard_bandwidth_excluding_exits,
* total_bandwidth, and total_exit_bandwidth.
*
* Also, set the is_exit flag of each router appropriately. */
static void
dirserv_compute_performance_thresholds(routerlist_t *rl)
{
int n_active, n_active_nonexit, n_familiar;
uint32_t *uptimes, *bandwidths, *bandwidths_excluding_exits;
long *tks;
double *mtbfs, *wfus;
time_t now = time(NULL);
/* initialize these all here, in case there are no routers */
stable_uptime = 0;
stable_mtbf = 0;
fast_bandwidth = 0;
guard_bandwidth_including_exits = 0;
guard_bandwidth_excluding_exits = 0;
guard_tk = 0;
guard_wfu = 0;
total_bandwidth = 0;
total_exit_bandwidth = 0;
/* Initialize arrays that will hold values for each router. We'll
* sort them and use that to compute thresholds. */
n_active = n_active_nonexit = 0;
/* Uptime for every active router. */
uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active router. */
bandwidths = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active non-exit router. */
bandwidths_excluding_exits =
tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Weighted mean time between failure for each active router. */
mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
/* Time-known for each active router. */
tks = tor_malloc(sizeof(long)*smartlist_len(rl->routers));
/* Weighted fractional uptime for each active router. */
wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
/* Now, fill in the arrays. */
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
if (router_is_active(ri, now)) {
const char *id = ri->cache_info.identity_digest;
uint32_t bw;
ri->is_exit = exit_policy_is_general_exit(ri->exit_policy);
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
total_bandwidth += bw;
if (ri->is_exit && !ri->is_bad_exit) {
total_exit_bandwidth += bw;
} else {
bandwidths_excluding_exits[n_active_nonexit] = bw;
++n_active_nonexit;
}
++n_active;
}
});
/* Now, compute thresholds. */
if (n_active) {
/* The median uptime is stable. */
stable_uptime = median_uint32(uptimes, n_active);
/* The median mtbf is stable, if we have enough mtbf info */
stable_mtbf = median_double(mtbfs, n_active);
/* The 12.5th percentile bandwidth is fast. */
fast_bandwidth = find_nth_uint32(bandwidths, n_active, n_active/8);
/* (Now bandwidths is sorted.) */
if (fast_bandwidth < ROUTER_REQUIRED_MIN_BANDWIDTH)
fast_bandwidth = bandwidths[n_active/4];
guard_bandwidth_including_exits = bandwidths[(n_active-1)/2];
guard_tk = find_nth_long(tks, n_active, n_active/8);
}
if (guard_tk > TIME_KNOWN_TO_GUARANTEE_FAMILIAR)
guard_tk = TIME_KNOWN_TO_GUARANTEE_FAMILIAR;
if (fast_bandwidth > BANDWIDTH_TO_GUARANTEE_FAST)
fast_bandwidth = BANDWIDTH_TO_GUARANTEE_FAST;
/* Now that we have a time-known that 7/8 routers are known longer than,
* fill wfus with the wfu of every such "familiar" router. */
n_familiar = 0;
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
if (router_is_active(ri, now)) {
const char *id = ri->cache_info.identity_digest;
long tk = rep_hist_get_weighted_time_known(id, now);
if (tk < guard_tk)
continue;
wfus[n_familiar++] = rep_hist_get_weighted_fractional_uptime(id, now);
}
});
if (n_familiar)
guard_wfu = median_double(wfus, n_familiar);
if (guard_wfu > WFU_TO_GUARANTEE_GUARD)
guard_wfu = WFU_TO_GUARANTEE_GUARD;
enough_mtbf_info = rep_hist_have_measured_enough_stability();
if (n_active_nonexit) {
guard_bandwidth_excluding_exits =
median_uint32(bandwidths_excluding_exits, n_active_nonexit);
}
log(LOG_INFO, LD_DIRSERV,
"Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. "
"For Fast: %lu bytes/sec. "
"For Guard: WFU %.03lf%%, time-known %lu sec, "
"and bandwidth %lu or %lu bytes/sec.",
(unsigned long)stable_uptime,
(unsigned long)stable_mtbf,
(unsigned long)fast_bandwidth,
guard_wfu*100,
(unsigned long)guard_tk,
(unsigned long)guard_bandwidth_including_exits,
(unsigned long)guard_bandwidth_excluding_exits);
tor_free(uptimes);
tor_free(mtbfs);
tor_free(bandwidths);
tor_free(bandwidths_excluding_exits);
tor_free(tks);
tor_free(wfus);
}
/** Given a platform string as in a routerinfo_t (possibly null), return a
* newly allocated version string for a networkstatus document, or NULL if the
* platform doesn't give a Tor version. */
static char *
version_from_platform(const char *platform)
{
if (platform && !strcmpstart(platform, "Tor ")) {
const char *eos = find_whitespace(platform+4);
if (eos && !strcmpstart(eos, " (r")) {
/* XXXX021 Unify this logic with the other version extraction
* logic */
eos = find_whitespace(eos+1);
}
if (eos) {
return tor_strndup(platform, eos-platform);
}
}
return NULL;
}
/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>,
* which has at least <b>buf_len</b> free characters. Do NUL-termination.
* Use the same format as in network-status documents. If <b>version</b> is
* non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
* failure. If <b>first_line_only<b> is true, don't include any flags
* or version line.
*/
int
routerstatus_format_entry(char *buf, size_t buf_len,
routerstatus_t *rs, const char *version,
int first_line_only)
{
int r;
struct in_addr in;
char *cp;
char published[ISO_TIME_LEN+1];
char ipaddr[INET_NTOA_BUF_LEN];
char identity64[BASE64_DIGEST_LEN+1];
char digest64[BASE64_DIGEST_LEN+1];
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
in.s_addr = htonl(rs->addr);
tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
r = tor_snprintf(buf, buf_len,
"r %s %s %s %s %s %d %d\n",
rs->nickname,
identity64,
digest64,
published,
ipaddr,
(int)rs->or_port,
(int)rs->dir_port);
if (r<0) {
log_warn(LD_BUG, "Not enough space in buffer.");
return -1;
}
if (first_line_only)
return 0;
cp = buf + strlen(buf);
/* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
r = tor_snprintf(cp, buf_len - (cp-buf),
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in al
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -