Merge branch 'maint-0.2.2' into release-0.2.2

This commit is contained in:
Roger Dingledine 2011-04-27 14:06:19 -04:00
commit 984a6bfeb8
34 changed files with 788 additions and 330 deletions

73
changes/bug1090-general Normal file
View File

@ -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.

View File

@ -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.

5
changes/bug2704 Normal file
View File

@ -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.

4
changes/bug2899 Normal file
View File

@ -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.

4
changes/bug2917 Normal file
View File

@ -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.

6
changes/bug2971 Normal file
View File

@ -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.

9
changes/bug2979 Normal file
View File

@ -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.

View File

@ -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.)

View File

@ -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

View File

@ -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);

View File

@ -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: ;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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,

View File

@ -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);

View File

@ -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) {

View File

@ -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,

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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).*/

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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);