aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug1090-general73
-rw-r--r--changes/bug1090-launch-warning5
-rw-r--r--changes/bug24755
-rw-r--r--changes/bug27045
-rw-r--r--changes/bug2704_part15
-rw-r--r--changes/bug2704_part25
-rw-r--r--changes/bug272211
-rw-r--r--changes/bug27506
-rw-r--r--changes/bug28994
-rw-r--r--changes/bug29174
-rw-r--r--changes/bug29334
-rw-r--r--changes/bug29487
-rw-r--r--changes/bug29716
-rw-r--r--changes/bug29799
-rw-r--r--changes/bug30207
-rw-r--r--changes/clear_trackexithost5
-rw-r--r--changes/exitnodes_reliable7
-rw-r--r--changes/forget-rend-descs-on-newnym21
-rw-r--r--changes/gmtime_null6
-rw-r--r--changes/microdesc-double-free7
-rw-r--r--changes/ticket24974
-rw-r--r--doc/tor.1.txt76
-rw-r--r--src/common/address.c2
-rw-r--r--src/common/compat.c112
-rw-r--r--src/common/compat.h9
-rw-r--r--src/common/crypto.c2
-rw-r--r--src/common/torint.h4
-rw-r--r--src/or/circuitbuild.c186
-rw-r--r--src/or/circuitlist.c70
-rw-r--r--src/or/circuitlist.h1
-rw-r--r--src/or/circuituse.c102
-rw-r--r--src/or/circuituse.h2
-rw-r--r--src/or/config.c87
-rw-r--r--src/or/connection_edge.c119
-rw-r--r--src/or/connection_edge.h4
-rw-r--r--src/or/control.c4
-rw-r--r--src/or/directory.c31
-rw-r--r--src/or/dnsserv.c2
-rw-r--r--src/or/eventdns.c6
-rw-r--r--src/or/eventdns.h4
-rw-r--r--src/or/hibernate.c3
-rw-r--r--src/or/main.c58
-rw-r--r--src/or/main.h2
-rw-r--r--src/or/or.h13
-rw-r--r--src/or/rendclient.c264
-rw-r--r--src/or/rendclient.h2
-rw-r--r--src/or/rendcommon.c12
-rw-r--r--src/or/rendcommon.h1
-rw-r--r--src/or/rendservice.c40
-rw-r--r--src/or/rephist.c84
-rw-r--r--src/or/router.c28
-rw-r--r--src/or/routerlist.c83
-rw-r--r--src/or/routerlist.h4
-rw-r--r--src/or/routerparse.c11
-rw-r--r--src/test/test_addr.c4
55 files changed, 1194 insertions, 444 deletions
diff --git a/changes/bug1090-general b/changes/bug1090-general
new file mode 100644
index 000000000..465631592
--- /dev/null
+++ b/changes/bug1090-general
@@ -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.
+
diff --git a/changes/bug1090-launch-warning b/changes/bug1090-launch-warning
new file mode 100644
index 000000000..3f3fbcb4d
--- /dev/null
+++ b/changes/bug1090-launch-warning
@@ -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.
diff --git a/changes/bug2475 b/changes/bug2475
new file mode 100644
index 000000000..d6f0595a5
--- /dev/null
+++ b/changes/bug2475
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Avoid signed/unsigned comparisons by making SIZE_T_CEILING unsigned.
+ (None of the cases where we did this before were wrong, but by making
+ this change we can avoid warnings.) Fixes bug2475; bugfix on
+ Tor 0.2.1.28.
diff --git a/changes/bug2704 b/changes/bug2704
new file mode 100644
index 000000000..821b38bc0
--- /dev/null
+++ b/changes/bug2704
@@ -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.
+
diff --git a/changes/bug2704_part1 b/changes/bug2704_part1
new file mode 100644
index 000000000..eaf22812c
--- /dev/null
+++ b/changes/bug2704_part1
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Fix an issue causing calculation of Tor's average bandwidth as saved
+ in the state file to be 10 times smaller than it should be. Fixes the
+ first part of bug 2704, bugfix on tor-0.2.2.23-alpha.
+
diff --git a/changes/bug2704_part2 b/changes/bug2704_part2
new file mode 100644
index 000000000..962c8b709
--- /dev/null
+++ b/changes/bug2704_part2
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Prevent relays that read their bandwidth history from their state file
+ from arbitrarily inflating that value. Fixes the second half of bug
+ 2704, bugfix on tor-0.2.2.23-alpha.
+
diff --git a/changes/bug2722 b/changes/bug2722
new file mode 100644
index 000000000..ed132fc89
--- /dev/null
+++ b/changes/bug2722
@@ -0,0 +1,11 @@
+ o Minor bugfixes
+ - Ignore the TunnelDirConns option when determining which HSDir
+ relays are responsible for a hidden service descriptor ID.
+ Currently, clients and hidden services with TunnelDirConns off
+ will skip over HSDir relays which do not advertise a DirPort
+ when making a list of HSDirs responsible for a descriptor ID,
+ even though they would never try to use a HSDir's DirPort to
+ upload or fetch a hidden service descriptor. Fixes bug 2722;
+ bugfix on 0.2.1.6-alpha.
+
+
diff --git a/changes/bug2750 b/changes/bug2750
new file mode 100644
index 000000000..4371a0a4e
--- /dev/null
+++ b/changes/bug2750
@@ -0,0 +1,6 @@
+ o Minor bugfixes
+ - Correct the warning displayed when a rendezvous descriptor exceeds
+ the maximum size. Fixes bug 2750; bugfix on 0.2.1.5-alpha. Found
+ by John Brooks.
+
+
diff --git a/changes/bug2899 b/changes/bug2899
new file mode 100644
index 000000000..6af86d067
--- /dev/null
+++ b/changes/bug2899
@@ -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.
+
diff --git a/changes/bug2917 b/changes/bug2917
new file mode 100644
index 000000000..6b1e64334
--- /dev/null
+++ b/changes/bug2917
@@ -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.
+
diff --git a/changes/bug2933 b/changes/bug2933
new file mode 100644
index 000000000..7aaf52611
--- /dev/null
+++ b/changes/bug2933
@@ -0,0 +1,4 @@
+ o Minor bugfixes
+ - Fix an uncommon assertion failure when running with DNSPort under
+ heavy load. Fixes bug 2933; bugfix on 2.0.1-alpha.
+
diff --git a/changes/bug2948 b/changes/bug2948
new file mode 100644
index 000000000..640ef625d
--- /dev/null
+++ b/changes/bug2948
@@ -0,0 +1,7 @@
+ o Minor bugfixes
+ - Only limit the lengths of single HS descriptors, even when
+ multiple HS descriptors are published to an HSDir relay in a
+ single POST operation. Fixes bug 2948; bugfix on 0.2.1.5-alpha.
+ Found by hsdir.
+
+
diff --git a/changes/bug2971 b/changes/bug2971
new file mode 100644
index 000000000..8b71ce040
--- /dev/null
+++ b/changes/bug2971
@@ -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.
+
diff --git a/changes/bug2979 b/changes/bug2979
new file mode 100644
index 000000000..fe1f45fe0
--- /dev/null
+++ b/changes/bug2979
@@ -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.
+
diff --git a/changes/bug3020 b/changes/bug3020
new file mode 100644
index 000000000..b98716122
--- /dev/null
+++ b/changes/bug3020
@@ -0,0 +1,7 @@
+ o Minor bugfixes:
+ - When checking whether a hibernation period has fully elapsed, use
+ the amount of seconds we expect for that period instead of using
+ the new period that just started. This would cause an issue because
+ February is a really short month. Bugfix on 0.2.2.17-alpha;
+ fixes bug 3020.
+
diff --git a/changes/clear_trackexithost b/changes/clear_trackexithost
new file mode 100644
index 000000000..b9ac6fec4
--- /dev/null
+++ b/changes/clear_trackexithost
@@ -0,0 +1,5 @@
+ o Minor bugfixes:
+ - Fix a bug in the code where we could keep trying to use a
+ TrackHostExits-based mapping after we failed to reach the intended
+ destination node. Fixes bug 2999. Bugfix on 0.2.0.20-rc.
+
diff --git a/changes/exitnodes_reliable b/changes/exitnodes_reliable
new file mode 100644
index 000000000..62ef03a0c
--- /dev/null
+++ b/changes/exitnodes_reliable
@@ -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.)
diff --git a/changes/forget-rend-descs-on-newnym b/changes/forget-rend-descs-on-newnym
new file mode 100644
index 000000000..da7afbe20
--- /dev/null
+++ b/changes/forget-rend-descs-on-newnym
@@ -0,0 +1,21 @@
+ o Security fixes:
+ - Forget all hidden service descriptors cached as a client when
+ processing a SIGNAL NEWNYM command. Fixes bug 3000. Bugfix on
+ 0.0.6.
+ o Major bugfixes:
+ - When we find that we have extended a hidden service's introduction
+ circuit to a relay which isn't listed as an introduction point in
+ the HS descriptor we currently have for the service, we now retry
+ one of the introduction points in the current HS descriptor.
+ Previously we would just give up. Bugfix on 0.2.0.10-alpha; fixes
+ bugs 1024 and 1930.
+ o Minor bugfixes:
+ - Don't allow v0 hidden service authorities to act as clients.
+ Required by fix for bug 3000.
+ - Ignore SIGNAL NEWNYM commands on relay-only Tor instances.
+ Required by fix for bug 3000.
+ o Code simplifications and refactoring:
+ - Allow rend_client_send_introduction to fail without closing the
+ AP connection permanently.
+
+
diff --git a/changes/gmtime_null b/changes/gmtime_null
new file mode 100644
index 000000000..16a25408b
--- /dev/null
+++ b/changes/gmtime_null
@@ -0,0 +1,6 @@
+ o Minor bugfixes
+ - On some platforms, gmtime and localtime can return NULL under
+ certain circumstances even for well-defined values of time_t.
+ Try to detect and make up for this deficiency. Possible fix for
+ bug 2077. Bugfix on all versions of Tor. Found by boboper.
+
diff --git a/changes/microdesc-double-free b/changes/microdesc-double-free
new file mode 100644
index 000000000..932cc754b
--- /dev/null
+++ b/changes/microdesc-double-free
@@ -0,0 +1,7 @@
+ o Security fixes:
+ - Don't double-free a parsable, but invalid, microdescriptor, even
+ if it is followed in the blob we're parsing by an unparsable
+ microdescriptor. Fixes an issue reported in a comment on bug 2954.
+ Bugfix on 0.2.2.6-alpha; fix by "cypherpunks".
+
+
diff --git a/changes/ticket2497 b/changes/ticket2497
new file mode 100644
index 000000000..51171412b
--- /dev/null
+++ b/changes/ticket2497
@@ -0,0 +1,4 @@
+ o Minor features:
+ - Ensure that no empty [dirreq-](read|write)-history lines are added
+ to an extrainfo document. Implements ticket 2497.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index f1734d201..04a053771 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -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
diff --git a/src/common/address.c b/src/common/address.c
index adc0ef0f7..aff517ca5 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -604,7 +604,7 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_t *addr_out,
if (family == AF_INET6 && v4map) {
if (bits > 32 && bits < 96) { /* Crazy */
log_warn(LD_GENERAL,
- "Bad mask bits %i for V4-mapped V6 address; rejecting.",
+ "Bad mask bits %d for V4-mapped V6 address; rejecting.",
bits);
goto err;
}
diff --git a/src/common/compat.c b/src/common/compat.c
index 27489e568..3644bd999 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1996,14 +1996,88 @@ tor_gettimeofday(struct timeval *timeval)
#define TIME_FNS_NEED_LOCKS
#endif
+static struct tm *
+correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
+ struct tm *r)
+{
+ const char *outcome;
+
+ if (PREDICT_LIKELY(r)) {
+ if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */
+ r->tm_year = 8099;
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ }
+ return r;
+ }
+
+ /* If we get here, gmtime or localtime returned NULL. It might have done
+ * this because of overrun or underrun, or it might have done it because of
+ * some other weird issue. */
+ if (timep) {
+ if (*timep < 0) {
+ r = resultbuf;
+ r->tm_year = 70; /* 1970 CE */
+ r->tm_mon = 0;
+ r->tm_mday = 1;
+ r->tm_yday = 1;
+ r->tm_hour = 0;
+ r->tm_min = 0 ;
+ r->tm_sec = 0;
+ outcome = "Rounding up to 1970";
+ goto done;
+ } else if (*timep >= INT32_MAX) {
+ /* Rounding down to INT32_MAX isn't so great, but keep in mind that we
+ * only do it if gmtime/localtime tells us NULL. */
+ r = resultbuf;
+ r->tm_year = 137; /* 2037 CE */
+ r->tm_mon = 11;
+ r->tm_mday = 31;
+ r->tm_yday = 365;
+ r->tm_hour = 23;
+ r->tm_min = 59;
+ r->tm_sec = 59;
+ outcome = "Rounding down to 2037";
+ goto done;
+ }
+ }
+
+ /* If we get here, then gmtime/localtime failed without getting an extreme
+ * value for *timep */
+
+ tor_fragile_assert();
+ r = resultbuf;
+ memset(resultbuf, 0, sizeof(struct tm));
+ outcome="can't recover";
+ done:
+ log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s",
+ islocal?"localtime":"gmtime",
+ timep?I64_PRINTF_ARG(*timep):0,
+ strerror(errno),
+ outcome);
+ return r;
+}
+
+
/** @{ */
/** As localtime_r, but defined for platforms that don't have it:
*
* Convert *<b>timep</b> to a struct tm in local time, and store the value in
* *<b>result</b>. Return the result on success, or NULL on failure.
*/
-#ifndef HAVE_LOCALTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+#ifdef HAVE_LOCALTIME_R
+struct tm *
+tor_localtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = localtime_r(timep, result);
+ return correct_tm(1, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_localtime_r(const time_t *timep, struct tm *result)
{
@@ -2013,9 +2087,10 @@ tor_localtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(1, timep, result, r);
}
#else
struct tm *
@@ -2024,11 +2099,11 @@ tor_localtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = localtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(1, timep, result, r);
}
#endif
-#endif
/** @} */
/** @{ */
@@ -2037,8 +2112,15 @@ tor_localtime_r(const time_t *timep, struct tm *result)
* Convert *<b>timep</b> to a struct tm in UTC, and store the value in
* *<b>result</b>. Return the result on success, or NULL on failure.
*/
-#ifndef HAVE_GMTIME_R
-#ifdef TIME_FNS_NEED_LOCKS
+#ifdef HAVE_GMTIME_R
+struct tm *
+tor_gmtime_r(const time_t *timep, struct tm *result)
+{
+ struct tm *r;
+ r = gmtime_r(timep, result);
+ return correct_tm(0, timep, result, r);
+}
+#elif defined(TIME_FNS_NEED_LOCKS)
struct tm *
tor_gmtime_r(const time_t *timep, struct tm *result)
{
@@ -2048,9 +2130,10 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
tor_assert(result);
tor_mutex_acquire(m);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
- return result;
+ return correct_tm(0, timep, result, r);
}
#else
struct tm *
@@ -2059,12 +2142,11 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
struct tm *r;
tor_assert(result);
r = gmtime(timep);
- memcpy(result, r, sizeof(struct tm));
- return result;
+ if (r)
+ memcpy(result, r, sizeof(struct tm));
+ return correct_tm(0, timep, result, r);
}
#endif
-#endif
-/** @} */
#if defined(USE_WIN32_THREADS)
void
diff --git a/src/common/compat.h b/src/common/compat.h
index 550c08b53..af795ffba 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -321,17 +321,8 @@ struct timeval {
void tor_gettimeofday(struct timeval *timeval);
-#ifdef HAVE_LOCALTIME_R
-#define tor_localtime_r localtime_r
-#else
struct tm *tor_localtime_r(const time_t *timep, struct tm *result);
-#endif
-
-#ifdef HAVE_GMTIME_R
-#define tor_gmtime_r gmtime_r
-#else
struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
-#endif
#ifndef timeradd
/** Replacement for timeradd on platforms that do not have it: sets tvout to
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 2ef40c29c..8d17a3dae 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -523,7 +523,7 @@ crypto_pk_read_private_key_from_string(crypto_pk_env_t *env,
tor_assert(env);
tor_assert(s);
- tor_assert(len < INT_MAX && len < SIZE_T_CEILING);
+ tor_assert(len < INT_MAX && len < SSIZE_T_CEILING);
/* Create a read-only memory BIO, backed by the string 's' */
b = BIO_new_mem_buf((char*)s, (int)len);
diff --git a/src/common/torint.h b/src/common/torint.h
index f5bebf8b9..0b5c29adc 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -329,8 +329,10 @@ typedef uint32_t uintptr_t;
#endif
#endif
+/** Any ssize_t larger than this amount is likely to be an underflow. */
+#define SSIZE_T_CEILING ((ssize_t)(SSIZE_T_MAX-16))
/** Any size_t larger than this amount is likely to be an underflow. */
-#define SIZE_T_CEILING (SSIZE_T_MAX-16)
+#define SIZE_T_CEILING ((size_t)(SSIZE_T_MAX-16))
#endif /* __TORINT_H */
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 2d4d5c032..fe9426455 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -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; /* user asked us not to use it, no matter what */
+ }
+ if (options->ExitNodes &&
+ !routerset_contains_router(options->ExitNodes, 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; /* 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)
@@ -4573,12 +4584,12 @@ find_bridge_by_digest(const char *digest)
return NULL;
}
-/** We need to ask <b>bridge</b> for its server descriptor. <b>address</b>
- * is a helpful string describing this bridge. */
+/** We need to ask <b>bridge</b> for its server descriptor. */
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 +4597,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 +4644,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);
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index d11b45794..33dc8f09a 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -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: ;
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index ef6fc3a3d..7b01ca3ae 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -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);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index cdf49e398..fbe2e459a 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -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. */
+ /* then consider the final hop */
+ if (routerset_contains_extendinfo(options->ExcludeExitNodes,
+ circ->cpath->prev->extend_info))
+ return 0;
- if (routerset_contains_extendinfo(options->ExcludeExitNodes,
- cpath->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,12 +431,13 @@ 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)) {
+ first_hop_succeeded,
+ victim->timestamp_created.tv_sec)) {
circuit_build_times_set_timeout(&circ_times);
}
}
@@ -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);
@@ -763,7 +770,8 @@ circuit_expire_old_circuits_clientside(void)
* on it, mark it for close.
*/
if (circ->timestamp_dirty &&
- circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now.tv_sec &&
+ circ->timestamp_dirty + get_options()->MaxCircuitDirtiness <
+ now.tv_sec &&
!TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %ld sec ago, "
"purpose %d)",
@@ -793,12 +801,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 +1142,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 +1296,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 +1410,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 +1628,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;
@@ -1723,14 +1744,21 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
"introduction. (stream %d sec old)",
introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
conn_age);
- if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
+ switch (rend_client_send_introduction(introcirc, rendcirc)) {
+ case 0: /* success */
+ rendcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->_base.timestamp_dirty = time(NULL);
+ assert_circuit_ok(TO_CIRCUIT(rendcirc));
+ assert_circuit_ok(TO_CIRCUIT(introcirc));
+ return 0;
+ case -1: /* transient error */
+ return 0;
+ case -2: /* permanent error */
+ return -1;
+ default: /* oops */
+ tor_fragile_assert();
return -1;
}
- rendcirc->_base.timestamp_dirty = time(NULL);
- introcirc->_base.timestamp_dirty = time(NULL);
- assert_circuit_ok(TO_CIRCUIT(rendcirc));
- assert_circuit_ok(TO_CIRCUIT(introcirc));
- return 0;
}
}
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index a121099ac..9f393ab37 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -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);
diff --git a/src/or/config.c b/src/or/config.c
index 5000f5d60..9384b3a68 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -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)) {
@@ -3135,6 +3078,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("FetchDirInfoExtraEarly requires that you also set "
"FetchDirInfoEarly");
+ if (options->HSAuthoritativeDir && proxy_mode(options))
+ REJECT("Running as authoritative v0 HS directory, but also configured "
+ "as a client.");
+
if (options->ConnLimit <= 0) {
tor_asprintf(msg,
"ConnLimit must be greater than 0, but was set to %d",
@@ -3243,6 +3190,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 +4335,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;
}
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 72e2c8a40..2c1196c0c 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -799,7 +799,8 @@ clear_trackexithost_mappings(const char *exitname)
tor_strlower(suffix);
STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) {
- if (ent->source == ADDRMAPSRC_TRACKEXIT && !strcmpend(address, suffix)) {
+ if (ent->source == ADDRMAPSRC_TRACKEXIT &&
+ !strcmpend(ent->new_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;
}
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 0b08dd07c..70d0dd271 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -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);
diff --git a/src/or/control.c b/src/or/control.c
index 8f3af0bda..9f7739a40 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -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;
}
diff --git a/src/or/directory.c b/src/or/directory.c
index 8f33a608d..0c095fe87 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -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,
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index f7a8d35f7..243b730cb 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -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) {
diff --git a/src/or/eventdns.c b/src/or/eventdns.c
index 8b679f898..cf583d068 100644
--- a/src/or/eventdns.c
+++ b/src/or/eventdns.c
@@ -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,
@@ -1904,7 +1904,7 @@ server_request_free(struct server_request *req)
if (req->port) {
if (req->port->pending_replies == req) {
- if (req->next_pending)
+ if (req->next_pending && req->next_pending != req)
req->port->pending_replies = req->next_pending;
else
req->port->pending_replies = NULL;
diff --git a/src/or/eventdns.h b/src/or/eventdns.h
index bf3b64d08..2fe4ac937 100644
--- a/src/or/eventdns.h
+++ b/src/or/eventdns.h
@@ -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);
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 1878d5d52..aebce4cc8 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -378,7 +378,8 @@ configure_accounting(time_t now)
/* We are in the interval we thought we were in. Do nothing.*/
interval_end_time = start_of_accounting_period_after(interval_start_time);
} else {
- long duration = length_of_accounting_period_containing(now);
+ long duration =
+ length_of_accounting_period_containing(interval_start_time);
double delta = ((double)(s_now - interval_start_time)) / duration;
if (-0.50 <= delta && delta <= 0.50) {
/* The start of the period is now a little later or earlier than we
diff --git a/src/or/main.c b/src/or/main.c
index 83d1e1e51..a26be39fd 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -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);
@@ -843,8 +842,17 @@ run_connection_housekeeping(int i, time_t now)
static void
signewnym_impl(time_t now)
{
+ or_options_t *options = get_options();
+ if (!proxy_mode(options)) {
+ log_info(LD_CONTROL, "Ignoring SIGNAL NEWNYM because client functionality "
+ "is disabled.");
+ return;
+ }
+
circuit_expire_all_dirty_circs();
addressmap_clear_transient();
+ rend_cache_purge();
+ rend_client_cancel_descriptor_fetches();
time_of_last_signewnym = now;
signewnym_is_pending = 0;
}
@@ -1577,46 +1585,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 +1593,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:
diff --git a/src/or/main.h b/src/or/main.h
index ed0fb9770..0551f7aaf 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -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);
diff --git a/src/or/or.h b/src/or/or.h
index 1688a08f9..7d354c8fe 100644
--- a/src/or/or.h
+++ b/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).*/
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 8ac909fc8..8d024d8eb 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -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
@@ -62,6 +66,50 @@ rend_client_send_establish_rendezvous(origin_circuit_t *circ)
return 0;
}
+/** Extend the introduction circuit <b>circ</b> to another valid
+ * introduction point for the hidden service it is trying to connect
+ * to, or mark it and launch a new circuit if we can't extend it.
+ * Return 0 on success. Return -1 and mark the introduction
+ * circuit on failure.
+ *
+ * On failure, the caller is responsible for marking the associated
+ * rendezvous circuit for close. */
+static int
+rend_client_reextend_intro_circuit(origin_circuit_t *circ)
+{
+ extend_info_t *extend_info;
+ int result;
+ extend_info = rend_client_get_random_intro(circ->rend_data);
+ if (!extend_info) {
+ log_warn(LD_REND,
+ "No usable introduction points left for %s. Closing.",
+ safe_str_client(circ->rend_data->onion_address));
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ return -1;
+ }
+ if (circ->remaining_relay_early_cells) {
+ log_info(LD_REND,
+ "Re-extending circ %d, this time to %s.",
+ circ->_base.n_circ_id, extend_info->nickname);
+ result = circuit_extend_to_new_exit(circ, extend_info);
+ } else {
+ log_info(LD_REND,
+ "Building a new introduction circuit, this time to %s.",
+ extend_info->nickname);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
+ if (!circuit_launch_by_extend_info(CIRCUIT_PURPOSE_C_INTRODUCING,
+ extend_info,
+ CIRCLAUNCH_IS_INTERNAL)) {
+ log_warn(LD_REND, "Building introduction circuit failed.");
+ result = -1;
+ } else {
+ result = 0;
+ }
+ }
+ extend_info_free(extend_info);
+ return result;
+}
+
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
* down introcirc if possible.
*/
@@ -87,13 +135,25 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
&entry) < 1) {
- log_warn(LD_REND,
- "query %s didn't have valid rend desc in cache. Failing.",
- escaped_safe_str_client(introcirc->rend_data->onion_address));
- goto err;
+ log_info(LD_REND,
+ "query %s didn't have valid rend desc in cache. "
+ "Refetching descriptor.",
+ safe_str_client(introcirc->rend_data->onion_address));
+ rend_client_refetch_v2_renddesc(introcirc->rend_data);
+ {
+ connection_t *conn;
+
+ while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
+ AP_CONN_STATE_CIRCUIT_WAIT,
+ introcirc->rend_data->onion_address))) {
+ conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+ }
+ }
+
+ return -1;
}
- /* first 20 bytes of payload are the hash of the intro key */
+ /* first 20 bytes of payload are the hash of Bob's pk */
intro_key = NULL;
SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
intro, {
@@ -104,15 +164,22 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
}
});
if (!intro_key) {
- log_info(LD_REND, "Our introduction point knowledge changed in "
- "mid-connect! Could not find intro key; we only have a "
- "v2 rend desc with %d intro points. Giving up.",
+ log_info(LD_REND, "Could not find intro key for %s at %s; we "
+ "have a v2 rend desc with %d intro points. "
+ "Trying a different intro point...",
+ safe_str_client(introcirc->rend_data->onion_address),
+ introcirc->build_state->chosen_exit->nickname,
smartlist_len(entry->parsed->intro_nodes));
- goto err;
+
+ if (rend_client_reextend_intro_circuit(introcirc)) {
+ goto perm_err;
+ } else {
+ return -1;
+ }
}
if (crypto_pk_get_digest(intro_key, payload)<0) {
log_warn(LD_BUG, "Internal error: couldn't hash public key.");
- goto err;
+ goto perm_err;
}
/* Initialize the pending_final_cpath and start the DH handshake. */
@@ -123,11 +190,11 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
cpath->magic = CRYPT_PATH_MAGIC;
if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
- goto err;
+ goto perm_err;
}
if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
- goto err;
+ goto perm_err;
}
}
@@ -177,7 +244,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
DH_KEY_LEN)<0) {
log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
- goto err;
+ goto perm_err;
}
note_crypto_pk_op(REND_CLIENT);
@@ -190,7 +257,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
PK_PKCS1_OAEP_PADDING, 0);
if (r<0) {
log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
- goto err;
+ goto perm_err;
}
payload_len = DIGEST_LEN + r;
@@ -203,17 +270,18 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
introcirc->cpath->prev)<0) {
/* introcirc is already marked for close. leave rendcirc alone. */
log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
- return -1;
+ return -2;
}
/* Now, we wait for an ACK or NAK on this circuit. */
introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
return 0;
- err:
- circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
+perm_err:
+ if (!introcirc->_base.marked_for_close)
+ circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
- return -1;
+ return -2;
}
/** Called when a rendezvous circuit is open; sends a establish
@@ -274,45 +342,16 @@ rend_client_introduction_acked(origin_circuit_t *circ,
* points. If any remain, extend to a new one and try again.
* If none remain, refetch the service descriptor.
*/
+ log_info(LD_REND, "Got nack for %s from %s...",
+ safe_str_client(circ->rend_data->onion_address),
+ circ->build_state->chosen_exit->nickname);
if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
circ->rend_data) > 0) {
/* There are introduction points left. Re-extend the circuit to
* another intro point and try again. */
- extend_info_t *extend_info;
- int result;
- extend_info = rend_client_get_random_intro(circ->rend_data);
- if (!extend_info) {
- log_warn(LD_REND, "No introduction points left for %s. Closing.",
- escaped_safe_str_client(circ->rend_data->onion_address));
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
- return -1;
- }
- if (circ->remaining_relay_early_cells) {
- log_info(LD_REND,
- "Got nack for %s from %s. Re-extending circ %d, "
- "this time to %s.",
- escaped_safe_str_client(circ->rend_data->onion_address),
- circ->build_state->chosen_exit->nickname,
- circ->_base.n_circ_id, extend_info->nickname);
- result = circuit_extend_to_new_exit(circ, extend_info);
- } else {
- log_info(LD_REND,
- "Got nack for %s from %s. Building a new introduction "
- "circuit, this time to %s.",
- escaped_safe_str_client(circ->rend_data->onion_address),
- circ->build_state->chosen_exit->nickname,
- extend_info->nickname);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
- if (!circuit_launch_by_extend_info(CIRCUIT_PURPOSE_C_INTRODUCING,
- extend_info,
- CIRCLAUNCH_IS_INTERNAL)) {
- log_warn(LD_REND, "Building introduction circuit failed.");
- result = -1;
- } else {
- result = 0;
- }
- }
- extend_info_free(extend_info);
+ int result = rend_client_reextend_intro_circuit(circ);
+ /* XXXX If that call failed, should we close the rend circuit,
+ * too? */
return result;
}
}
@@ -522,8 +561,44 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
return;
}
+/** Cancel all rendezvous descriptor fetches currently in progress.
+ */
+void
+rend_client_cancel_descriptor_fetches(void)
+{
+ smartlist_t *connection_array = get_connection_array();
+
+ SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
+ if (conn->type == CONN_TYPE_DIR &&
+ (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC ||
+ conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)) {
+ /* It's a rendezvous descriptor fetch in progress -- cancel it
+ * by marking the connection for close.
+ *
+ * Even if this connection has already reached EOF, this is
+ * enough to make sure that if the descriptor hasn't been
+ * processed yet, it won't be. See the end of
+ * connection_handle_read; connection_reached_eof (indirectly)
+ * processes whatever response the connection received. */
+
+ const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data;
+ if (!rd) {
+ log_warn(LD_BUG | LD_REND,
+ "Marking for close dir conn fetching rendezvous "
+ "descriptor for unknown service!");
+ } else {
+ log_debug(LD_REND, "Marking for close dir conn fetching "
+ "rendezvous descriptor for service %s",
+ safe_str(rd->onion_address));
+ }
+ connection_mark_for_close(conn);
+ }
+ } SMARTLIST_FOREACH_END(conn);
+}
+
/** Remove failed_intro from ent. If ent now has no intro points, or
* service is unrecognized, then launch a new renddesc fetch.
+
*
* Return -1 if error, 0 if no intro points remain or service
* unrecognized, 1 if recognized and some intro points remain.
@@ -559,7 +634,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 +780,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 +814,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;
}
+ /* 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;
+}
+
+/** 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(entry->parsed->intro_nodes) == 0)
+ 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(entry->parsed->intro_nodes));
- intro = smartlist_get(entry->parsed->intro_nodes, i);
+ 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 +880,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;
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index 56ccde146..6910c1a97 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -18,6 +18,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ,
const uint8_t *request,
size_t request_len);
void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query);
+void rend_client_cancel_descriptor_fetches(void);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const rend_data_t *rend_query);
int rend_client_rendezvous_acked(origin_circuit_t *circ,
@@ -29,6 +30,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);
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index f4c8888c0..f8e7f9bbb 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -834,6 +834,16 @@ rend_cache_clean(void)
}
}
+/** Remove ALL entries from the rendezvous service descriptor cache.
+ */
+void
+rend_cache_purge(void)
+{
+ if (rend_cache)
+ strmap_free(rend_cache, _rend_cache_entry_free);
+ rend_cache = strmap_new();
+}
+
/** Remove all old v2 descriptors and those for which this hidden service
* directory is not responsible for any more. */
void
@@ -934,7 +944,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;
}
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index 501495745..44b5227cf 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -36,6 +36,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
void rend_cache_init(void);
void rend_cache_clean(void);
void rend_cache_clean_v2_descs_as_dir(void);
+void rend_cache_purge(void);
void rend_cache_free_all(void);
int rend_valid_service_id(const char *query);
int rend_cache_lookup_desc(const char *query, int version, const char **desc,
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 45039822f..cd8f9eabe 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -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,
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 9b7eefecf..02db24738 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -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)
@@ -1524,10 +1525,15 @@ rep_hist_get_bandwidth_lines(void)
size_t len;
/* opt [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
- len = (67+21*NUM_TOTALS)*4;
+/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
+ * long, plus the comma. */
+#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
+ len = (67+MAX_HIST_VALUE_LEN)*4;
buf = tor_malloc_zero(len);
cp = buf;
for (r=0;r<4;++r) {
+ char tmp[MAX_HIST_VALUE_LEN];
+ size_t slen;
switch (r) {
case 0:
b = write_array;
@@ -1547,11 +1553,16 @@ rep_hist_get_bandwidth_lines(void)
break;
}
tor_assert(b);
+ slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
+ /* If we don't have anything to write, skip to the next entry. */
+ if (slen == 0)
+ continue;
format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
desc, t, NUM_SECS_BW_SUM_INTERVAL);
cp += strlen(cp);
- cp += rep_hist_fill_bandwidth_history(cp, len-(cp-buf), b);
+ strlcat(cp, tmp, len-(cp-buf));
+ cp += slen;
strlcat(cp, "\n", len-(cp-buf));
++cp;
}
@@ -1559,7 +1570,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 +1581,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 +1615,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 +1625,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 +1655,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,
@@ -1673,7 +1686,7 @@ rep_hist_load_bwhist_state_section(bw_array_t *b,
mv *= NUM_SECS_ROLLING_MEASURE;
} else {
/* No maxima known; guess average rate to be conservative. */
- mv = v / s_interval;
+ mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
}
if (!ok) {
retval = -1;
@@ -1686,11 +1699,24 @@ rep_hist_load_bwhist_state_section(bw_array_t *b,
}
if (start < now) {
- add_obs(b, start, v);
+ time_t cur_start = start;
+ time_t actual_interval_len = s_interval;
+ uint64_t cur_val = 0;
+ /* Calculate the average per second. This is the best we can do
+ * because our state file doesn't have per-second resolution. */
+ if (start + s_interval > now)
+ actual_interval_len = now - start;
+ cur_val = v / actual_interval_len;
+ /* This is potentially inefficient, but since we don't do it very
+ * often it should be ok. */
+ while (cur_start < start + actual_interval_len) {
+ add_obs(b, cur_start, cur_val);
+ ++cur_start;
+ }
b->max_total = mv;
/* This will result in some fairly choppy history if s_interval
- * is notthe same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
- start += s_interval;
+ * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
+ start += actual_interval_len;
}
} SMARTLIST_FOREACH_END(cp);
}
@@ -1704,7 +1730,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)
{
@@ -1752,7 +1778,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;
diff --git a/src/or/router.c b/src/or/router.c
index c15b9b236..65afd49f7 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -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",
@@ -1087,10 +1107,10 @@ set_server_advertised(int s)
int
proxy_mode(or_options_t *options)
{
- return (options->SocksPort != 0 || options->SocksListenAddress ||
- options->TransPort != 0 || options->TransListenAddress ||
- options->NATDPort != 0 || options->NATDListenAddress ||
- options->DNSPort != 0 || options->DNSListenAddress);
+ return (options->SocksPort != 0 ||
+ options->TransPort != 0 ||
+ options->NATDPort != 0 ||
+ options->DNSPort != 0);
}
/** Decide if we're a publishable server. We are a publishable server if:
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 4deff53a3..f567ccdf3 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -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;
@@ -5676,7 +5727,6 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
{
int start, found, n_added = 0, i;
networkstatus_t *c = networkstatus_get_latest_consensus();
- int use_begindir = get_options()->TunnelDirConns;
if (!c || !smartlist_len(c->routerstatus_list)) {
log_warn(LD_REND, "We don't have a consensus, so we can't perform v2 "
"rendezvous operations.");
@@ -5689,14 +5739,9 @@ hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
do {
routerstatus_t *r = smartlist_get(c->routerstatus_list, i);
if (r->is_hs_dir) {
- if (r->dir_port || use_begindir)
- smartlist_add(responsible_dirs, r);
- else
- log_info(LD_REND, "Not adding router '%s' to list of responsible "
- "hidden service directories, because we have no way of "
- "reaching it.", r->nickname);
+ smartlist_add(responsible_dirs, r);
if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS)
- break;
+ return 0;
}
if (++i == smartlist_len(c->routerstatus_list))
i = 0;
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index ca428114e..fec18705b 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -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);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 95e174e55..d0138e638 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -4357,6 +4357,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
md = NULL;
next:
microdesc_free(md);
+ md = NULL;
memarea_clear(area);
smartlist_clear(tokens);
@@ -4638,10 +4639,12 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
else
eos = eos + 1;
/* Check length. */
- if (strlen(desc) > REND_DESC_MAX_SIZE) {
- log_warn(LD_REND, "Descriptor length is %i which exceeds "
- "maximum rendezvous descriptor size of %i kilobytes.",
- (int)strlen(desc), REND_DESC_MAX_SIZE);
+ if (eos-desc > REND_DESC_MAX_SIZE) {
+ /* XXX023 If we are parsing this descriptor as a server, this
+ * should be a protocol warning. */
+ log_warn(LD_REND, "Descriptor length is %d which exceeds "
+ "maximum rendezvous descriptor size of %d bytes.",
+ (int)(eos-desc), REND_DESC_MAX_SIZE);
goto err;
}
/* Tokenize descriptor. */
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 20ffaa0c5..6db4ee248 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -477,9 +477,9 @@ test_addr_ip6_helpers(void)
i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
#if 0
tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf));
- printf("\nv4 address: %s (family=%i)", buf, IN_FAMILY(&t1));
+ printf("\nv4 address: %s (family=%d)", buf, IN_FAMILY(&t1));
tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf));
- printf("\nv6 address: %s (family=%i)", buf, IN_FAMILY(&t2));
+ printf("\nv6 address: %s (family=%d)", buf, IN_FAMILY(&t2));
#endif
done: