📄 router.c
字号:
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 we believe ourselves to be an authoritative
* directory server.
*/
int
authdir_mode(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(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(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(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(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(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
* <b>purpose</b> its dirport. Use -1 for "any purpose". */
int
authdir_mode_handles_descs(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(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(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(or_options_t *options)
{
return authdir_mode(options) && options->BridgeAuthoritativeDir != 0;
}
/** Return true iff we once tried to stay connected to all ORs at once.
* FFFF this function, and the notion of staying connected to ORs, is
* nearly obsolete. One day there will be a proposal for getting rid of
* it.
*/
int
clique_mode(or_options_t *options)
{
return authdir_mode_tests_reachability(options);
}
/** Return true iff we are trying to be a server.
*/
int
server_mode(or_options_t *options)
{
if (options->ClientOnly) return 0;
return (options->ORPort != 0 || options->ORListenAddress);
}
/** 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 be a socks proxy. */
int
proxy_mode(or_options_t *options)
{
return (options->SocksPort != 0 || options->SocksListenAddress ||
options->TransPort != 0 || options->TransListenAddress ||
options->NatdPort != 0 || options->NatdListenAddress ||
options->DNSPort != 0 || options->DNSListenAddress);
}
/** 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)
{
or_options_t *options = get_options();
if (options->ClientOnly)
return 0;
if (options->_PublishServerDescriptor == NO_AUTHORITY)
return 0;
if (!server_mode(options))
return 0;
if (authdir_mode(options))
return 1;
return check_whether_orport_reachable();
}
/** Initiate server descriptor upload as reasonable (if server is publishable,
* etc). <b>force</b> 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);
}
}
/*
* Clique maintenance -- to be phased out.
*/
/** Return true iff we believe this OR tries to keep connections open
* to all other ORs. */
int
router_is_clique_mode(routerinfo_t *router)
{
if (router_digest_is_trusted_dir(router->cache_info.identity_digest))
return 1;
return 0;
}
/*
* OR descriptor generation.
*/
/** My routerinfo. */
static routerinfo_t *desc_routerinfo = NULL;
/** My extrainfo */
static extrainfo_t *desc_extrainfo = NULL;
/** Since when has our descriptor been "clean"? 0 if we need to regenerate it
* now. */
static time_t desc_clean_since = 0;
/** Boolean: do we need to regenerate the above? */
static int desc_needs_upload = 0;
/** OR only: If <b>force</b> 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)
{
routerinfo_t *ri;
extrainfo_t *ei;
char *msg;
size_t desc_len, extra_len = 0, total_len;
authority_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_AUTHORITY)
return;
if (!force && !desc_needs_upload)
return;
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_AUTHORITY) ?
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(edge_connection_t *conn)
{
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 (!conn->_base.addr)
return -1;
return compare_addr_to_addr_policy(conn->_base.addr, conn->_base.port,
desc_routerinfo->exit_policy) != ADDR_POLICY_ACCEPTED;
}
/** Return true iff I'm a server and <b>digest</b> is equal to
* my identity digest. */
int
router_digest_is_me(const char *digest)
{
return identitykey && !memcmp(identitykey_digest, digest, DIGEST_LEN);
}
/** Return true iff I'm a server and <b>digest</b> 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 !memcmp(digest,
ei->cache_info.signed_descriptor_digest,
DIGEST_LEN);
}
/** A wrapper around router_digest_is_me(). */
int
router_is_me(routerinfo_t *router)
{
return router_digest_is_me(router->cache_info.identity_digest);
}
/** Return true iff <b>fp</b> 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. */
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;
}
/** 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 *<b>addr</b> and return
* 0 on success, else return -1 if we have no guess. */
int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -