Merge branch 'maint-0.2.2' into release-0.2.2
This commit is contained in:
commit
984a6bfeb8
|
@ -0,0 +1,73 @@
|
|||
o Major features and bugfixes (node selection)
|
||||
|
||||
- Revise and unify the meaning of the ExitNodes, EntryNodes,
|
||||
ExcludeEntryNodes, ExcludeExitNodes, ExcludeNodes, and
|
||||
StrictNodes options. Previously, we had been ambiguous in
|
||||
describing what counted as an "exit" node, and what operations
|
||||
exactly "StrictNodes 0" would permit. This created confusion
|
||||
when people saw nodes built through unexpected circuits, and
|
||||
made it hard to tell real bugs from surprises. We now stipulate
|
||||
that the intended behavior is:
|
||||
|
||||
. "Exit", in the context of ExitNodes and ExcludeExitNodes,
|
||||
means a node that delivers user traffic outside the Tor
|
||||
network.
|
||||
. "Entry", in the context of EntryNodes and ExcludeEntryNodes,
|
||||
means a node used as the first hop of a multihop circuit:
|
||||
it doesn't include direct connections to directory servers.
|
||||
. "ExcludeNodes" applies to all nodes.
|
||||
. "StrictNodes" changes the behavior of ExcludeNodes only.
|
||||
When StrictNodes is set, Tor should avoid all nodes listed
|
||||
in ExcludeNodes, even when it will make user requests
|
||||
fail. When StrictNodes is *not* set, then Tor should
|
||||
follow ExcludeNodes whenever it can, except when it must
|
||||
use an excluded node to perform self-tests, connect to a
|
||||
hidden service, provide a hidden service, fulfill a .exit
|
||||
request, upload directory information, or fetch directory
|
||||
information.
|
||||
|
||||
Collectively, the changes to implement the behavior are a fix for
|
||||
bug 1090.
|
||||
|
||||
- ExcludeNodes now takes precedence over EntryNodes and ExitNodes:
|
||||
if a node is listed in both, it's treated as excluded.
|
||||
|
||||
- ExcludeNodes now applies to directory nodes: as a preference if
|
||||
StrictNodes is 0, or an absolute requirement if StrictNodes is 1.
|
||||
(Don't exclude all the directory authorities and set StrictNodes
|
||||
to 1 unless you really want your Tor to break.)
|
||||
|
||||
- ExcludeNodes and ExcludeExitNodes now override exit enclaving.
|
||||
|
||||
- ExcludeExitNodes now overrides .exit requests.
|
||||
|
||||
- We don't use bridges from ExcludeNodes.
|
||||
|
||||
- When StrictNodes is 1:
|
||||
. We now apply ExcludeNodes to hidden service introduction points
|
||||
and to rendezvous points selected by hidden service users.
|
||||
This can make your hidden service less reliable: use it with
|
||||
caution!
|
||||
. If we have used ExcludeNodes on ourself, do not try self-tests.
|
||||
. If we have excluded all the directory authorities, we will
|
||||
not even try to upload our descriptor if we're a server.
|
||||
. Do not honor .exit requests to an excluded node.
|
||||
|
||||
- Remove a misfeature that caused us to ignore the Fast/Stable flags
|
||||
if ExitNodes was set. Bugfix on 0.2.2.7-alpha.
|
||||
|
||||
- When the set of permitted nodes changes, we now remove any
|
||||
mappings introduced via TrackExitHosts to now-excluded nodes.
|
||||
Bugfix on 0.1.0.1-rc.
|
||||
|
||||
- We never cannibalize a circuit that had excluded nodes on it,
|
||||
even if StrictNodes is 0. Bugfix on 0.1.0.1-rc.
|
||||
|
||||
- Improve log messages related to excluded nodes.
|
||||
|
||||
- Revert a change where we would be laxer about attaching streams to
|
||||
circuits than when building the circuits. This was meant to
|
||||
prevent a set of bugs where streams were never attachable, but our
|
||||
improved code here should make this unnecessary. Bugfix on
|
||||
0.2.2.7-alpha.
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
o Minor features:
|
||||
- Keep track of how many times we launch a new circuit to handle
|
||||
a given stream. Too many launches could indicate an inconsistency
|
||||
between our "launch a circuit to handle this stream" logic and our
|
||||
"attach our stream to one of the available circuits" logic.
|
|
@ -0,0 +1,5 @@
|
|||
o Major bugfixes:
|
||||
- When writing our maximum bw for the current interval to the state
|
||||
file, don't wrongly inflate that value by a factor of 10 anymore.
|
||||
Fixes more of bug 2704.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
- Minor bugfixes:
|
||||
o Downgrade "no current certificates known for authority" message from
|
||||
Notice to Info. Bugfix on 0.2.0.10-alpha; fixes bug 2899.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
o Minor bugfixes
|
||||
- Make the SIGNAL DUMP control-port command work on FreeBSD. Fixes
|
||||
bug 2917. Bugfix on 0.1.1.1-alpha.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
o Minor bugfixes:
|
||||
- Be more consistent in our treatment of file system paths. ~ should
|
||||
get expanded to the user's home directory in the Log config option.
|
||||
Bugfix on 0.2.0.1-alpha, which introduced the feature for the -f and
|
||||
--DataDirectory options.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
o Minor bugfixes:
|
||||
- If the Nickname configuration option wasn't given, Tor used to pick
|
||||
a nickname based on the local hostname as the nickname for a relay.
|
||||
Because nicknames are not very important in today's Tor and the
|
||||
"Unnamed" nickname has been implemented, this is now problematic
|
||||
behaviour: It leaks information about the hostname without being
|
||||
useful at all. Bugfix on tor-0.1.2.2-alpha, which introduced the
|
||||
Unnamed nickname. Fixes bug 2979, reported by tagnaq.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
o Minor features:
|
||||
- If ExitNodes is set, still pay attention to the Fast/Stable
|
||||
status of exits when picking exit nodes. (We used to ignore
|
||||
these flags when ExitNodes was set, on the grounds that people
|
||||
who set exitnodes wanted all of those nodes to get used, but
|
||||
with the ability to pick exits by country and IP range, this
|
||||
doesn't necessarily make sense any more.)
|
|
@ -489,32 +489,76 @@ The following options are useful only for clients (that is, if
|
|||
|
||||
**ExcludeNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints, nicknames, country codes and address
|
||||
patterns of nodes to never use when building a circuit. (Example:
|
||||
ExcludeNodes SlowServer, $ EFFFFFFFFFFFFFFF, \{cc}, 255.254.0.0/8)
|
||||
patterns of nodes to avoid when building a circuit.
|
||||
(Example:
|
||||
ExcludeNodes SlowServer, $ EFFFFFFFFFFFFFFF, \{cc}, 255.254.0.0/8) +
|
||||
+
|
||||
By default, this option is treated as a preference that Tor is allowed
|
||||
to override in order to keep working.
|
||||
For example, if you try to connect to a hidden service,
|
||||
but you have excluded all of the hidden service's introduction points,
|
||||
Tor will connect to one of them anyway. If you do not want this
|
||||
behavior, set the StrictNodes option (documented below). +
|
||||
+
|
||||
Note also that if you are a relay, this (and the other node selection
|
||||
options below) only affects your own circuits that Tor builds for you.
|
||||
Clients can still build circuits through you to any node. Controllers
|
||||
can tell Tor to build circuits through any node.
|
||||
|
||||
|
||||
**ExcludeExitNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints, nicknames, country codes and address
|
||||
patterns of nodes to never use when picking an exit node. Note that any
|
||||
patterns of nodes to never use when picking an exit node---that is, a
|
||||
node that delivers traffic for you outside the Tor network. Note that any
|
||||
node listed in ExcludeNodes is automatically considered to be part of this
|
||||
list.
|
||||
list too. See also the caveats on the "ExitNodes" option below.
|
||||
|
||||
**EntryNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints, nicknames and address
|
||||
patterns of nodes to use for the first hop in normal circuits. These are
|
||||
treated only as preferences unless StrictNodes (see below) is also set.
|
||||
|
||||
**ExitNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints, nicknames, country codes and address
|
||||
patterns of nodes to use for the last hop in normal exit circuits. These
|
||||
are treated only as preferences unless StrictNodes (see below) is also set.
|
||||
patterns of nodes to use as exit node---that is, a
|
||||
node that delivers traffic for you outside the Tor network. +
|
||||
+
|
||||
Note that if you list too few nodes here, or if you exclude too many exit
|
||||
nodes with ExcludeExitNodes, you can degrade functionality. For example,
|
||||
if none of the exits you list allows traffic on port 80 or 443, you won't
|
||||
be able to browse the web. +
|
||||
+
|
||||
Note also that not every circuit is used to deliver traffic outside of
|
||||
the Tor network. It is normal to see non-exit circuits (such as those
|
||||
used to connect to hidden services, those that do directory fetches,
|
||||
those used for relay reachability self-tests, and so on) that end
|
||||
at a non-exit node. To
|
||||
keep a node from being used entirely, see ExcludeNodes and StrictNodes. +
|
||||
+
|
||||
The ExcludeNodes option overrides this option: any node listed in both
|
||||
ExitNodes and ExcludeNodes is treated as excluded. +
|
||||
+
|
||||
The .exit address notation, if enabled via AllowDotExit, overrides
|
||||
this option.
|
||||
|
||||
**EntryNodes** __node__,__node__,__...__::
|
||||
A list of identity fingerprints and nicknames of nodes
|
||||
to use for the first hop in your normal circuits. (Country codes and
|
||||
address patterns are not yet supported.) Normal circuits include all
|
||||
circuits except for direct connections to directory servers. The Bridge
|
||||
option overrides this option; if you have configured bridges and
|
||||
UseBridges is 1, the Bridges are used as your entry nodes. +
|
||||
+
|
||||
The ExcludeNodes option overrides this option: any node listed in both
|
||||
EntryNodes and ExcludeNodes is treated as excluded.
|
||||
|
||||
**StrictNodes** **0**|**1**::
|
||||
If 1 and EntryNodes config option is set, Tor will never use any nodes
|
||||
besides those listed in EntryNodes for the first hop of a normal circuit.
|
||||
If 1 and ExitNodes config option is set, Tor will never use any nodes
|
||||
besides those listed in ExitNodes for the last hop of a normal exit
|
||||
circuit. Note that Tor might still use these nodes for non-exit circuits
|
||||
such as one-hop directory fetches or hidden service support circuits.
|
||||
If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a
|
||||
requirement to follow for all the circuits you generate, even if doing so
|
||||
will break functionality for you. If StrictNodes is set to 0, Tor will
|
||||
still try to avoid nodes in the ExcludeNodes list, but it will err on the
|
||||
side of avoiding unexpected errors. Specifically, StrictNodes 0 tells
|
||||
Tor that it is okay to use an excluded node when it is *necessary* to
|
||||
perform relay reachability self-tests, connect to
|
||||
a hidden service, provide a hidden service to a client, fulfill a .exit
|
||||
request, upload directory information, or download directory information.
|
||||
(Default: 0)
|
||||
|
||||
**FascistFirewall** **0**|**1**::
|
||||
If 1, Tor will only create outgoing connections to ORs running on ports
|
||||
|
|
|
@ -2051,8 +2051,9 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
|||
*/
|
||||
if (timediff < 0 || timediff > 2*circ_times.close_ms+1000) {
|
||||
log_notice(LD_CIRC, "Strange value for circuit build time: %ldmsec. "
|
||||
"Assuming clock jump. Purpose %d", timediff,
|
||||
circ->_base.purpose);
|
||||
"Assuming clock jump. Purpose %d (%s)", timediff,
|
||||
circ->_base.purpose,
|
||||
circuit_purpose_to_string(circ->_base.purpose));
|
||||
} else if (!circuit_build_times_disabled()) {
|
||||
/* Only count circuit times if the network is live */
|
||||
if (circuit_build_times_network_check_live(&circ_times)) {
|
||||
|
@ -2685,16 +2686,24 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
n_supported[i] = -1;
|
||||
continue; /* skip routers that are known to be down or bad exits */
|
||||
}
|
||||
if (router_is_unreliable(router, need_uptime, need_capacity, 0) &&
|
||||
(!options->ExitNodes ||
|
||||
!routerset_contains_router(options->ExitNodes, router))) {
|
||||
/* FFFF Someday, differentiate between a routerset that names
|
||||
* routers, and a routerset that names countries, and only do this
|
||||
* check if they've asked for specific exit relays. Or if the country
|
||||
* they ask for is rare. Or something. */
|
||||
|
||||
if (options->_ExcludeExitNodesUnion &&
|
||||
routerset_contains_router(options->_ExcludeExitNodesUnion, router)) {
|
||||
n_supported[i] = -1;
|
||||
continue; /* skip routers that are not suitable, unless we have
|
||||
* ExitNodes set, in which case we asked for it */
|
||||
continue; /* user asked us not to use it, no matter what */
|
||||
}
|
||||
if (options->ExitNodes &&
|
||||
!routerset_contains_router(options->ExitNodes, router)) {
|
||||
n_supported[i] = -1;
|
||||
continue; /* not one of our chosen exit nodes */
|
||||
}
|
||||
|
||||
if (router_is_unreliable(router, need_uptime, need_capacity, 0)) {
|
||||
n_supported[i] = -1;
|
||||
continue; /* skip routers that are not suitable. Don't worry if
|
||||
* this makes us reject all the possible routers: if so,
|
||||
* we'll retry later in this function with need_update and
|
||||
* need_capacity set to 0. */
|
||||
}
|
||||
if (!(router->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
|
||||
/* if it's invalid and we don't want it */
|
||||
|
@ -2719,7 +2728,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
{
|
||||
if (!ap_stream_wants_exit_attention(conn))
|
||||
continue; /* Skip everything but APs in CIRCUIT_WAIT */
|
||||
if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), router, 1)) {
|
||||
if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), router)) {
|
||||
++n_supported[i];
|
||||
// log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
|
||||
// router->nickname, i, n_supported[i]);
|
||||
|
@ -2753,21 +2762,13 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
/* If any routers definitely support any pending connections, choose one
|
||||
* at random. */
|
||||
if (best_support > 0) {
|
||||
smartlist_t *supporting = smartlist_create(), *use = smartlist_create();
|
||||
smartlist_t *supporting = smartlist_create();
|
||||
|
||||
for (i = 0; i < smartlist_len(dir->routers); i++)
|
||||
if (n_supported[i] == best_support)
|
||||
smartlist_add(supporting, smartlist_get(dir->routers, i));
|
||||
|
||||
routersets_get_disjunction(use, supporting, options->ExitNodes,
|
||||
options->_ExcludeExitNodesUnion, 1);
|
||||
if (smartlist_len(use) == 0 && options->ExitNodes &&
|
||||
!options->StrictNodes) { /* give up on exitnodes and try again */
|
||||
routersets_get_disjunction(use, supporting, NULL,
|
||||
options->_ExcludeExitNodesUnion, 1);
|
||||
}
|
||||
router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
|
||||
smartlist_free(use);
|
||||
router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
|
||||
smartlist_free(supporting);
|
||||
} else {
|
||||
/* Either there are no pending connections, or no routers even seem to
|
||||
|
@ -2775,7 +2776,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
* at least one predicted exit port. */
|
||||
|
||||
int attempt;
|
||||
smartlist_t *needed_ports, *supporting, *use;
|
||||
smartlist_t *needed_ports, *supporting;
|
||||
|
||||
if (best_support == -1) {
|
||||
if (need_uptime || need_capacity) {
|
||||
|
@ -2792,7 +2793,6 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
options->_ExcludeExitNodesUnion ? " or are Excluded" : "");
|
||||
}
|
||||
supporting = smartlist_create();
|
||||
use = smartlist_create();
|
||||
needed_ports = circuit_get_unhandled_ports(time(NULL));
|
||||
for (attempt = 0; attempt < 2; attempt++) {
|
||||
/* try once to pick only from routers that satisfy a needed port,
|
||||
|
@ -2807,25 +2807,13 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
}
|
||||
}
|
||||
|
||||
routersets_get_disjunction(use, supporting, options->ExitNodes,
|
||||
options->_ExcludeExitNodesUnion, 1);
|
||||
if (smartlist_len(use) == 0 && options->ExitNodes &&
|
||||
!options->StrictNodes) { /* give up on exitnodes and try again */
|
||||
routersets_get_disjunction(use, supporting, NULL,
|
||||
options->_ExcludeExitNodesUnion, 1);
|
||||
}
|
||||
/* FFF sometimes the above results in null, when the requested
|
||||
* exit node is considered down by the consensus. we should pick
|
||||
* it anyway, since the user asked for it. */
|
||||
router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT);
|
||||
router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
|
||||
if (router)
|
||||
break;
|
||||
smartlist_clear(supporting);
|
||||
smartlist_clear(use);
|
||||
}
|
||||
SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp));
|
||||
smartlist_free(needed_ports);
|
||||
smartlist_free(use);
|
||||
smartlist_free(supporting);
|
||||
}
|
||||
|
||||
|
@ -2834,10 +2822,11 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
|
|||
log_info(LD_CIRC, "Chose exit server '%s'", router->nickname);
|
||||
return router;
|
||||
}
|
||||
if (options->ExitNodes && options->StrictNodes) {
|
||||
if (options->ExitNodes) {
|
||||
log_warn(LD_CIRC,
|
||||
"No specified exit routers seem to be running, and "
|
||||
"StrictNodes is set: can't choose an exit.");
|
||||
"No specified %sexit routers seem to be running: "
|
||||
"can't choose an exit.",
|
||||
options->_ExcludeExitNodesUnion ? "non-excluded " : "");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2889,7 +2878,6 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
|
|||
or_options_t *options = get_options();
|
||||
routerset_t *rs = options->ExcludeNodes;
|
||||
const char *description;
|
||||
int domain = LD_CIRC;
|
||||
uint8_t purpose = circ->_base.purpose;
|
||||
|
||||
if (circ->build_state->onehop_tunnel)
|
||||
|
@ -2902,13 +2890,14 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
|
|||
case CIRCUIT_PURPOSE_INTRO_POINT:
|
||||
case CIRCUIT_PURPOSE_REND_POINT_WAITING:
|
||||
case CIRCUIT_PURPOSE_REND_ESTABLISHED:
|
||||
log_warn(LD_BUG, "Called on non-origin circuit (purpose %d)",
|
||||
(int)purpose);
|
||||
log_warn(LD_BUG, "Called on non-origin circuit (purpose %d, %s)",
|
||||
(int)purpose,
|
||||
circuit_purpose_to_string(purpose));
|
||||
return;
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
if (circ->build_state->is_internal)
|
||||
return;
|
||||
description = "Requested exit node";
|
||||
description = "requested exit node";
|
||||
rs = options->_ExcludeExitNodesUnion;
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
|
@ -2923,22 +2912,34 @@ warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
|
|||
case CIRCUIT_PURPOSE_C_REND_READY:
|
||||
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
|
||||
case CIRCUIT_PURPOSE_C_REND_JOINED:
|
||||
description = "Chosen rendezvous point";
|
||||
domain = LD_BUG;
|
||||
description = "chosen rendezvous point";
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_CONTROLLER:
|
||||
rs = options->_ExcludeExitNodesUnion;
|
||||
description = "Controller-selected circuit target";
|
||||
description = "controller-selected circuit target";
|
||||
break;
|
||||
}
|
||||
|
||||
if (routerset_contains_extendinfo(rs, exit)) {
|
||||
log_fn(LOG_WARN, domain, "%s '%s' is in ExcludeNodes%s. Using anyway "
|
||||
"(circuit purpose %d).",
|
||||
description,exit->nickname,
|
||||
rs==options->ExcludeNodes?"":" or ExcludeExitNodes",
|
||||
(int)purpose);
|
||||
circuit_log_path(LOG_WARN, domain, circ);
|
||||
/* We should never get here if StrictNodes is set to 1. */
|
||||
if (options->StrictNodes) {
|
||||
log_warn(LD_BUG, "Using %s '%s' which is listed in ExcludeNodes%s, "
|
||||
"even though StrictNodes is set. Please report. "
|
||||
"(Circuit purpose: %s)",
|
||||
description, exit->nickname,
|
||||
rs==options->ExcludeNodes?"":" or ExcludeExitNodes",
|
||||
circuit_purpose_to_string(purpose));
|
||||
} else {
|
||||
log_warn(LD_CIRC, "Using %s '%s' which is listed in "
|
||||
"ExcludeNodes%s, because no better options were available. To "
|
||||
"prevent this (and possibly break your Tor functionality), "
|
||||
"set the StrictNodes configuration option. "
|
||||
"(Circuit purpose: %s)",
|
||||
description, exit->nickname,
|
||||
rs==options->ExcludeNodes?"":" or ExcludeExitNodes",
|
||||
circuit_purpose_to_string(purpose));
|
||||
}
|
||||
circuit_log_path(LOG_WARN, LD_CIRC, circ);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -3979,7 +3980,8 @@ entry_guards_prepend_from_config(or_options_t *options)
|
|||
* Perhaps we should do this calculation once whenever the list of routers
|
||||
* changes or the entrynodes setting changes.
|
||||
*/
|
||||
routerset_get_all_routers(entry_routers, options->EntryNodes, 0);
|
||||
routerset_get_all_routers(entry_routers, options->EntryNodes,
|
||||
options->ExcludeNodes, 0);
|
||||
SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri,
|
||||
smartlist_add(entry_fps,ri->cache_info.identity_digest));
|
||||
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
|
||||
|
@ -4004,14 +4006,10 @@ entry_guards_prepend_from_config(or_options_t *options)
|
|||
SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, {
|
||||
add_an_entry_guard(ri, 0);
|
||||
});
|
||||
/* Finally, the remaining previously configured guards that are not in
|
||||
* EntryNodes, unless we're strict in which case we drop them */
|
||||
if (options->StrictNodes) {
|
||||
SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
|
||||
entry_guard_free(e));
|
||||
} else {
|
||||
smartlist_add_all(entry_guards, old_entry_guards_not_on_list);
|
||||
}
|
||||
/* Finally, free the remaining previously configured guards that are not in
|
||||
* EntryNodes. */
|
||||
SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
|
||||
entry_guard_free(e));
|
||||
|
||||
smartlist_free(entry_routers);
|
||||
smartlist_free(entry_fps);
|
||||
|
@ -4022,7 +4020,7 @@ entry_guards_prepend_from_config(or_options_t *options)
|
|||
|
||||
/** Return 0 if we're fine adding arbitrary routers out of the
|
||||
* directory to our entry guard list, or return 1 if we have a
|
||||
* list already and we'd prefer to stick to it.
|
||||
* list already and we must stick to it.
|
||||
*/
|
||||
int
|
||||
entry_list_is_constrained(or_options_t *options)
|
||||
|
@ -4034,18 +4032,6 @@ entry_list_is_constrained(or_options_t *options)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Are we dead set against changing our entry guard list, or would we
|
||||
* change it if it means keeping Tor usable? */
|
||||
static int
|
||||
entry_list_is_totally_static(or_options_t *options)
|
||||
{
|
||||
if (options->EntryNodes && options->StrictNodes)
|
||||
return 1;
|
||||
if (options->UseBridges)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Pick a live (up and listed) entry guard from entry_guards. If
|
||||
* <b>state</b> is non-NULL, this is for a specific circuit --
|
||||
* make sure not to pick this circuit's exit or any node in the
|
||||
|
@ -4090,6 +4076,7 @@ choose_random_entry(cpath_build_state_t *state)
|
|||
continue; /* don't pick the same node for entry and exit */
|
||||
if (consider_exit_family && smartlist_isin(exit_family, r))
|
||||
continue; /* avoid relays that are family members of our exit */
|
||||
#if 0 /* since EntryNodes is always strict now, this clause is moot */
|
||||
if (options->EntryNodes &&
|
||||
!routerset_contains_router(options->EntryNodes, r)) {
|
||||
/* We've come to the end of our preferred entry nodes. */
|
||||
|
@ -4104,6 +4091,7 @@ choose_random_entry(cpath_build_state_t *state)
|
|||
"No relays from EntryNodes available. Using others.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
smartlist_add(live_entry_guards, r);
|
||||
if (!entry->made_contact) {
|
||||
/* Always start with the first not-yet-contacted entry
|
||||
|
@ -4129,7 +4117,7 @@ choose_random_entry(cpath_build_state_t *state)
|
|||
}
|
||||
|
||||
if (smartlist_len(live_entry_guards) < preferred_min) {
|
||||
if (!entry_list_is_totally_static(options)) {
|
||||
if (!entry_list_is_constrained(options)) {
|
||||
/* still no? try adding a new entry then */
|
||||
/* XXX if guard doesn't imply fast and stable, then we need
|
||||
* to tell add_an_entry_guard below what we want, or it might
|
||||
|
@ -4154,13 +4142,18 @@ choose_random_entry(cpath_build_state_t *state)
|
|||
need_capacity = 0;
|
||||
goto retry;
|
||||
}
|
||||
#if 0
|
||||
/* Removing this retry logic: if we only allow one exit, and it is in the
|
||||
same family as all our entries, then we are just plain not going to win
|
||||
here. */
|
||||
if (!r && entry_list_is_constrained(options) && consider_exit_family) {
|
||||
/* still no? if we're using bridges or have strictentrynodes
|
||||
* set, and our chosen exit is in the same family as all our
|
||||
* bridges/entry guards, then be flexible about families. */
|
||||
/* still no? if we're using bridges,
|
||||
* and our chosen exit is in the same family as all our
|
||||
* bridges, then be flexible about families. */
|
||||
consider_exit_family = 0;
|
||||
goto retry;
|
||||
}
|
||||
#endif
|
||||
/* live_entry_guards may be empty below. Oh well, we tried. */
|
||||
}
|
||||
|
||||
|
@ -4561,6 +4554,24 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port, char *digest)
|
|||
smartlist_add(bridge_list, b);
|
||||
}
|
||||
|
||||
/** Return true iff <b>routerset</b> contains the bridge <b>bridge</b>. */
|
||||
static int
|
||||
routerset_contains_bridge(const routerset_t *routerset,
|
||||
const bridge_info_t *bridge)
|
||||
{
|
||||
int result;
|
||||
extend_info_t *extinfo;
|
||||
tor_assert(bridge);
|
||||
if (!routerset)
|
||||
return 0;
|
||||
|
||||
extinfo = extend_info_alloc(
|
||||
NULL, bridge->identity, NULL, &bridge->addr, bridge->port);
|
||||
result = routerset_contains_extendinfo(routerset, extinfo);
|
||||
extend_info_free(extinfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If <b>digest</b> is one of our known bridges, return it. */
|
||||
static bridge_info_t *
|
||||
find_bridge_by_digest(const char *digest)
|
||||
|
@ -4579,6 +4590,7 @@ static void
|
|||
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
|
||||
{
|
||||
char *address;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
if (connection_get_by_type_addr_port_purpose(
|
||||
CONN_TYPE_DIR, &bridge->addr, bridge->port,
|
||||
|
@ -4586,6 +4598,13 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
|
|||
return; /* it's already on the way */
|
||||
|
||||
address = tor_dup_addr(&bridge->addr);
|
||||
if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
|
||||
download_status_mark_impossible(&bridge->fetch_status);
|
||||
log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
|
||||
safe_str_client(fmt_addr(&bridge->addr)));
|
||||
return;
|
||||
}
|
||||
|
||||
directory_initiate_command(address, &bridge->addr,
|
||||
bridge->port, 0,
|
||||
0, /* does not matter */
|
||||
|
@ -4626,6 +4645,12 @@ fetch_bridge_descriptors(or_options_t *options, time_t now)
|
|||
if (!download_status_is_ready(&bridge->fetch_status, now,
|
||||
IMPOSSIBLE_TO_DOWNLOAD))
|
||||
continue; /* don't bother, no need to retry yet */
|
||||
if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
|
||||
download_status_mark_impossible(&bridge->fetch_status);
|
||||
log_warn(LD_APP, "Not using bridge at %s: it is in ExcludeNodes.",
|
||||
safe_str_client(fmt_addr(&bridge->addr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* schedule another fetch as if this one will fail, in case it does */
|
||||
download_status_failed(&bridge->fetch_status, 0);
|
||||
|
|
|
@ -378,6 +378,62 @@ circuit_purpose_to_controller_string(uint8_t purpose)
|
|||
}
|
||||
}
|
||||
|
||||
/** Return a human-readable string for the circuit purpose <b>purpose</b>. */
|
||||
const char *
|
||||
circuit_purpose_to_string(uint8_t purpose)
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
switch (purpose)
|
||||
{
|
||||
case CIRCUIT_PURPOSE_OR:
|
||||
return "Circuit at relay";
|
||||
case CIRCUIT_PURPOSE_INTRO_POINT:
|
||||
return "Acting as intro point";
|
||||
case CIRCUIT_PURPOSE_REND_POINT_WAITING:
|
||||
return "Acting as rendevous (pending)";
|
||||
case CIRCUIT_PURPOSE_REND_ESTABLISHED:
|
||||
return "Acting as rendevous (established)";
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
return "General-purpose client";
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
return "Hidden service client: Connecting to intro point";
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
|
||||
return "Hidden service client: Waiting for ack from intro point";
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
|
||||
return "Hidden service client: Received ack from intro point";
|
||||
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
|
||||
return "Hidden service client: Establishing rendezvous point";
|
||||
case CIRCUIT_PURPOSE_C_REND_READY:
|
||||
return "Hidden service client: Pending rendezvous point";
|
||||
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
|
||||
return "Hidden service client: Pending rendezvous point (ack received)";
|
||||
case CIRCUIT_PURPOSE_C_REND_JOINED:
|
||||
return "Hidden service client: Active rendezvous point";
|
||||
case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
|
||||
return "Measuring circuit timeout";
|
||||
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
return "Hidden service: Establishing introduction point";
|
||||
case CIRCUIT_PURPOSE_S_INTRO:
|
||||
return "Hidden service: Introduction point";
|
||||
case CIRCUIT_PURPOSE_S_CONNECT_REND:
|
||||
return "Hidden service: Connecting to rendezvous point";
|
||||
case CIRCUIT_PURPOSE_S_REND_JOINED:
|
||||
return "Hidden service: Active rendezvous point";
|
||||
|
||||
case CIRCUIT_PURPOSE_TESTING:
|
||||
return "Testing circuit";
|
||||
|
||||
case CIRCUIT_PURPOSE_CONTROLLER:
|
||||
return "Circuit made by controller";
|
||||
|
||||
default:
|
||||
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
/** Pick a reasonable package_window to start out for our circuits.
|
||||
* Originally this was hard-coded at 1000, but now the consensus votes
|
||||
* on the answer. See proposal 168. */
|
||||
|
@ -923,6 +979,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
|||
int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
|
||||
int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
|
||||
int internal = (flags & CIRCLAUNCH_IS_INTERNAL) != 0;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
/* Make sure we're not trying to create a onehop circ by
|
||||
* cannibalization. */
|
||||
|
@ -961,6 +1018,19 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
|||
hop=hop->next;
|
||||
} while (hop!=circ->cpath);
|
||||
}
|
||||
if (options->ExcludeNodes) {
|
||||
/* Make sure no existing nodes in the circuit are excluded for
|
||||
* general use. (This may be possible if StrictNodes is 0, and we
|
||||
* thought we needed to use an otherwise excluded node for, say, a
|
||||
* directory operation.) */
|
||||
crypt_path_t *hop = circ->cpath;
|
||||
do {
|
||||
if (routerset_contains_extendinfo(options->ExcludeNodes,
|
||||
hop->extend_info))
|
||||
goto next;
|
||||
hop = hop->next;
|
||||
} while (hop != circ->cpath);
|
||||
}
|
||||
if (!best || (best->build_state->need_uptime && !need_uptime))
|
||||
best = circ;
|
||||
next: ;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
circuit_t * _circuit_get_global_list(void);
|
||||
const char *circuit_state_to_string(int state);
|
||||
const char *circuit_purpose_to_controller_string(uint8_t purpose);
|
||||
const char *circuit_purpose_to_string(uint8_t purpose);
|
||||
void circuit_dump_by_conn(connection_t *conn, int severity);
|
||||
void circuit_set_p_circid_orconn(or_circuit_t *circ, circid_t id,
|
||||
or_connection_t *conn);
|
||||
|
|
|
@ -127,7 +127,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
if (exitrouter && !connection_ap_can_use_exit(conn, exitrouter, 0)) {
|
||||
if (exitrouter && !connection_ap_can_use_exit(conn, exitrouter)) {
|
||||
/* can't exit from this router */
|
||||
return 0;
|
||||
}
|
||||
|
@ -166,6 +166,10 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
|||
return 1;
|
||||
if (CIRCUIT_IS_ORIGIN(b) &&
|
||||
TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
|
||||
/* XXX023 what the heck is this internal thing doing here. I
|
||||
* think we can get rid of it. circuit_is_acceptable() already
|
||||
* makes sure that is_internal is exactly what we need it to
|
||||
* be. -RD */
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -242,33 +246,34 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
|
|||
return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Check whether, according to the policies in <b>options</b>, the
|
||||
* circuit <b>circ</b> makes sense. */
|
||||
/* XXXX currently only checks Exclude{Exit}Nodes. It should check more. */
|
||||
/* XXXX currently only checks Exclude{Exit}Nodes; it should check more.
|
||||
* Also, it doesn't have the right definition of an exit circuit. Also,
|
||||
* it's never called. */
|
||||
int
|
||||
circuit_conforms_to_options(const origin_circuit_t *circ,
|
||||
const or_options_t *options)
|
||||
{
|
||||
const crypt_path_t *cpath, *cpath_next = NULL;
|
||||
|
||||
for (cpath = circ->cpath; cpath && cpath_next != circ->cpath;
|
||||
cpath = cpath_next) {
|
||||
/* first check if it includes any excluded nodes */
|
||||
for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
|
||||
cpath_next = cpath->next;
|
||||
|
||||
if (routerset_contains_extendinfo(options->ExcludeNodes,
|
||||
cpath->extend_info))
|
||||
return 0;
|
||||
|
||||
if (cpath->next == circ->cpath) {
|
||||
/* This is apparently the exit node. */
|
||||
|
||||
if (routerset_contains_extendinfo(options->ExcludeExitNodes,
|
||||
cpath->extend_info))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* then consider the final hop */
|
||||
if (routerset_contains_extendinfo(options->ExcludeExitNodes,
|
||||
circ->cpath->prev->extend_info))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Close all circuits that start at us, aren't open, and were born
|
||||
* at least CircuitBuildTimeout seconds ago.
|
||||
|
@ -391,10 +396,11 @@ circuit_expire_building(void)
|
|||
TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN;
|
||||
|
||||
if (TO_ORIGIN_CIRCUIT(victim)->p_streams != NULL) {
|
||||
log_warn(LD_BUG, "Circuit %d (purpose %d) has timed out, "
|
||||
log_warn(LD_BUG, "Circuit %d (purpose %d, %s) has timed out, "
|
||||
"yet has attached streams!",
|
||||
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
|
||||
victim->purpose);
|
||||
victim->purpose,
|
||||
circuit_purpose_to_string(victim->purpose));
|
||||
tor_fragile_assert();
|
||||
continue;
|
||||
}
|
||||
|
@ -425,9 +431,10 @@ circuit_expire_building(void)
|
|||
if (timercmp(&victim->timestamp_created, &extremely_old_cutoff, <)) {
|
||||
log_notice(LD_CIRC,
|
||||
"Extremely large value for circuit build timeout: %lds. "
|
||||
"Assuming clock jump. Purpose %d",
|
||||
"Assuming clock jump. Purpose %d (%s)",
|
||||
(long)(now.tv_sec - victim->timestamp_created.tv_sec),
|
||||
victim->purpose);
|
||||
victim->purpose,
|
||||
circuit_purpose_to_string(victim->purpose));
|
||||
} else if (circuit_build_times_count_close(&circ_times,
|
||||
first_hop_succeeded,
|
||||
victim->timestamp_created.tv_sec)) {
|
||||
|
@ -508,7 +515,7 @@ circuit_stream_is_being_handled(edge_connection_t *conn,
|
|||
if (exitrouter && (!need_uptime || build_state->need_uptime)) {
|
||||
int ok;
|
||||
if (conn) {
|
||||
ok = connection_ap_can_use_exit(conn, exitrouter, 0);
|
||||
ok = connection_ap_can_use_exit(conn, exitrouter);
|
||||
} else {
|
||||
addr_policy_result_t r = compare_addr_to_addr_policy(
|
||||
0, port, exitrouter->exit_policy);
|
||||
|
@ -793,12 +800,11 @@ circuit_expire_old_circuits_clientside(void)
|
|||
circ->purpose != CIRCUIT_PURPOSE_S_INTRO) {
|
||||
log_notice(LD_CIRC,
|
||||
"Ancient non-dirty circuit %d is still around after "
|
||||
"%ld milliseconds. Purpose: %d",
|
||||
"%ld milliseconds. Purpose: %d (%s)",
|
||||
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
|
||||
tv_mdiff(&circ->timestamp_created, &now),
|
||||
circ->purpose);
|
||||
/* FFFF implement a new circuit_purpose_to_string() so we don't
|
||||
* just print out a number for circ->purpose */
|
||||
circ->purpose,
|
||||
circuit_purpose_to_string(circ->purpose));
|
||||
TO_ORIGIN_CIRCUIT(circ)->is_ancient = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1135,8 +1141,9 @@ circuit_launch_by_extend_info(uint8_t purpose,
|
|||
* internal circs rather than exit circs? -RD */
|
||||
circ = circuit_find_to_cannibalize(purpose, extend_info, flags);
|
||||
if (circ) {
|
||||
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
|
||||
build_state_get_exit_nickname(circ->build_state), purpose);
|
||||
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)",
|
||||
build_state_get_exit_nickname(circ->build_state), purpose,
|
||||
circuit_purpose_to_string(purpose));
|
||||
circ->_base.purpose = purpose;
|
||||
/* reset the birth date of this circ, else expire_building
|
||||
* will see it and think it's been trying to build since it
|
||||
|
@ -1288,9 +1295,10 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
|
|||
* refactor into a single function? */
|
||||
routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
|
||||
int opt = conn->chosen_exit_optional;
|
||||
if (router && !connection_ap_can_use_exit(conn, router, 0)) {
|
||||
if (router && !connection_ap_can_use_exit(conn, router)) {
|
||||
log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
|
||||
"Requested exit point '%s' would refuse request. %s.",
|
||||
"Requested exit point '%s' is excluded or "
|
||||
"would refuse request. %s.",
|
||||
conn->chosen_exit_name, opt ? "Trying others" : "Closing");
|
||||
if (opt) {
|
||||
conn->chosen_exit_optional = 0;
|
||||
|
@ -1401,7 +1409,18 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
|
|||
|
||||
extend_info_free(extend_info);
|
||||
|
||||
if (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
/* We just caused a circuit to get built because of this stream.
|
||||
* If this stream has caused a _lot_ of circuits to be built, that's
|
||||
* a bad sign: we should tell the user. */
|
||||
if (conn->num_circuits_launched < NUM_CIRCUITS_LAUNCHED_THRESHOLD &&
|
||||
++conn->num_circuits_launched == NUM_CIRCUITS_LAUNCHED_THRESHOLD)
|
||||
log_warn(LD_BUG, "The application request to %s:%d has launched "
|
||||
"%d circuits without finding one it likes.",
|
||||
escaped_safe_str_client(conn->socks_request->address),
|
||||
conn->socks_request->port,
|
||||
conn->num_circuits_launched);
|
||||
} else {
|
||||
/* help predict this next time */
|
||||
rep_hist_note_used_internal(time(NULL), need_uptime, 1);
|
||||
if (circ) {
|
||||
|
@ -1608,9 +1627,10 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
if (router && !connection_ap_can_use_exit(conn, router, 0)) {
|
||||
if (router && !connection_ap_can_use_exit(conn, router)) {
|
||||
log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP,
|
||||
"Requested exit point '%s' would refuse request. %s.",
|
||||
"Requested exit point '%s' is excluded or "
|
||||
"would refuse request. %s.",
|
||||
conn->chosen_exit_name, opt ? "Trying others" : "Closing");
|
||||
if (opt) {
|
||||
conn->chosen_exit_optional = 0;
|
||||
|
|
|
@ -16,8 +16,10 @@ void circuit_expire_building(void);
|
|||
void circuit_remove_handled_ports(smartlist_t *needed_ports);
|
||||
int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port,
|
||||
int min);
|
||||
#if 0
|
||||
int circuit_conforms_to_options(const origin_circuit_t *circ,
|
||||
const or_options_t *options);
|
||||
#endif
|
||||
void circuit_build_needed_circs(time_t now);
|
||||
void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
|
||||
|
||||
|
|
|
@ -1260,21 +1260,18 @@ options_act(or_options_t *old_options)
|
|||
/* Check for transitions that need action. */
|
||||
if (old_options) {
|
||||
if ((options->UseEntryGuards && !old_options->UseEntryGuards) ||
|
||||
(options->ExcludeNodes &&
|
||||
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes)) ||
|
||||
(options->ExcludeExitNodes &&
|
||||
!routerset_equal(old_options->ExcludeExitNodes,
|
||||
options->ExcludeExitNodes)) ||
|
||||
(options->EntryNodes &&
|
||||
!routerset_equal(old_options->EntryNodes, options->EntryNodes)) ||
|
||||
(options->ExitNodes &&
|
||||
!routerset_equal(old_options->ExitNodes, options->ExitNodes)) ||
|
||||
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes) ||
|
||||
!routerset_equal(old_options->ExcludeExitNodes,
|
||||
options->ExcludeExitNodes) ||
|
||||
!routerset_equal(old_options->EntryNodes, options->EntryNodes) ||
|
||||
!routerset_equal(old_options->ExitNodes, options->ExitNodes) ||
|
||||
options->StrictNodes != old_options->StrictNodes) {
|
||||
log_info(LD_CIRC,
|
||||
"Changed to using entry guards, or changed preferred or "
|
||||
"excluded node lists. Abandoning previous circuits.");
|
||||
circuit_mark_all_unused_circs();
|
||||
circuit_expire_all_dirty_circs();
|
||||
addressmap_clear_excluded_trackexithosts(options);
|
||||
}
|
||||
|
||||
/* How long should we delay counting bridge stats after becoming a bridge?
|
||||
|
@ -1412,7 +1409,8 @@ options_act(or_options_t *old_options)
|
|||
/* Check if we need to parse and add the EntryNodes config option. */
|
||||
if (options->EntryNodes &&
|
||||
(!old_options ||
|
||||
(!routerset_equal(old_options->EntryNodes,options->EntryNodes))))
|
||||
!routerset_equal(old_options->EntryNodes,options->EntryNodes) ||
|
||||
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes)))
|
||||
entry_nodes_should_be_added();
|
||||
|
||||
/* Since our options changed, we might need to regenerate and upload our
|
||||
|
@ -2500,54 +2498,6 @@ is_local_addr(const tor_addr_t *addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Called when we don't have a nickname set. Try to guess a good nickname
|
||||
* based on the hostname, and return it in a newly allocated string. If we
|
||||
* can't, return NULL and let the caller warn if it wants to. */
|
||||
static char *
|
||||
get_default_nickname(void)
|
||||
{
|
||||
static const char * const bad_default_nicknames[] = {
|
||||
"localhost",
|
||||
NULL,
|
||||
};
|
||||
char localhostname[256];
|
||||
char *cp, *out, *outp;
|
||||
int i;
|
||||
|
||||
if (gethostname(localhostname, sizeof(localhostname)) < 0)
|
||||
return NULL;
|
||||
|
||||
/* Put it in lowercase; stop at the first dot. */
|
||||
if ((cp = strchr(localhostname, '.')))
|
||||
*cp = '\0';
|
||||
tor_strlower(localhostname);
|
||||
|
||||
/* Strip invalid characters. */
|
||||
cp = localhostname;
|
||||
out = outp = tor_malloc(strlen(localhostname) + 1);
|
||||
while (*cp) {
|
||||
if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
|
||||
*outp++ = *cp++;
|
||||
else
|
||||
cp++;
|
||||
}
|
||||
*outp = '\0';
|
||||
|
||||
/* Enforce length. */
|
||||
if (strlen(out) > MAX_NICKNAME_LEN)
|
||||
out[MAX_NICKNAME_LEN]='\0';
|
||||
|
||||
/* Check for dumb names. */
|
||||
for (i = 0; bad_default_nicknames[i]; ++i) {
|
||||
if (!strcmp(out, bad_default_nicknames[i])) {
|
||||
tor_free(out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Release storage held by <b>options</b>. */
|
||||
static void
|
||||
config_free(config_format_t *fmt, void *options)
|
||||
|
@ -2976,14 +2926,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||
|
||||
if (options->Nickname == NULL) {
|
||||
if (server_mode(options)) {
|
||||
if (!(options->Nickname = get_default_nickname())) {
|
||||
log_notice(LD_CONFIG, "Couldn't pick a nickname based on "
|
||||
"our hostname; using %s instead.", UNNAMED_ROUTER_NICKNAME);
|
||||
options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME);
|
||||
} else {
|
||||
log_notice(LD_CONFIG, "Choosing default nickname '%s'",
|
||||
options->Nickname);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_legal_nickname(options->Nickname)) {
|
||||
|
@ -3243,6 +3186,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
|||
REJECT("Servers must be able to freely connect to the rest "
|
||||
"of the Internet, so they must not set UseBridges.");
|
||||
|
||||
/* If both of these are set, we'll end up with funny behavior where we
|
||||
* demand enough entrynodes be up and running else we won't build
|
||||
* circuits, yet we never actually use them. */
|
||||
if (options->UseBridges && options->EntryNodes)
|
||||
REJECT("You cannot set both UseBridges and EntryNodes.");
|
||||
|
||||
options->_AllowInvalid = 0;
|
||||
if (options->AllowInvalidNodes) {
|
||||
SMARTLIST_FOREACH(options->AllowInvalidNodes, const char *, cp, {
|
||||
|
@ -4382,11 +4331,13 @@ options_init_logs(or_options_t *options, int validate_only)
|
|||
if (smartlist_len(elts) == 2 &&
|
||||
!strcasecmp(smartlist_get(elts,0), "file")) {
|
||||
if (!validate_only) {
|
||||
if (add_file_log(severity, smartlist_get(elts, 1)) < 0) {
|
||||
char *fname = expand_filename(smartlist_get(elts, 1));
|
||||
if (add_file_log(severity, fname) < 0) {
|
||||
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
|
||||
opt->value, strerror(errno));
|
||||
ok = 0;
|
||||
}
|
||||
tor_free(fname);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
|
@ -799,6 +799,7 @@ clear_trackexithost_mappings(const char *exitname)
|
|||
tor_strlower(suffix);
|
||||
|
||||
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
|
||||
/* XXXX022 HEY! Shouldn't this look at ent->new_address? */
|
||||
if (ent->source == ADDRMAPSRC_TRACKEXIT && !strcmpend(address, suffix)) {
|
||||
addressmap_ent_remove(address, ent);
|
||||
MAP_DEL_CURRENT(address);
|
||||
|
@ -808,6 +809,56 @@ clear_trackexithost_mappings(const char *exitname)
|
|||
tor_free(suffix);
|
||||
}
|
||||
|
||||
/** Remove all TRACKEXIT mappings from the addressmap for which the target
|
||||
* host is unknown or no longer allowed. */
|
||||
void
|
||||
addressmap_clear_excluded_trackexithosts(or_options_t *options)
|
||||
{
|
||||
const routerset_t *allow_nodes = options->ExitNodes;
|
||||
const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion;
|
||||
|
||||
if (!addressmap)
|
||||
return;
|
||||
if (routerset_is_empty(allow_nodes))
|
||||
allow_nodes = NULL;
|
||||
if (allow_nodes == NULL && routerset_is_empty(exclude_nodes))
|
||||
return;
|
||||
|
||||
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
|
||||
size_t len;
|
||||
const char *target = ent->new_address, *dot;
|
||||
char *nodename;
|
||||
routerinfo_t *ri; /* XXX023 Use node_t. */
|
||||
|
||||
if (strcmpend(target, ".exit")) {
|
||||
/* Not a .exit mapping */
|
||||
continue;
|
||||
} else if (ent->source != ADDRMAPSRC_TRACKEXIT) {
|
||||
/* Not a trackexit mapping. */
|
||||
continue;
|
||||
}
|
||||
len = strlen(target);
|
||||
if (len < 6)
|
||||
continue; /* malformed. */
|
||||
dot = target + len - 6; /* dot now points to just before .exit */
|
||||
dot = strrchr(dot, '.'); /* dot now points to the . before .exit or NULL */
|
||||
if (!dot) {
|
||||
nodename = tor_strndup(target, len-5);
|
||||
} else {
|
||||
nodename = tor_strndup(dot+1, strlen(dot+1)-5);
|
||||
}
|
||||
ri = router_get_by_nickname(nodename, 0);
|
||||
tor_free(nodename);
|
||||
if (!ri ||
|
||||
(allow_nodes && !routerset_contains_router(allow_nodes, ri)) ||
|
||||
routerset_contains_router(exclude_nodes, ri)) {
|
||||
/* We don't know this one, or we want to be rid of it. */
|
||||
addressmap_ent_remove(address, ent);
|
||||
MAP_DEL_CURRENT(address);
|
||||
}
|
||||
} STRMAP_FOREACH_END;
|
||||
}
|
||||
|
||||
/** Remove all entries from the addressmap that were set via the
|
||||
* configuration file or the command line. */
|
||||
void
|
||||
|
@ -1494,9 +1545,13 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
|
|||
hostname_type_t addresstype;
|
||||
or_options_t *options = get_options();
|
||||
struct in_addr addr_tmp;
|
||||
/* We set this to true if this is an address we should automatically
|
||||
* remap to a local address in VirtualAddrNetwork */
|
||||
int automap = 0;
|
||||
char orig_address[MAX_SOCKS_ADDR_LEN];
|
||||
time_t map_expires = TIME_MAX;
|
||||
/* This will be set to true iff the address starts out as a non-.exit
|
||||
address, and we remap it to one because of an entry in the addressmap. */
|
||||
int remapped_to_exit = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
|
@ -1607,14 +1662,24 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
|
|||
/* foo.exit -- modify conn->chosen_exit_node to specify the exit
|
||||
* node, and conn->address to hold only the address portion. */
|
||||
char *s = strrchr(socks->address,'.');
|
||||
|
||||
/* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
|
||||
routerset_t *excludeset = options->StrictNodes ?
|
||||
options->_ExcludeExitNodesUnion : options->ExcludeExitNodes;
|
||||
/*XXX023 make this a node_t. */
|
||||
routerinfo_t *router;
|
||||
|
||||
tor_assert(!automap);
|
||||
if (s) {
|
||||
/* The address was of the form "(stuff).(name).exit */
|
||||
if (s[1] != '\0') {
|
||||
conn->chosen_exit_name = tor_strdup(s+1);
|
||||
router = router_get_by_nickname(conn->chosen_exit_name, 1);
|
||||
if (remapped_to_exit) /* 5 tries before it expires the addressmap */
|
||||
conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
|
||||
*s = 0;
|
||||
} else {
|
||||
/* Oops, the address was (stuff)..exit. That's not okay. */
|
||||
log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
|
||||
safe_str_client(socks->address));
|
||||
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
|
||||
|
@ -1623,20 +1688,33 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
|
|||
return -1;
|
||||
}
|
||||
} else {
|
||||
routerinfo_t *r;
|
||||
/* It looks like they just asked for "foo.exit". */
|
||||
conn->chosen_exit_name = tor_strdup(socks->address);
|
||||
r = router_get_by_nickname(conn->chosen_exit_name, 1);
|
||||
*socks->address = 0;
|
||||
if (r) {
|
||||
strlcpy(socks->address, r->address, sizeof(socks->address));
|
||||
} else {
|
||||
log_warn(LD_APP,
|
||||
"Unrecognized server in exit address '%s.exit'. Refusing.",
|
||||
safe_str_client(socks->address));
|
||||
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return -1;
|
||||
router = router_get_by_nickname(conn->chosen_exit_name, 1);
|
||||
if (router) {
|
||||
*socks->address = 0;
|
||||
strlcpy(socks->address, router->address, sizeof(socks->address));
|
||||
}
|
||||
}
|
||||
/* Now make sure that the chosen exit exists... */
|
||||
if (!router) {
|
||||
log_warn(LD_APP,
|
||||
"Unrecognized relay in exit address '%s.exit'. Refusing.",
|
||||
safe_str_client(socks->address));
|
||||
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return -1;
|
||||
}
|
||||
/* ...and make sure that it isn't excluded. */
|
||||
if (routerset_contains_router(excludeset, router)) {
|
||||
log_warn(LD_APP,
|
||||
"Excluded relay in exit address '%s.exit'. Refusing.",
|
||||
safe_str_client(socks->address));
|
||||
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
|
||||
return -1;
|
||||
}
|
||||
/* XXXX022-1090 Should we also allow foo.bar.exit if ExitNodes is set and
|
||||
Bar is not listed in it? I say yes, but our revised manpage branch
|
||||
implies no. */
|
||||
}
|
||||
|
||||
if (addresstype != ONION_HOSTNAME) {
|
||||
|
@ -2966,13 +3044,9 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn)
|
|||
* to exit from it, or 0 if it probably will not allow it.
|
||||
* (We might be uncertain if conn's destination address has not yet been
|
||||
* resolved.)
|
||||
*
|
||||
* If <b>excluded_means_no</b> is 1 and Exclude*Nodes is set and excludes
|
||||
* this relay, return 0.
|
||||
*/
|
||||
int
|
||||
connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit,
|
||||
int excluded_means_no)
|
||||
connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
|
||||
|
@ -3022,17 +3096,8 @@ connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit,
|
|||
return 0;
|
||||
}
|
||||
if (options->_ExcludeExitNodesUnion &&
|
||||
(options->StrictNodes || excluded_means_no) &&
|
||||
routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) {
|
||||
/* If we are trying to avoid this node as exit, and we have StrictNodes
|
||||
* set, then this is not a suitable exit. Refuse it.
|
||||
*
|
||||
* If we don't have StrictNodes set, then this function gets called in
|
||||
* two contexts. First, we've got a circuit open and we want to know
|
||||
* whether we can use it. In that case, we somehow built this circuit
|
||||
* despite having the last hop in ExcludeExitNodes, so we should be
|
||||
* willing to use it. Second, we are evaluating whether this is an
|
||||
* acceptable exit for a new circuit. In that case, skip it. */
|
||||
/* Not a suitable exit. Refuse it. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
|
|||
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
|
||||
void connection_exit_connect(edge_connection_t *conn);
|
||||
int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
|
||||
int connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit,
|
||||
int excluded_means_no);
|
||||
int connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit);
|
||||
void connection_ap_expire_beginning(void);
|
||||
void connection_ap_attach_pending(void);
|
||||
void connection_ap_fail_onehop(const char *failed_digest,
|
||||
|
@ -62,6 +61,7 @@ int connection_ap_process_transparent(edge_connection_t *conn);
|
|||
int address_is_invalid_destination(const char *address, int client);
|
||||
|
||||
void addressmap_init(void);
|
||||
void addressmap_clear_excluded_trackexithosts(or_options_t *options);
|
||||
void addressmap_clean(time_t now);
|
||||
void addressmap_clear_configured(void);
|
||||
void addressmap_clear_transient(void);
|
||||
|
|
|
@ -1222,7 +1222,9 @@ handle_control_signal(control_connection_t *conn, uint32_t len,
|
|||
/* Flush the "done" first if the signal might make us shut down. */
|
||||
if (sig == SIGTERM || sig == SIGINT)
|
||||
connection_handle_write(TO_CONN(conn), 1);
|
||||
control_signal_act(sig);
|
||||
|
||||
process_signal(sig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -253,10 +253,13 @@ directories_have_accepted_server_descriptor(void)
|
|||
}
|
||||
|
||||
/** Start a connection to every suitable directory authority, using
|
||||
* connection purpose 'purpose' and uploading the payload 'payload'
|
||||
* (length 'payload_len'). dir_purpose should be one of
|
||||
* connection purpose <b>dir_purpose</b> and uploading <b>payload</b>
|
||||
* (of length <b>payload_len</b>). The dir_purpose should be one of
|
||||
* 'DIR_PURPOSE_UPLOAD_DIR' or 'DIR_PURPOSE_UPLOAD_RENDDESC'.
|
||||
*
|
||||
* <b>router_purpose</b> describes the type of descriptor we're
|
||||
* publishing, if we're publishing a descriptor -- e.g. general or bridge.
|
||||
*
|
||||
* <b>type</b> specifies what sort of dir authorities (V1, V2,
|
||||
* HIDSERV, BRIDGE) we should upload to.
|
||||
*
|
||||
|
@ -272,6 +275,7 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
|||
const char *payload,
|
||||
size_t payload_len, size_t extrainfo_len)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
int post_via_tor;
|
||||
smartlist_t *dirservers = router_get_trusted_dir_servers();
|
||||
int found = 0;
|
||||
|
@ -287,6 +291,16 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
|
|||
if ((type & ds->type) == 0)
|
||||
continue;
|
||||
|
||||
if (options->ExcludeNodes && options->StrictNodes &&
|
||||
routerset_contains_routerstatus(options->ExcludeNodes, rs)) {
|
||||
log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but "
|
||||
"it's in our ExcludedNodes list and StrictNodes is set. "
|
||||
"Skipping.",
|
||||
ds->nickname,
|
||||
dir_conn_purpose_to_string(dir_purpose));
|
||||
continue;
|
||||
}
|
||||
|
||||
found = 1; /* at least one authority of this type was listed */
|
||||
if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR)
|
||||
ds->has_accepted_serverdesc = 0;
|
||||
|
@ -496,12 +510,14 @@ directory_initiate_command_routerstatus_rend(routerstatus_t *status,
|
|||
time_t if_modified_since,
|
||||
const rend_data_t *rend_query)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
routerinfo_t *router;
|
||||
char address_buf[INET_NTOA_BUF_LEN+1];
|
||||
struct in_addr in;
|
||||
const char *address;
|
||||
tor_addr_t addr;
|
||||
router = router_get_by_digest(status->identity_digest);
|
||||
|
||||
if (!router && anonymized_connection) {
|
||||
log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we "
|
||||
"don't have its router descriptor.", status->nickname);
|
||||
|
@ -514,6 +530,17 @@ directory_initiate_command_routerstatus_rend(routerstatus_t *status,
|
|||
address = address_buf;
|
||||
}
|
||||
tor_addr_from_ipv4h(&addr, status->addr);
|
||||
|
||||
if (options->ExcludeNodes && options->StrictNodes &&
|
||||
routerset_contains_routerstatus(options->ExcludeNodes, status)) {
|
||||
log_warn(LD_DIR, "Wanted to contact directory mirror '%s' for %s, but "
|
||||
"it's in our ExcludedNodes list and StrictNodes is set. "
|
||||
"Skipping. This choice might make your Tor not work.",
|
||||
status->nickname,
|
||||
dir_conn_purpose_to_string(dir_purpose));
|
||||
return;
|
||||
}
|
||||
|
||||
directory_initiate_command_rend(address, &addr,
|
||||
status->or_port, status->dir_port,
|
||||
status->version_supports_conditional_consensus,
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
MAX_V_LINE_LEN \
|
||||
)
|
||||
|
||||
#define UNNAMED_ROUTER_NICKNAME "Unnamed"
|
||||
#define UNNAMED_ROUTER_NICKNAME "Unnamed"
|
||||
|
||||
int connection_dirserv_flushed_some(dir_connection_t *conn);
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ dnsserv_resolved(edge_connection_t *conn,
|
|||
conn->socks_request->command == SOCKS_COMMAND_RESOLVE) {
|
||||
evdns_server_request_add_a_reply(req,
|
||||
name,
|
||||
1, (char*)answer, ttl);
|
||||
1, answer, ttl);
|
||||
} else if (answer_type == RESOLVED_TYPE_HOSTNAME &&
|
||||
answer_len < 256 &&
|
||||
conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) {
|
||||
|
|
|
@ -1668,7 +1668,7 @@ evdns_server_request_add_reply(struct evdns_server_request *_req, int section, c
|
|||
|
||||
/* exported function */
|
||||
int
|
||||
evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
|
||||
evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
|
||||
{
|
||||
return evdns_server_request_add_reply(
|
||||
req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
|
||||
|
@ -1677,7 +1677,7 @@ evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *n
|
|||
|
||||
/* exported function */
|
||||
int
|
||||
evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
|
||||
evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
|
||||
{
|
||||
return evdns_server_request_add_reply(
|
||||
req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
|
||||
|
|
|
@ -323,8 +323,8 @@ struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_re
|
|||
void evdns_close_server_port(struct evdns_server_port *port);
|
||||
|
||||
int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
|
||||
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
|
||||
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
|
||||
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
|
||||
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
|
||||
int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
|
||||
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ static void dumpmemusage(int severity);
|
|||
static void dumpstats(int severity); /* log stats */
|
||||
static void conn_read_callback(int fd, short event, void *_conn);
|
||||
static void conn_write_callback(int fd, short event, void *_conn);
|
||||
static void signal_callback(int fd, short events, void *arg);
|
||||
static void second_elapsed_callback(periodic_timer_t *timer, void *args);
|
||||
static int conn_close_if_marked(int i);
|
||||
static void connection_start_reading_from_linked_conn(connection_t *conn);
|
||||
|
@ -1577,46 +1576,6 @@ do_main_loop(void)
|
|||
}
|
||||
}
|
||||
|
||||
/** Used to implement the SIGNAL control command: if we accept
|
||||
* <b>the_signal</b> as a remote pseudo-signal, act on it. */
|
||||
/* We don't re-use catch() here because:
|
||||
* 1. We handle a different set of signals than those allowed in catch.
|
||||
* 2. Platforms without signal() are unlikely to define SIGfoo.
|
||||
* 3. The control spec is defined to use fixed numeric signal values
|
||||
* which just happen to match the Unix values.
|
||||
*/
|
||||
void
|
||||
control_signal_act(int the_signal)
|
||||
{
|
||||
switch (the_signal)
|
||||
{
|
||||
case 1:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGHUP);
|
||||
break;
|
||||
case 2:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGINT);
|
||||
break;
|
||||
case 10:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGUSR1);
|
||||
break;
|
||||
case 12:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGUSR2);
|
||||
break;
|
||||
case 15:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGTERM);
|
||||
break;
|
||||
case SIGNEWNYM:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGNEWNYM);
|
||||
break;
|
||||
case SIGCLEARDNSCACHE:
|
||||
signal_callback(0,0,(void*)(uintptr_t)SIGCLEARDNSCACHE);
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_BUG, "Unrecognized signal number %d.", the_signal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Libevent callback: invoked when we get a signal.
|
||||
*/
|
||||
static void
|
||||
|
@ -1625,6 +1584,14 @@ signal_callback(int fd, short events, void *arg)
|
|||
uintptr_t sig = (uintptr_t)arg;
|
||||
(void)fd;
|
||||
(void)events;
|
||||
|
||||
process_signal(sig);
|
||||
}
|
||||
|
||||
/** Do the work of acting on a signal received in <b>sig</b> */
|
||||
void
|
||||
process_signal(uintptr_t sig)
|
||||
{
|
||||
switch (sig)
|
||||
{
|
||||
case SIGTERM:
|
||||
|
|
|
@ -46,8 +46,8 @@ void directory_info_has_arrived(time_t now, int from_cache);
|
|||
void ip_address_changed(int at_interface);
|
||||
void dns_servers_relaunch_checks(void);
|
||||
|
||||
void control_signal_act(int the_signal);
|
||||
void handle_signals(int is_parent);
|
||||
void process_signal(uintptr_t sig);
|
||||
|
||||
int try_locking(or_options_t *options, int err_if_locked);
|
||||
int have_lockfile(void);
|
||||
|
|
13
src/or/or.h
13
src/or/or.h
|
@ -91,7 +91,7 @@
|
|||
#include "compat_libevent.h"
|
||||
#include "ht.h"
|
||||
|
||||
/* These signals are defined to help control_signal_act work.
|
||||
/* These signals are defined to help handle_control_signal work.
|
||||
*/
|
||||
#ifndef SIGHUP
|
||||
#define SIGHUP 1
|
||||
|
@ -1151,6 +1151,13 @@ typedef struct edge_connection_t {
|
|||
* already retried several times. */
|
||||
uint8_t num_socks_retries;
|
||||
|
||||
#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10
|
||||
/** Number of times we've launched a circuit to handle this stream. If
|
||||
* it gets too high, that could indicate an inconsistency between our
|
||||
* "launch a circuit to handle this stream" logic and our "attach our
|
||||
* stream to one of the available circuits" logic. */
|
||||
unsigned int num_circuits_launched:4;
|
||||
|
||||
/** True iff this connection is for a DNS request only. */
|
||||
unsigned int is_dns_request:1;
|
||||
|
||||
|
@ -2387,7 +2394,7 @@ typedef struct {
|
|||
* ORs not to consider as exits. */
|
||||
|
||||
/** Union of ExcludeNodes and ExcludeExitNodes */
|
||||
struct routerset_t *_ExcludeExitNodesUnion;
|
||||
routerset_t *_ExcludeExitNodesUnion;
|
||||
|
||||
int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our
|
||||
* process for all current and future memory. */
|
||||
|
@ -3487,7 +3494,7 @@ typedef struct trusted_dir_server_t {
|
|||
|
||||
#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX
|
||||
|
||||
/* Flags for pick_directory_server and pick_trusteddirserver. */
|
||||
/* Flags for pick_directory_server() and pick_trusteddirserver(). */
|
||||
/** Flag to indicate that we should not automatically be willing to use
|
||||
* ourself to answer a directory request.
|
||||
* Passed to router_pick_directory_server (et al).*/
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include "rephist.h"
|
||||
#include "routerlist.h"
|
||||
|
||||
static extend_info_t *rend_client_get_random_intro_impl(
|
||||
const rend_cache_entry_t *rend_query,
|
||||
const int strict, const int warnings);
|
||||
|
||||
/** Called when we've established a circuit to an introduction point:
|
||||
* send the introduction request. */
|
||||
void
|
||||
|
@ -559,7 +563,7 @@ rend_client_remove_intro_point(extend_info_t *failed_intro,
|
|||
}
|
||||
}
|
||||
|
||||
if (smartlist_len(ent->parsed->intro_nodes) == 0) {
|
||||
if (! rend_client_any_intro_points_usable(ent)) {
|
||||
log_info(LD_REND,
|
||||
"No more intro points remain for %s. Re-fetching descriptor.",
|
||||
escaped_safe_str_client(rend_query->onion_address));
|
||||
|
@ -705,7 +709,7 @@ rend_client_desc_trynow(const char *query)
|
|||
assert_connection_ok(TO_CONN(conn), now);
|
||||
if (rend_cache_lookup_entry(conn->rend_data->onion_address, -1,
|
||||
&entry) == 1 &&
|
||||
smartlist_len(entry->parsed->intro_nodes) > 0) {
|
||||
rend_client_any_intro_points_usable(entry)) {
|
||||
/* either this fetch worked, or it failed but there was a
|
||||
* valid entry from before which we should reuse */
|
||||
log_info(LD_REND,"Rend desc is usable. Launching circuits.");
|
||||
|
@ -739,24 +743,63 @@ rend_client_desc_trynow(const char *query)
|
|||
extend_info_t *
|
||||
rend_client_get_random_intro(const rend_data_t *rend_query)
|
||||
{
|
||||
int i;
|
||||
extend_info_t *result;
|
||||
rend_cache_entry_t *entry;
|
||||
rend_intro_point_t *intro;
|
||||
routerinfo_t *router;
|
||||
|
||||
if (rend_cache_lookup_entry(rend_query->onion_address, -1, &entry) < 1) {
|
||||
log_warn(LD_REND,
|
||||
"Query '%s' didn't have valid rend desc in cache. Failing.",
|
||||
safe_str_client(rend_query->onion_address));
|
||||
log_warn(LD_REND,
|
||||
"Query '%s' didn't have valid rend desc in cache. Failing.",
|
||||
safe_str_client(rend_query->onion_address));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
again:
|
||||
if (smartlist_len(entry->parsed->intro_nodes) == 0)
|
||||
return NULL;
|
||||
/* See if we can get a node that complies with ExcludeNodes */
|
||||
if ((result = rend_client_get_random_intro_impl(entry, 1, 1)))
|
||||
return result;
|
||||
/* If not, and StrictNodes is not set, see if we can return any old node
|
||||
*/
|
||||
if (!get_options()->StrictNodes)
|
||||
return rend_client_get_random_intro_impl(entry, 0, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes));
|
||||
intro = smartlist_get(entry->parsed->intro_nodes, i);
|
||||
/** As rend_client_get_random_intro, except assume that StrictNodes is set
|
||||
* iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain
|
||||
* to the user when we're out of nodes, even if StrictNodes is true.
|
||||
*/
|
||||
static extend_info_t *
|
||||
rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
|
||||
const int strict,
|
||||
const int warnings)
|
||||
{
|
||||
int i;
|
||||
|
||||
rend_intro_point_t *intro;
|
||||
routerinfo_t *router;
|
||||
or_options_t *options = get_options();
|
||||
smartlist_t *usable_nodes;
|
||||
int n_excluded = 0;
|
||||
|
||||
/* We'll keep a separate list of the usable nodes. If this becomes empty,
|
||||
* no nodes are usable. */
|
||||
usable_nodes = smartlist_create();
|
||||
smartlist_add_all(usable_nodes, entry->parsed->intro_nodes);
|
||||
|
||||
again:
|
||||
if (smartlist_len(usable_nodes) == 0) {
|
||||
if (n_excluded && get_options()->StrictNodes && warnings) {
|
||||
/* We only want to warn if StrictNodes is really set. Otherwise
|
||||
* we're just about to retry anyways.
|
||||
*/
|
||||
log_warn(LD_REND, "All introduction points for hidden service are "
|
||||
"at excluded relays, and StrictNodes is set. Skipping.");
|
||||
}
|
||||
smartlist_free(usable_nodes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = crypto_rand_int(smartlist_len(usable_nodes));
|
||||
intro = smartlist_get(usable_nodes, i);
|
||||
/* Do we need to look up the router or is the extend info complete? */
|
||||
if (!intro->extend_info->onion_key) {
|
||||
if (tor_digest_is_zero(intro->extend_info->identity_digest))
|
||||
|
@ -766,16 +809,34 @@ rend_client_get_random_intro(const rend_data_t *rend_query)
|
|||
if (!router) {
|
||||
log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
|
||||
intro->extend_info->nickname);
|
||||
rend_intro_point_free(intro);
|
||||
smartlist_del(entry->parsed->intro_nodes, i);
|
||||
smartlist_del(usable_nodes, i);
|
||||
goto again;
|
||||
}
|
||||
extend_info_free(intro->extend_info);
|
||||
intro->extend_info = extend_info_from_router(router);
|
||||
}
|
||||
/* Check if we should refuse to talk to this router. */
|
||||
if (options->ExcludeNodes && strict &&
|
||||
routerset_contains_extendinfo(options->ExcludeNodes,
|
||||
intro->extend_info)) {
|
||||
n_excluded++;
|
||||
smartlist_del(usable_nodes, i);
|
||||
goto again;
|
||||
}
|
||||
|
||||
smartlist_free(usable_nodes);
|
||||
return extend_info_dup(intro->extend_info);
|
||||
}
|
||||
|
||||
/** Return true iff any introduction points still listed in <b>entry</b> are
|
||||
* usable. */
|
||||
int
|
||||
rend_client_any_intro_points_usable(const rend_cache_entry_t *entry)
|
||||
{
|
||||
return rend_client_get_random_intro_impl(
|
||||
entry, get_options()->StrictNodes, 0) != NULL;
|
||||
}
|
||||
|
||||
/** Client-side authorizations for hidden services; map of onion address to
|
||||
* rend_service_authorization_t*. */
|
||||
static strmap_t *auth_hid_servs = NULL;
|
||||
|
|
|
@ -29,6 +29,7 @@ int rend_client_receive_rendezvous(origin_circuit_t *circ,
|
|||
void rend_client_desc_trynow(const char *query);
|
||||
|
||||
extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query);
|
||||
int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry);
|
||||
|
||||
int rend_client_send_introduction(origin_circuit_t *introcirc,
|
||||
origin_circuit_t *rendcirc);
|
||||
|
|
|
@ -934,7 +934,7 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
|
|||
tor_assert((*e)->parsed && (*e)->parsed->intro_nodes);
|
||||
/* XXX023 hack for now, to return "not found" if there are no intro
|
||||
* points remaining. See bug 997. */
|
||||
if (smartlist_len((*e)->parsed->intro_nodes) == 0)
|
||||
if (! rend_client_any_intro_points_usable(*e))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -848,6 +848,7 @@ clean_accepted_intros(rend_service_t *service, time_t now)
|
|||
/** Respond to an INTRODUCE2 cell by launching a circuit to the chosen
|
||||
* rendezvous point.
|
||||
*/
|
||||
/* XXX022 this function sure could use some organizing. -RD */
|
||||
int
|
||||
rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
|
||||
size_t request_len)
|
||||
|
@ -875,6 +876,8 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
|
|||
time_t now = time(NULL);
|
||||
char diffie_hellman_hash[DIGEST_LEN];
|
||||
time_t *access_time;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
tor_assert(circuit->rend_data);
|
||||
|
||||
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
|
||||
|
@ -1047,6 +1050,15 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* Check if we'd refuse to talk to this router */
|
||||
if (options->ExcludeNodes && options->StrictNodes &&
|
||||
routerset_contains_extendinfo(options->ExcludeNodes, extend_info)) {
|
||||
log_warn(LD_REND, "Client asked to rendezvous at a relay that we "
|
||||
"exclude, and StrictNodes is set. Refusing service.");
|
||||
reason = END_CIRC_REASON_INTERNAL; /* XXX might leak why we refused */
|
||||
goto err;
|
||||
}
|
||||
|
||||
r_cookie = ptr;
|
||||
base16_encode(hexcookie,9,r_cookie,4);
|
||||
|
||||
|
@ -1335,14 +1347,26 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
|
|||
}
|
||||
|
||||
/* If we already have enough introduction circuits for this service,
|
||||
* redefine this one as a general circuit. */
|
||||
* redefine this one as a general circuit or close it, depending. */
|
||||
if (count_established_intro_points(serviceid) > NUM_INTRO_POINTS) {
|
||||
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
|
||||
"circuit, but we already have enough. Redefining purpose to "
|
||||
"general.");
|
||||
TO_CIRCUIT(circuit)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
|
||||
circuit_has_opened(circuit);
|
||||
return;
|
||||
or_options_t *options = get_options();
|
||||
if (options->ExcludeNodes) {
|
||||
/* XXXX in some future version, we can test whether the transition is
|
||||
allowed or not given the actual nodes in the circuit. But for now,
|
||||
this case, we might as well close the thing. */
|
||||
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
|
||||
"circuit, but we already have enough. Closing it.");
|
||||
circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_REASON_NONE);
|
||||
return;
|
||||
} else {
|
||||
tor_assert(circuit->build_state->is_internal);
|
||||
log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
|
||||
"circuit, but we already have enough. Redefining purpose to "
|
||||
"general; leaving as internal.");
|
||||
TO_CIRCUIT(circuit)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
|
||||
circuit_has_opened(circuit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log_info(LD_REND,
|
||||
|
@ -1394,7 +1418,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
|
|||
|
||||
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
|
||||
* live introduction point, and note that the service descriptor is
|
||||
* now out-of-date.*/
|
||||
* now out-of-date. */
|
||||
int
|
||||
rend_service_intro_established(origin_circuit_t *circuit,
|
||||
const uint8_t *request,
|
||||
|
|
|
@ -992,10 +992,10 @@ find_next_with(smartlist_t *sl, int i, const char *prefix)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/** How many bad times has parse_possibly_bad_iso_time parsed? */
|
||||
/** How many bad times has parse_possibly_bad_iso_time() parsed? */
|
||||
static int n_bogus_times = 0;
|
||||
/** Parse the ISO-formatted time in <b>s</b> into *<b>time_out</b>, but
|
||||
* rounds any pre-1970 date to Jan 1, 1970. */
|
||||
* round any pre-1970 date to Jan 1, 1970. */
|
||||
static int
|
||||
parse_possibly_bad_iso_time(const char *s, time_t *time_out)
|
||||
{
|
||||
|
@ -1288,7 +1288,7 @@ commit_max(bw_array_t *b)
|
|||
b->total_in_period = 0;
|
||||
}
|
||||
|
||||
/** Shift the current observation time of 'b' forward by one second. */
|
||||
/** Shift the current observation time of <b>b</b> forward by one second. */
|
||||
static INLINE void
|
||||
advance_obs(bw_array_t *b)
|
||||
{
|
||||
|
@ -1318,16 +1318,16 @@ advance_obs(bw_array_t *b)
|
|||
static INLINE void
|
||||
add_obs(bw_array_t *b, time_t when, uint64_t n)
|
||||
{
|
||||
/* Don't record data in the past. */
|
||||
if (when<b->cur_obs_time)
|
||||
return;
|
||||
if (when < b->cur_obs_time)
|
||||
return; /* Don't record data in the past. */
|
||||
|
||||
/* If we're currently adding observations for an earlier second than
|
||||
* 'when', advance b->cur_obs_time and b->cur_obs_idx by an
|
||||
* appropriate number of seconds, and do all the other housekeeping */
|
||||
while (when>b->cur_obs_time) {
|
||||
* appropriate number of seconds, and do all the other housekeeping. */
|
||||
while (when > b->cur_obs_time) {
|
||||
/* Doing this one second at a time is potentially inefficient, if we start
|
||||
with a state file that is very old. Fortunately, it doesn't seem to
|
||||
show up in profiles, so we can just ignore it for now. */
|
||||
show up in profiles, so we can just ignore it for now. */
|
||||
advance_obs(b);
|
||||
}
|
||||
|
||||
|
@ -1375,7 +1375,7 @@ bw_arrays_init(void)
|
|||
dir_write_array = bw_array_new();
|
||||
}
|
||||
|
||||
/** We read <b>num_bytes</b> more bytes in second <b>when</b>.
|
||||
/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
|
||||
*
|
||||
* Add num_bytes to the current running total for <b>when</b>.
|
||||
*
|
||||
|
@ -1396,7 +1396,7 @@ rep_hist_note_bytes_written(size_t num_bytes, time_t when)
|
|||
add_obs(write_array, when, num_bytes);
|
||||
}
|
||||
|
||||
/** We wrote <b>num_bytes</b> more bytes in second <b>when</b>.
|
||||
/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
|
||||
* (like rep_hist_note_bytes_written() above)
|
||||
*/
|
||||
void
|
||||
|
@ -1406,8 +1406,8 @@ rep_hist_note_bytes_read(size_t num_bytes, time_t when)
|
|||
add_obs(read_array, when, num_bytes);
|
||||
}
|
||||
|
||||
/** We wrote <b>num_bytes</b> more directory bytes in second <b>when</b>.
|
||||
* (like rep_hist_note_bytes_written() above)
|
||||
/** Remember that we wrote <b>num_bytes</b> directory bytes in second
|
||||
* <b>when</b>. (like rep_hist_note_bytes_written() above)
|
||||
*/
|
||||
void
|
||||
rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when)
|
||||
|
@ -1415,8 +1415,8 @@ rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when)
|
|||
add_obs(dir_write_array, when, num_bytes);
|
||||
}
|
||||
|
||||
/** We read <b>num_bytes</b> more directory bytes in second <b>when</b>.
|
||||
* (like rep_hist_note_bytes_written() above)
|
||||
/** Remember that we read <b>num_bytes</b> directory bytes in second
|
||||
* <b>when</b>. (like rep_hist_note_bytes_written() above)
|
||||
*/
|
||||
void
|
||||
rep_hist_note_dir_bytes_read(size_t num_bytes, time_t when)
|
||||
|
@ -1511,7 +1511,8 @@ rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
|
|||
}
|
||||
|
||||
/** Allocate and return lines for representing this server's bandwidth
|
||||
* history in its descriptor.
|
||||
* history in its descriptor. We publish these lines in our extra-info
|
||||
* descriptor.
|
||||
*/
|
||||
char *
|
||||
rep_hist_get_bandwidth_lines(void)
|
||||
|
@ -1559,7 +1560,7 @@ rep_hist_get_bandwidth_lines(void)
|
|||
}
|
||||
|
||||
/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
|
||||
* entries of an or_state_t. */
|
||||
* entries of an or_state_t. Done before writing out a new state file. */
|
||||
static void
|
||||
rep_hist_update_bwhist_state_section(or_state_t *state,
|
||||
const bw_array_t *b,
|
||||
|
@ -1570,6 +1571,7 @@ rep_hist_update_bwhist_state_section(or_state_t *state,
|
|||
{
|
||||
char *cp;
|
||||
int i,j;
|
||||
uint64_t maxval;
|
||||
|
||||
if (*s_values) {
|
||||
SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
|
||||
|
@ -1603,7 +1605,6 @@ rep_hist_update_bwhist_state_section(or_state_t *state,
|
|||
/* Set i to first position in circular array */
|
||||
i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
|
||||
for (j=0; j < b->num_maxes_set; ++j,++i) {
|
||||
uint64_t maxval;
|
||||
if (i >= NUM_TOTALS)
|
||||
i = 0;
|
||||
tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(b->totals[i] & ~0x3ff));
|
||||
|
@ -1614,11 +1615,13 @@ rep_hist_update_bwhist_state_section(or_state_t *state,
|
|||
}
|
||||
tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(b->total_in_period & ~0x3ff));
|
||||
smartlist_add(*s_values, cp);
|
||||
tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(b->max_total & ~0x3ff));
|
||||
maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
|
||||
tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(maxval & ~0x3ff));
|
||||
smartlist_add(*s_maxima, cp);
|
||||
}
|
||||
|
||||
/** Update <b>state</b> with the newest bandwidth history. */
|
||||
/** Update <b>state</b> with the newest bandwidth history. Done before
|
||||
* writing out a new state file. */
|
||||
void
|
||||
rep_hist_update_state(or_state_t *state)
|
||||
{
|
||||
|
@ -1642,7 +1645,7 @@ rep_hist_update_state(or_state_t *state)
|
|||
}
|
||||
|
||||
/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
|
||||
* entries in an or_state_t. */
|
||||
* entries in an or_state_t. Done while reading the state file. */
|
||||
static int
|
||||
rep_hist_load_bwhist_state_section(bw_array_t *b,
|
||||
const smartlist_t *s_values,
|
||||
|
@ -1717,7 +1720,7 @@ rep_hist_load_bwhist_state_section(bw_array_t *b,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/** Set bandwidth history from our saved state. */
|
||||
/** Set bandwidth history from the state file we just loaded. */
|
||||
int
|
||||
rep_hist_load_state(or_state_t *state, char **err)
|
||||
{
|
||||
|
@ -1765,7 +1768,7 @@ static smartlist_t *predicted_ports_times=NULL;
|
|||
static void
|
||||
add_predicted_port(time_t now, uint16_t port)
|
||||
{
|
||||
/* XXXX we could just use uintptr_t here, I think. */
|
||||
/* XXXX we could just use uintptr_t here, I think. -NM */
|
||||
uint16_t *tmp_port = tor_malloc(sizeof(uint16_t));
|
||||
time_t *tmp_time = tor_malloc(sizeof(time_t));
|
||||
*tmp_port = port;
|
||||
|
|
|
@ -850,9 +850,29 @@ consider_testing_reachability(int test_or, int test_dir)
|
|||
routerinfo_t *me = router_get_my_routerinfo();
|
||||
int orport_reachable = check_whether_orport_reachable();
|
||||
tor_addr_t addr;
|
||||
or_options_t *options = get_options();
|
||||
if (!me)
|
||||
return;
|
||||
|
||||
if (routerset_contains_router(options->ExcludeNodes, me) &&
|
||||
options->StrictNodes) {
|
||||
/* If we've excluded ourself, and StrictNodes is set, we can't test
|
||||
* ourself. */
|
||||
if (test_or || test_dir) {
|
||||
#define SELF_EXCLUDED_WARN_INTERVAL 3600
|
||||
static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
|
||||
char *msg;
|
||||
if ((msg = rate_limit_log(&warning_limit, approx_time()))) {
|
||||
log_warn(LD_CIRC, "Can't peform self-tests for this relay: we have "
|
||||
"listed ourself in ExcludeNodes, and StrictNodes is set. "
|
||||
"We cannot learn whether we are usable, and will not "
|
||||
"be able to advertise ourself.%s", msg);
|
||||
tor_free(msg);
|
||||
}
|
||||
}
|
||||
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",
|
||||
|
|
|
@ -531,8 +531,8 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
|
|||
if (!found &&
|
||||
download_status_is_ready(&cl->dl_status, now,MAX_CERT_DL_FAILURES) &&
|
||||
!digestmap_get(pending, ds->v3_identity_digest)) {
|
||||
log_notice(LD_DIR, "No current certificate known for authority %s; "
|
||||
"launching request.", ds->nickname);
|
||||
log_info(LD_DIR, "No current certificate known for authority %s; "
|
||||
"launching request.", ds->nickname);
|
||||
smartlist_add(missing_digests, ds->v3_identity_digest);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ds);
|
||||
|
@ -1070,6 +1070,7 @@ router_pick_trusteddirserver(authority_type_t type, int flags)
|
|||
static routerstatus_t *
|
||||
router_pick_directory_server_impl(authority_type_t type, int flags)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
routerstatus_t *result;
|
||||
smartlist_t *direct, *tunnel;
|
||||
smartlist_t *trusted_direct, *trusted_tunnel;
|
||||
|
@ -1079,10 +1080,13 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
|
|||
int requireother = ! (flags & PDS_ALLOW_SELF);
|
||||
int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
|
||||
int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
|
||||
int try_excluding = 1, n_excluded = 0;
|
||||
|
||||
if (!consensus)
|
||||
return NULL;
|
||||
|
||||
retry_without_exclude:
|
||||
|
||||
direct = smartlist_create();
|
||||
tunnel = smartlist_create();
|
||||
trusted_direct = smartlist_create();
|
||||
|
@ -1114,6 +1118,11 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
|
|||
if ((type & EXTRAINFO_CACHE) &&
|
||||
!router_supports_extrainfo(status->identity_digest, 0))
|
||||
continue;
|
||||
if (try_excluding && options->ExcludeNodes &&
|
||||
routerset_contains_routerstatus(options->ExcludeNodes, status)) {
|
||||
++n_excluded;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXXX IP6 proposal 118 */
|
||||
tor_addr_from_ipv4h(&addr, status->addr);
|
||||
|
@ -1155,6 +1164,15 @@ router_pick_directory_server_impl(authority_type_t type, int flags)
|
|||
smartlist_free(trusted_tunnel);
|
||||
smartlist_free(overloaded_direct);
|
||||
smartlist_free(overloaded_tunnel);
|
||||
|
||||
if (result == NULL && try_excluding && !options->StrictNodes && n_excluded) {
|
||||
/* If we got no result, and we are excluding nodes, and StrictNodes is
|
||||
* not set, try again without excluding nodes. */
|
||||
try_excluding = 0;
|
||||
n_excluded = 0;
|
||||
goto retry_without_exclude;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1165,6 +1183,7 @@ static routerstatus_t *
|
|||
router_pick_trusteddirserver_impl(authority_type_t type, int flags,
|
||||
int *n_busy_out)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
smartlist_t *direct, *tunnel;
|
||||
smartlist_t *overloaded_direct, *overloaded_tunnel;
|
||||
routerinfo_t *me = router_get_my_routerinfo();
|
||||
|
@ -1175,10 +1194,13 @@ router_pick_trusteddirserver_impl(authority_type_t type, int flags,
|
|||
const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS);
|
||||
const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
|
||||
int n_busy = 0;
|
||||
int try_excluding = 1, n_excluded = 0;
|
||||
|
||||
if (!trusted_dir_servers)
|
||||
return NULL;
|
||||
|
||||
retry_without_exclude:
|
||||
|
||||
direct = smartlist_create();
|
||||
tunnel = smartlist_create();
|
||||
overloaded_direct = smartlist_create();
|
||||
|
@ -1197,6 +1219,12 @@ router_pick_trusteddirserver_impl(authority_type_t type, int flags,
|
|||
continue;
|
||||
if (requireother && me && router_digest_is_me(d->digest))
|
||||
continue;
|
||||
if (try_excluding && options->ExcludeNodes &&
|
||||
routerset_contains_routerstatus(options->ExcludeNodes,
|
||||
&d->fake_status)) {
|
||||
++n_excluded;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXXX IP6 proposal 118 */
|
||||
tor_addr_from_ipv4h(&addr, d->addr);
|
||||
|
@ -1243,6 +1271,15 @@ router_pick_trusteddirserver_impl(authority_type_t type, int flags,
|
|||
smartlist_free(tunnel);
|
||||
smartlist_free(overloaded_direct);
|
||||
smartlist_free(overloaded_tunnel);
|
||||
|
||||
if (result == NULL && try_excluding && !options->StrictNodes && n_excluded) {
|
||||
/* If we got no result, and we are excluding nodes, and StrictNodes is
|
||||
* not set, try again without excluding nodes. */
|
||||
try_excluding = 0;
|
||||
n_excluded = 0;
|
||||
goto retry_without_exclude;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1501,6 +1538,8 @@ routerlist_find_my_routerinfo(void)
|
|||
/** Find a router that's up, that has this IP address, and
|
||||
* that allows exit to this address:port, or return NULL if there
|
||||
* isn't a good one.
|
||||
* Don't exit enclave to excluded relays -- it wouldn't actually
|
||||
* hurt anything, but this way there are fewer confused users.
|
||||
*/
|
||||
routerinfo_t *
|
||||
router_find_exact_exit_enclave(const char *address, uint16_t port)
|
||||
|
@ -1508,6 +1547,7 @@ router_find_exact_exit_enclave(const char *address, uint16_t port)
|
|||
uint32_t addr;
|
||||
struct in_addr in;
|
||||
tor_addr_t a;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
if (!tor_inet_aton(address, &in))
|
||||
return NULL; /* it's not an IP already */
|
||||
|
@ -1520,7 +1560,8 @@ router_find_exact_exit_enclave(const char *address, uint16_t port)
|
|||
if (router->addr == addr &&
|
||||
router->is_running &&
|
||||
compare_tor_addr_to_addr_policy(&a, port, router->exit_policy) ==
|
||||
ADDR_POLICY_ACCEPTED)
|
||||
ADDR_POLICY_ACCEPTED &&
|
||||
!routerset_contains_router(options->_ExcludeExitNodesUnion, router))
|
||||
return router;
|
||||
});
|
||||
return NULL;
|
||||
|
@ -5433,7 +5474,7 @@ routerset_needs_geoip(const routerset_t *set)
|
|||
}
|
||||
|
||||
/** Return true iff there are no entries in <b>set</b>. */
|
||||
static int
|
||||
int
|
||||
routerset_is_empty(const routerset_t *set)
|
||||
{
|
||||
return !set || smartlist_len(set->list) == 0;
|
||||
|
@ -5516,10 +5557,11 @@ routerset_contains_routerstatus(const routerset_t *set, routerstatus_t *rs)
|
|||
}
|
||||
|
||||
/** Add every known routerinfo_t that is a member of <b>routerset</b> to
|
||||
* <b>out</b>. If <b>running_only</b>, only add the running ones. */
|
||||
* <b>out</b>, but never add any that are part of <b>excludeset</b>.
|
||||
* If <b>running_only</b>, only add the running ones. */
|
||||
void
|
||||
routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
|
||||
int running_only)
|
||||
const routerset_t *excludeset, int running_only)
|
||||
{
|
||||
tor_assert(out);
|
||||
if (!routerset || !routerset->list)
|
||||
|
@ -5529,12 +5571,13 @@ routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
|
|||
if (routerset_is_list(routerset)) {
|
||||
|
||||
/* No routers are specified by type; all are given by name or digest.
|
||||
* we can do a lookup in O(len(list)). */
|
||||
* we can do a lookup in O(len(routerset)). */
|
||||
SMARTLIST_FOREACH(routerset->list, const char *, name, {
|
||||
routerinfo_t *router = router_get_by_nickname(name, 1);
|
||||
if (router) {
|
||||
if (!running_only || router->is_running)
|
||||
smartlist_add(out, router);
|
||||
if (!routerset_contains_router(excludeset, router))
|
||||
smartlist_add(out, router);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -5544,12 +5587,14 @@ routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
|
|||
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, {
|
||||
if (running_only && !router->is_running)
|
||||
continue;
|
||||
if (routerset_contains_router(routerset, router))
|
||||
if (routerset_contains_router(routerset, router) &&
|
||||
!routerset_contains_router(excludeset, router))
|
||||
smartlist_add(out, router);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Add to <b>target</b> every routerinfo_t from <b>source</b> except:
|
||||
*
|
||||
* 1) Don't add it if <b>include</b> is non-empty and the relay isn't in
|
||||
|
@ -5580,6 +5625,7 @@ routersets_get_disjunction(smartlist_t *target,
|
|||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Remove every routerinfo_t from <b>lst</b> that is in <b>routerset</b>. */
|
||||
void
|
||||
|
@ -5611,10 +5657,15 @@ routerset_to_string(const routerset_t *set)
|
|||
int
|
||||
routerset_equal(const routerset_t *old, const routerset_t *new)
|
||||
{
|
||||
if (old == NULL && new == NULL)
|
||||
if (routerset_is_empty(old) && routerset_is_empty(new)) {
|
||||
/* Two empty sets are equal */
|
||||
return 1;
|
||||
else if (old == NULL || new == NULL)
|
||||
} else if (routerset_is_empty(old) || routerset_is_empty(new)) {
|
||||
/* An empty set is equal to nothing else. */
|
||||
return 0;
|
||||
}
|
||||
tor_assert(old != NULL);
|
||||
tor_assert(new != NULL);
|
||||
|
||||
if (smartlist_len(old->list) != smartlist_len(new->list))
|
||||
return 0;
|
||||
|
|
|
@ -167,16 +167,20 @@ int routerset_parse(routerset_t *target, const char *s,
|
|||
void routerset_union(routerset_t *target, const routerset_t *source);
|
||||
int routerset_is_list(const routerset_t *set);
|
||||
int routerset_needs_geoip(const routerset_t *set);
|
||||
int routerset_is_empty(const routerset_t *set);
|
||||
int routerset_contains_router(const routerset_t *set, routerinfo_t *ri);
|
||||
int routerset_contains_routerstatus(const routerset_t *set,
|
||||
routerstatus_t *rs);
|
||||
int routerset_contains_extendinfo(const routerset_t *set,
|
||||
const extend_info_t *ei);
|
||||
void routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset,
|
||||
const routerset_t *excludeset,
|
||||
int running_only);
|
||||
#if 0
|
||||
void routersets_get_disjunction(smartlist_t *target, const smartlist_t *source,
|
||||
const routerset_t *include,
|
||||
const routerset_t *exclude, int running_only);
|
||||
#endif
|
||||
void routerset_subtract_routers(smartlist_t *out,
|
||||
const routerset_t *routerset);
|
||||
char *routerset_to_string(const routerset_t *routerset);
|
||||
|
|
Loading…
Reference in New Issue