mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
Merge branch 'maint-0.2.4' into release-0.2.4
This commit is contained in:
commit
887eba9895
6
changes/bug6174
Normal file
6
changes/bug6174
Normal file
@ -0,0 +1,6 @@
|
||||
o Major bugfixes:
|
||||
- When we mark a circuit as unusable for new circuits, have it
|
||||
continue to be unusable for new circuits even if MaxCircuitDirtiness
|
||||
is increased too much at the wrong time, or the system clock jumped
|
||||
backwards. Fix for bug 6174; bugfix on 0.0.2pre26.
|
||||
|
6
changes/bug6206
Normal file
6
changes/bug6206
Normal file
@ -0,0 +1,6 @@
|
||||
o Minor bugfixes:
|
||||
- Always check the return values of functions fcntl() and
|
||||
setsockopt(). We don't believe these are ever actually failing in
|
||||
practice, but better safe than sorry. Also, checking these return
|
||||
values should please some analysis tools (like Coverity). Patch
|
||||
from 'flupzor'. Fix for bug 8206; bugfix on all versions of Tor.
|
4
changes/bug6304
Normal file
4
changes/bug6304
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Behave correctly when the user disables LearnCircuitBuildTimeout
|
||||
but doesn't tell us what they would like the timeout to be. Fixes
|
||||
bug 6304; bugfix on 0.2.2.14-alpha.
|
4
changes/bug6572
Normal file
4
changes/bug6572
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes (log messages)
|
||||
- Use circuit creation time for network liveness evaluation. This
|
||||
should eliminate warning log messages about liveness caused by
|
||||
changes in timeout evaluation. Fixes bug 6572; bugfix on 0.2.4.8-alpha.
|
4
changes/bug6673
Normal file
4
changes/bug6673
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor features (build):
|
||||
- Detect and reject attempts to build Tor with threading support
|
||||
when OpenSSL have been compiled with threading support disabled.
|
||||
Fixes bug 6673.
|
5
changes/bug7065
Normal file
5
changes/bug7065
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor bugfix (log cleanups):
|
||||
- Eliminate several instances where we use Nickname=ID to refer to
|
||||
nodes in logs. Use Nickname (ID) instead. (Elsewhere, we still use
|
||||
$ID=Nickname, which is also acceptable.) Fixes bug #7065. Bugfix
|
||||
on 0.2.3.21-rc, 0.2.4.5-alpha, 0.2.4.8-alpha, and 0.2.4.10-alpha.
|
4
changes/bug7164_diagnostic
Normal file
4
changes/bug7164_diagnostic
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor features (bug diagnostic):
|
||||
- If we fail to free a microdescriptor because of bug #7164, log
|
||||
the filename and line number from which we tried to free it.
|
||||
This should help us finally fix #7164.
|
4
changes/bug7280
Normal file
4
changes/bug7280
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Fix some bugs in tor-fw-helper-natpmp when trying to build and
|
||||
run it on Windows. More bugs likely remain. Patch from Gisle Vanem.
|
||||
Fixes bug 7280; bugfix on 0.2.3.1-alpha.
|
4
changes/bug7350
Normal file
4
changes/bug7350
Normal file
@ -0,0 +1,4 @@
|
||||
o Major bugfixes:
|
||||
- Avoid an assertion when we discover that we'd like to write a cell
|
||||
onto a closing connection: just discard the cell. Fixes another
|
||||
case of bug 7350; bugfix on 0.2.4.4-alpha.
|
9
changes/bug7582
Normal file
9
changes/bug7582
Normal file
@ -0,0 +1,9 @@
|
||||
o Major bugfixes:
|
||||
|
||||
- When an exit node tells us that it is rejecting because of its
|
||||
exit policy a stream we expected it to accept (because of its exit
|
||||
policy), do not mark the node as useless for exiting if our
|
||||
expectation was only based on an exit policy summary. Instead,
|
||||
mark the circuit as unsuitable for that particular address. Fixes
|
||||
part of bug 7582; bugfix on 0.2.3.2-alpha.
|
||||
|
5
changes/bug7707_diagnostic
Normal file
5
changes/bug7707_diagnostic
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor features:
|
||||
- Add another diagnostic to the heartbeat message: track and log
|
||||
overhead that TLS is adding to the data we write. If this is
|
||||
high, we are sending too little data to SSL_write at a time.
|
||||
Diagnostic for bug 7707.
|
3
changes/bug7768
Normal file
3
changes/bug7768
Normal file
@ -0,0 +1,3 @@
|
||||
o Documentation fixes:
|
||||
- Update tor-fw-helper.1.txt and tor-fw-helper.c to make option
|
||||
names match. Fixes bug 7768.
|
7
changes/bug7799
Normal file
7
changes/bug7799
Normal file
@ -0,0 +1,7 @@
|
||||
o Minor changes (log clarification)
|
||||
- Add more detail to a log message about relaxed timeouts. Hopefully
|
||||
this additional detail will allow us to diagnose the cause of bug 7799.
|
||||
o Minor bugfixes
|
||||
- Don't attempt to relax the timeout of already opened 1-hop circuits.
|
||||
They might never timeout. This should eliminate some/all cases of
|
||||
the relaxed timeout log message.
|
4
changes/bug7947
Normal file
4
changes/bug7947
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Fix the handling of a TRUNCATE cell when it arrives while the circuit
|
||||
extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1.
|
||||
|
4
changes/bug7950
Normal file
4
changes/bug7950
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- When rejecting a configuration because we were unable to parse a
|
||||
quoted string, log an actual error message. Fix for bug 7950;
|
||||
bugfix on 0.2.0.16-alpha.
|
5
changes/bug8002
Normal file
5
changes/bug8002
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor bugfixes:
|
||||
- When autodetecting the number of CPUs, use the number of available
|
||||
CPUs in preferernce to the number of configured CPUs. Inform the
|
||||
user if this reduces the number of avialable CPUs. Fix for bug 8002.
|
||||
Bugfix on 0.2.3.1-alpha.
|
5
changes/bug8014
Normal file
5
changes/bug8014
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor usability improvements (build):
|
||||
- Clarify that when autconf is checking for nacl, it is checking
|
||||
specifically for nacl with a fast curve25519 implementation.
|
||||
Fixes bug 8014.
|
||||
|
7
changes/bug8031
Normal file
7
changes/bug8031
Normal file
@ -0,0 +1,7 @@
|
||||
o Minor bugfixes:
|
||||
- Use direct writes rather than stdio when building microdescriptor
|
||||
caches, in an attempt to mitigate bug 8031, or at least make it
|
||||
less common.
|
||||
- Warn more aggressively when flushing microdescriptors to a
|
||||
microdescriptor cache fails, in an attempt to mitegate bug 8031,
|
||||
or at least make it more diagnosable.
|
6
changes/bug8059
Normal file
6
changes/bug8059
Normal file
@ -0,0 +1,6 @@
|
||||
o Minor bugfixes (protocol conformance):
|
||||
- Fix a misframing issue when reading the version numbers in a
|
||||
VERSIONS cell. Previously we would recognize [00 01 00 02] as
|
||||
'version 1, version 2, and version 0x100', when it should have
|
||||
only included versions 1 and 2. Fixes bug 8059; bugfix on
|
||||
0.2.0.10-alpha. Reported pseudonymously.
|
5
changes/bug8062
Normal file
5
changes/bug8062
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor bugfixes:
|
||||
- Increase the width of the field used to remember a connection's
|
||||
link protocol version to two bytes. Harmless for now, since the
|
||||
only currently recognized versions are one byte long. Reported
|
||||
pseudynmously. Fixes bug 8062, bugfix on 0.2.0.10-alpha.
|
7
changes/bug8180
Normal file
7
changes/bug8180
Normal file
@ -0,0 +1,7 @@
|
||||
o Minor bugfixes (security usability):
|
||||
- Elevate the severity of the warning message when setting
|
||||
EntryNodes but disabling UseGuardNodes to an error. The outcome
|
||||
of letting Tor procede with those options enabled (which causes
|
||||
EntryNodes to get ignored) is sufficiently different from what
|
||||
was expected that it's best to just refuse to proceed. Fixes bug
|
||||
8180; bugfix on 0.2.3.11-alpha.
|
4
changes/bug8203
Normal file
4
changes/bug8203
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Make the format and order of STREAM events for DNS lookups consistent
|
||||
among the various ways to launch DNS lookups. Fix for bug 8203;
|
||||
bugfix on 0.2.0.24-rc. Patch by "Desoxy."
|
5
changes/bug8231
Normal file
5
changes/bug8231
Normal file
@ -0,0 +1,5 @@
|
||||
o Major bugfixes:
|
||||
- When unable to find any working directory nodes to use as a
|
||||
directory guard, give up rather than adding the same non-working
|
||||
nodes to the list over and over. Fixes bug 8231; bugfix on
|
||||
0.2.4.8-alpha.
|
5
changes/bug8235-diagnosing
Normal file
5
changes/bug8235-diagnosing
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor features (diagnostic)
|
||||
- If the state file's path bias counts are invalid (presumably from a
|
||||
buggy tor prior to 0.2.4.10-alpha), make them correct.
|
||||
- Add additional checks and log messages to the scaling of Path Bias
|
||||
counts, in case there still are remaining issues with scaling.
|
3
changes/bug8273
Normal file
3
changes/bug8273
Normal file
@ -0,0 +1,3 @@
|
||||
o Critical bugfixes:
|
||||
- When dirserv.c computes flags and thresholds, use measured bandwidths
|
||||
in preference to advertised ones.
|
9
changes/bug8290
Normal file
9
changes/bug8290
Normal file
@ -0,0 +1,9 @@
|
||||
o Removed files:
|
||||
- The tor-tsocks.conf is no longer distributed or installed. We
|
||||
recommend that tsocks users use torsocks instead. Resolves
|
||||
ticket 8290.
|
||||
|
||||
o Documentation fixes:
|
||||
- The torify manpage no longer refers to tsocks; torify hasn't
|
||||
supported tsocks since 0.2.3.14-alpha.
|
||||
- The manpages no longer reference tsocks.
|
3
changes/bug8377
Normal file
3
changes/bug8377
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor bugfixes:
|
||||
- Correctly recognize that [::1] is a loopback address. Fixes bug #8377;
|
||||
bugfix on 0.2.1.3-alpha.
|
4
changes/bug8408
Normal file
4
changes/bug8408
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Allow TestingTorNetworks to override the 4096-byte minimum for the Fast
|
||||
threshold. Otherwise they can't bootstrap until they've observed more
|
||||
traffic. Fixes bug 8508; bugfix on 0.2.4.10-alpha.
|
5
changes/bug8427
Normal file
5
changes/bug8427
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor bugfixes:
|
||||
- If we encounter a write failure on a SOCKS connection before we
|
||||
finish our SOCKS handshake, don't warn that we closed the
|
||||
connection before we could send a SOCKS reply. Fixes bug 8427;
|
||||
bugfix on 0.1.0.1-rc.
|
4
changes/bug8435
Normal file
4
changes/bug8435
Normal file
@ -0,0 +1,4 @@
|
||||
o Major bugfixes:
|
||||
- When dirserv.c computes flags and thresholds, ignore advertised
|
||||
bandwidths if we have more than a threshold number of routers with
|
||||
measured bandwidths.
|
5
changes/bug8464
Normal file
5
changes/bug8464
Normal file
@ -0,0 +1,5 @@
|
||||
o Minor bugfixes:
|
||||
- Correct our check for which versions of Tor support the EXTEND2
|
||||
cell. We had been willing to send it to Tor 0.2.4.7-alpha and
|
||||
later, when support was really added in version 0.2.4.8-alpha.
|
||||
Fixes bug 8464; bugfix on 0.2.4.8-alpha.
|
4
changes/bug8475
Normal file
4
changes/bug8475
Normal file
@ -0,0 +1,4 @@
|
||||
o Major bugfixes:
|
||||
- If configured via ClientDNSRejectInternalAddresses not to report
|
||||
DNS queries which have resolved to internal addresses, apply that
|
||||
rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha.
|
3
changes/bug8477-easypart
Normal file
3
changes/bug8477-easypart
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor bugfixes:
|
||||
- Log the purpose of a path-bias testing circuit correctly.
|
||||
Improves a log message from bug 8477; bugfix on 0.2.4.8-alpha.
|
3
changes/bug8596
Normal file
3
changes/bug8596
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor features:
|
||||
- Add CACHED keyword to ADDRMAP events in the control protocol to indicate
|
||||
whether a DNS result will be cached or not.
|
6
changes/bug8598
Normal file
6
changes/bug8598
Normal file
@ -0,0 +1,6 @@
|
||||
o Bugfixes:
|
||||
- Fix compilation warning with some versions of clang that would prefer
|
||||
the -Wswitch-enum compiler flag to warn about switch statements with
|
||||
missing enum values, even if those switch statements have a default:
|
||||
statement. Fixes bug 8598; bugfix on 0.2.4.10-alpha.
|
||||
|
4
changes/bug8599
Normal file
4
changes/bug8599
Normal file
@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Fix some logic errors when the user manually overrides the
|
||||
PathsNeededToBuildCircuits option in torrc. Fixes bug 8599; bugfix
|
||||
on 0.2.4.10-alpha.
|
3
changes/bug8638
Normal file
3
changes/bug8638
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor features
|
||||
In our testsuite, create temporary directories with a bit more entropy
|
||||
in their name to make name collissions less likely. Fixes bug 8638.
|
3
changes/geoip-apr2013
Normal file
3
changes/geoip-apr2013
Normal file
@ -0,0 +1,3 @@
|
||||
o Minor features:
|
||||
- Update to the April 3 2013 Maxmind GeoLite Country database.
|
||||
|
11
changes/log-noise
Normal file
11
changes/log-noise
Normal file
@ -0,0 +1,11 @@
|
||||
o Minor bugfixes (log message reduction)
|
||||
- Fix a path state issue that triggered a notice during relay startup.
|
||||
Fixes bug #8320; bugfix on 0.2.4.10-alpha.
|
||||
- Reduce occurrences of warns about circuit purpose in
|
||||
connection_ap_expire_building(). Fixes bug #8477; bugfix on
|
||||
0.2.4.11-alpha.
|
||||
- Fix a directory authority warn caused when we have a large amount
|
||||
of badexit bandwidth. Fixes bug #8419; bugfix on 0.2.2.10-alpha.
|
||||
- Reduce a path bias length check notice log to info. The notice
|
||||
is triggered when creating controller circuits. Fixes bug #8196;
|
||||
bugfix on 0.2.4.8-alpha.
|
4
changes/ticket8240
Normal file
4
changes/ticket8240
Normal file
@ -0,0 +1,4 @@
|
||||
o Major security fixes:
|
||||
- Make the default guard lifetime controllable via a new
|
||||
GuardLifetime torrc option and a GuardLifetime consensus
|
||||
parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha.
|
5
changes/warn-unsigned-time_t
Normal file
5
changes/warn-unsigned-time_t
Normal file
@ -0,0 +1,5 @@
|
||||
o Build improvements:
|
||||
- Warn if building on a platform with an unsigned time_t: there
|
||||
are too many places where Tor currently assumes that time_t can
|
||||
hold negative values. We'd like to fix them all, but probably
|
||||
some will remain.
|
10
configure.ac
10
configure.ac
@ -693,7 +693,7 @@ if test x$enable_curve25519 != xno; then
|
||||
AC_CHECK_HEADERS([crypto_scalarmult_curve25519.h \
|
||||
nacl/crypto_scalarmult_curve25519.h])
|
||||
|
||||
AC_CACHE_CHECK([whether we can use curve25519 from nacl],
|
||||
AC_CACHE_CHECK([for nacl compiled with a fast curve25519 implementation],
|
||||
tor_cv_can_use_curve25519_nacl,
|
||||
[tor_saved_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lnacl"
|
||||
@ -705,7 +705,7 @@ if test x$enable_curve25519 != xno; then
|
||||
#include <nacl/crypto_scalarmult_curve25519.h>
|
||||
#endif
|
||||
#ifdef crypto_scalarmult_curve25519_ref_BYTES
|
||||
#error Hey, this is the reference implementation!
|
||||
#error Hey, this is the reference implementation! That's not fast.
|
||||
#endif
|
||||
], [
|
||||
unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
|
||||
@ -972,6 +972,10 @@ AX_CHECK_SIGN([time_t],
|
||||
#endif
|
||||
])
|
||||
|
||||
if test "$ax_cv_decl_time_t_signed" = no; then
|
||||
AC_MSG_WARN([You have an unsigned time_t; some things will probably break. Please tell the Tor developers about your interesting platform.])
|
||||
fi
|
||||
|
||||
AX_CHECK_SIGN([size_t],
|
||||
[ tor_cv_size_t_signed=yes ],
|
||||
[ tor_cv_size_t_signed=no ], [
|
||||
@ -980,7 +984,7 @@ AX_CHECK_SIGN([size_t],
|
||||
#endif
|
||||
])
|
||||
|
||||
if test "$tor_cv_size_t_signed" = yes; then
|
||||
if test "$ax_cv_decl_size_t_signed" = yes; then
|
||||
AC_MSG_ERROR([You have a signed size_t; that's grossly nonconformant.])
|
||||
fi
|
||||
|
||||
|
@ -9,12 +9,9 @@ EXTRA_DIST+= \
|
||||
contrib/tor-ctrl.sh \
|
||||
contrib/tor-exit-notice.html \
|
||||
contrib/tor-mingw.nsi.in \
|
||||
contrib/tor-tsocks.conf \
|
||||
contrib/tor.ico \
|
||||
contrib/tor.nsi.in \
|
||||
contrib/tor.sh \
|
||||
contrib/torctl
|
||||
|
||||
conf_DATA+= contrib/tor-tsocks.conf
|
||||
|
||||
bin_SCRIPTS+= contrib/torify
|
||||
|
@ -1,13 +0,0 @@
|
||||
# This is the configuration for libtsocks (transparent socks) for use
|
||||
# with tor, which is providing a socks server on port 9050 by default.
|
||||
#
|
||||
# See tsocks.conf(5) and torify(1) manpages.
|
||||
|
||||
server = 127.0.0.1
|
||||
server_port = 9050
|
||||
|
||||
# We specify local as 127.0.0.0 - 127.191.255.255 because the
|
||||
# Tor MAPADDRESS virtual IP range is the rest of net 127.
|
||||
local = 127.0.0.0/255.128.0.0
|
||||
local = 127.128.0.0/255.192.0.0
|
||||
|
@ -52,8 +52,8 @@ elif [ "$1" = "man" ]; then
|
||||
You need a working asciidoc installed to be able to build the manpage.
|
||||
|
||||
a2x is installed, but for some reason it isn't working. Sometimes
|
||||
This happens because required docbook support files are missing.
|
||||
Please install docbook-xsl, docbook-xml, and libxml2-utils (Debian) or
|
||||
this happens because required docbook support files are missing.
|
||||
Please install docbook-xsl, docbook-xml, and xmlto (Debian) or
|
||||
similar. If you use homebrew on Mac OS X, install the docbook formula
|
||||
and add "export XML_CATALOG_FILES=/usr/local/etc/xml/catalog" to your
|
||||
.bashrc
|
||||
|
@ -1,479 +0,0 @@
|
||||
|
||||
Tor Incentives Design Brainstorms
|
||||
|
||||
1. Goals: what do we want to achieve with an incentive scheme?
|
||||
|
||||
1.1. Encourage users to provide good relay service (throughput, latency).
|
||||
1.2. Encourage users to allow traffic to exit the Tor network from
|
||||
their node.
|
||||
|
||||
2. Approaches to learning who should get priority.
|
||||
|
||||
2.1. "Hard" or quantitative reputation tracking.
|
||||
|
||||
In this design, we track the number of bytes and throughput in and
|
||||
out of nodes we interact with. When a node asks to send or receive
|
||||
bytes, we provide service proportional to our current record of the
|
||||
node's value. One approach is to let each circuit be either a normal
|
||||
circuit or a premium circuit, and nodes can "spend" their value by
|
||||
sending and receiving bytes on premium circuits: see section 4.1 for
|
||||
details of this design. Another approach (section 4.2) would treat
|
||||
all traffic from the node with the same priority class, and so nodes
|
||||
that provide resources will get and provide better service on average.
|
||||
|
||||
This approach could be complemented with an anonymous e-cash
|
||||
implementation to let people spend reputations gained from one context
|
||||
in another context.
|
||||
|
||||
2.2. "Soft" or qualitative reputation tracking.
|
||||
|
||||
Rather than accounting for every byte (if I owe you a byte, I don't
|
||||
owe it anymore once you've spent it), instead I keep a general opinion
|
||||
about each server: my opinion increases when they do good work for me,
|
||||
and it decays with time, but it does not decrease as they send traffic.
|
||||
Therefore we reward servers who provide value to the system without
|
||||
nickle and diming them at each step. We also let them benefit from
|
||||
relaying traffic for others without having to "reserve" some of the
|
||||
payment for their own use. See section 4.3 for a possible design.
|
||||
|
||||
2.3. Centralized opinions from the reputation servers.
|
||||
|
||||
The above approaches are complex and we don't have all the answers
|
||||
for them yet. A simpler approach is just to let some central set
|
||||
of trusted servers (say, the Tor directory servers) measure whether
|
||||
people are contributing to the network, and provide a signal about
|
||||
which servers should be rewarded. They can even do the measurements
|
||||
via Tor so servers can't easily perform only when they're being
|
||||
tested. See section 4.4.
|
||||
|
||||
2.4. Reputation servers that aggregate opinions.
|
||||
|
||||
The option above has the directory servers doing all of the
|
||||
measurements. This doesn't scale. We can set it up so we have "deputy
|
||||
testers" -- trusted other nodes that do performance testing and report
|
||||
their results.
|
||||
|
||||
If we want to be really adventurous, we could even
|
||||
accept claims from every Tor user and build a complex weighting /
|
||||
reputation system to decide which claims are "probably" right.
|
||||
One possible way to implement the latter is something similar to
|
||||
EigenTrust [http://www.stanford.edu/~sdkamvar/papers/eigentrust.pdf],
|
||||
where the opinion of nodes with high reputation more is weighted
|
||||
higher.
|
||||
|
||||
3. Related issues we need to keep in mind.
|
||||
|
||||
3.1. Relay and exit configuration needs to be easy and usable.
|
||||
|
||||
Implicit in all of the above designs is the need to make it easy to
|
||||
run a Tor server out of the box. We need to make it stable on all
|
||||
common platforms (including XP), it needs to detect its available
|
||||
bandwidth and not overreach that, and it needs to help the operator
|
||||
through opening up ports on his firewall. Then we need a slick GUI
|
||||
that lets people click a button or two rather than editing text files.
|
||||
|
||||
Once we've done all this, we'll hit our first big question: is
|
||||
most of the barrier to growth caused by the unusability of the current
|
||||
software? If so, are the rest of these incentive schemes superfluous?
|
||||
|
||||
3.2. The network effect: how many nodes will you interact with?
|
||||
|
||||
One of the concerns with pairwise reputation systems is that as the
|
||||
network gets thousands of servers, the chance that you're going to
|
||||
interact with a given server decreases. So if 90% of interactions
|
||||
don't have any prior information, the "local" incentive schemes above
|
||||
are going to degrade. This doesn't mean they're pointless -- it just
|
||||
means we need to be aware that this is a limitation, and plan in the
|
||||
background for what step to take next. (It seems that e-cash solutions
|
||||
would scale better, though they have issues of their own.)
|
||||
|
||||
3.3. Guard nodes
|
||||
|
||||
As of Tor 0.1.1.11, Tor users pick from a small set of semi-permanent
|
||||
"guard nodes" for their first hop of each circuit. This seems like it
|
||||
would have a big impact on pairwise reputation systems since you
|
||||
will only be cashing in on your reputation to a few people, and it is
|
||||
unlikely that a given pair of nodes will use each other as guard nodes.
|
||||
|
||||
What does this imply? For one, it means that we don't care at all
|
||||
about the opinions of most of the servers out there -- we should
|
||||
focus on keeping our guard nodes happy with us.
|
||||
|
||||
One conclusion from that is that our design needs to judge performance
|
||||
not just through direct interaction (beginning of the circuit) but
|
||||
also through indirect interaction (middle of the circuit). That way
|
||||
you can never be sure when your guards are measuring you.
|
||||
|
||||
Both 3.2 and 3.3 may be solved by having a global notion of reputation,
|
||||
as in 2.3 and 2.4. However, computing the global reputation from local
|
||||
views could be expensive (O(n^2)) when the network is really large.
|
||||
|
||||
3.4. Restricted topology: benefits and roadmap.
|
||||
|
||||
As the Tor network continues to grow, we will need to make design
|
||||
changes to the network topology so that each node does not need
|
||||
to maintain connections to an unbounded number of other nodes. For
|
||||
anonymity's sake, we may partition the network such that all
|
||||
the nodes have the same belief about the divisions and each node is
|
||||
in only one partition. (The alternative is that every user fetches
|
||||
his own random subset of the overall node list -- this is bad because
|
||||
of intersection attacks.)
|
||||
|
||||
Therefore the "network horizon" for each user will stay bounded,
|
||||
which helps against the above issues in 3.2 and 3.3.
|
||||
|
||||
It could be that the core of long-lived servers will all get to know
|
||||
each other, and so the critical point that decides whether you get
|
||||
good service is whether the core likes you. Or perhaps it will turn
|
||||
out to work some other way.
|
||||
|
||||
A special case here is the social network, where the network isn't
|
||||
partitioned randomly but instead based on some external properties.
|
||||
Social network topologies can provide incentives in other ways, because
|
||||
people may be more inclined to help out their friends, and more willing
|
||||
to relay traffic if most of the traffic they are relaying comes
|
||||
from their friends. It also opens the door for out-of-band incentive
|
||||
schemes because of the out-of-band links in the graph.
|
||||
|
||||
3.5. Profit-maximizing vs. Altruism.
|
||||
|
||||
There are some interesting game theory questions here.
|
||||
|
||||
First, in a volunteer culture, success is measured in public utility
|
||||
or in public esteem. If we add a reward mechanism, there's a risk that
|
||||
reward-maximizing behavior will surpass utility- or esteem-maximizing
|
||||
behavior.
|
||||
|
||||
Specifically, if most of our servers right now are relaying traffic
|
||||
for the good of the community, we may actually *lose* those volunteers
|
||||
if we turn the act of relaying traffic into a selfish act.
|
||||
|
||||
I am not too worried about this issue for now, since we're aiming
|
||||
for an incentive scheme so effective that it produces tens of
|
||||
thousands of new servers.
|
||||
|
||||
3.6. What part of the node's performance do you measure?
|
||||
|
||||
We keep referring to having a node measure how well the other nodes
|
||||
receive bytes. But don't leeching clients receive bytes just as well
|
||||
as servers?
|
||||
|
||||
Further, many transactions in Tor involve fetching lots of
|
||||
bytes and not sending very many. So it seems that we want to turn
|
||||
things around: we need to measure how quickly a node is _sending_
|
||||
us bytes, and then only send it bytes in proportion to that.
|
||||
|
||||
However, a sneaky user could simply connect to a node and send some
|
||||
traffic through it, and voila, he has performed for the network. This
|
||||
is no good. The first fix is that we only count if you're receiving
|
||||
bytes "backwards" in the circuit. Now the sneaky user needs to
|
||||
construct a circuit such that his node appears later in the circuit,
|
||||
and then send some bytes back quickly.
|
||||
|
||||
Maybe that complexity is sufficient to deter most lazy users. Or
|
||||
maybe it's an argument in favor of a more penny-counting reputation
|
||||
approach.
|
||||
|
||||
Addendum: I was more thinking of measuring based on who is the service
|
||||
provider and service receiver for the circuit. Say Alice builds a
|
||||
circuit to Bob. Then Bob is providing service to Alice, since he
|
||||
otherwise wouldn't need to spend his bandwidth. So traffic in either
|
||||
direction should be charged to Alice. Of course, the same attack would
|
||||
work, namely, Bob could cheat by sending bytes back quickly. So someone
|
||||
close to the origin needs to detect this and close the circuit, if
|
||||
necessary. -JN
|
||||
|
||||
3.7. What is the appropriate resource balance for servers vs. clients?
|
||||
|
||||
If we build a good incentive system, we'll still need to tune it
|
||||
to provide the right bandwidth allocation -- if we reserve too much
|
||||
bandwidth for fast servers, then we're wasting some potential, but
|
||||
if we reserve too little, then fewer people will opt to become servers.
|
||||
In fact, finding an optimum balance is especially hard because it's
|
||||
a moving target: the better our incentive mechanism (and the lower
|
||||
the barrier to setup), the more servers there will be. How do we find
|
||||
the right balance?
|
||||
|
||||
One answer is that it doesn't have to be perfect: we can err on the
|
||||
side of providing extra resources to servers. Then we will achieve our
|
||||
desired goal -- when people complain about speed, we can tell them to
|
||||
run a server, and they will in fact get better performance.
|
||||
|
||||
3.8. Anonymity attack: fast connections probably come from good servers.
|
||||
|
||||
If only fast servers can consistently get good performance in the
|
||||
network, they will stand out. "Oh, that connection probably came from
|
||||
one of the top ten servers in the network." Intersection attacks over
|
||||
time can improve the certainty of the attack.
|
||||
|
||||
I'm not too worried about this. First, in periods of low activity,
|
||||
many different people might be getting good performance. This dirties
|
||||
the intersection attack. Second, with many of these schemes, we will
|
||||
still be uncertain whether the fast node originated the traffic, or
|
||||
was the entry node for some other lucky user -- and we already accept
|
||||
this level of attack in other cases such as the Murdoch-Danezis attack
|
||||
[http://freehaven.net/anonbib/#torta05].
|
||||
|
||||
3.9. How do we allocate bandwidth over the course of a second?
|
||||
|
||||
This may be a simple matter of engineering, but it still needs to be
|
||||
addressed. Our current token bucket design refills each bucket once a
|
||||
second. If we have N tokens in our bucket, and we don't know ahead of
|
||||
time how many connections are going to want to send out how many bytes,
|
||||
how do we balance providing quick service to the traffic that is
|
||||
already here compared to providing service to potential high-importance
|
||||
future traffic?
|
||||
|
||||
If we have only two classes of service, here is a simple design:
|
||||
At each point, when we are 1/t through the second, the total number
|
||||
of non-priority bytes we are willing to send out is N/t. Thus if N
|
||||
priority bytes are waiting at the beginning of the second, we drain
|
||||
our whole bucket then, and otherwise we provide some delayed service
|
||||
to the non-priority bytes.
|
||||
|
||||
Does this design expand to cover the case of three priority classes?
|
||||
Ideally we'd give each remote server its own priority number. Or
|
||||
hopefully there's an easy design in the literature to point to --
|
||||
this is clearly not my field.
|
||||
|
||||
Is our current flow control mechanism (each circuit and each stream
|
||||
start out with a certain window, and once they've exhausted it they
|
||||
need to receive an ack before they can send more) going to have
|
||||
problems with this new design now that we'll be queueing more bytes
|
||||
for less preferred nodes? If it turns out we do, the first fix is
|
||||
to have the windows start out at zero rather than start out full --
|
||||
it will slow down the startup phase but protect us better.
|
||||
|
||||
While we have outgoing cells queued for a given server, we have the
|
||||
option of reordering them based on the priority of the previous hop.
|
||||
Is this going to turn out to be useful? If we're the exit node (that
|
||||
is, there is no previous hop) what priority do those cells get?
|
||||
|
||||
Should we do this prioritizing just for sending out bytes (as I've
|
||||
described here) or would it help to do it also for receiving bytes?
|
||||
See next section.
|
||||
|
||||
3.10. Different-priority cells arriving on the same TCP connection.
|
||||
|
||||
In some of the proposed designs, servers want to give specific circuits
|
||||
priority rather than having all circuits from them get the same class
|
||||
of service.
|
||||
|
||||
Since Tor uses TCP's flow control for rate limiting, this constraints
|
||||
our design choices -- it is easy to give different TCP connections
|
||||
different priorities, but it is hard to give different cells on the
|
||||
same connection priority, because you have to read them to know what
|
||||
priority they're supposed to get.
|
||||
|
||||
There are several possible solutions though. First is that we rely on
|
||||
the sender to reorder them so the highest priority cells (circuits) are
|
||||
more often first. Second is that if we open two TCP connections -- one
|
||||
for the high-priority cells, and one for the low-priority cells. (But
|
||||
this prevents us from changing the priority of a circuit because
|
||||
we would need to migrate it from one connection to the other.) A
|
||||
third approach is to remember which connections have recently sent
|
||||
us high-priority cells, and preferentially read from those connections.
|
||||
|
||||
Hopefully we can get away with not solving this section at all. But if
|
||||
necessary, we can consult Ed Knightly, a Professor at Rice
|
||||
[http://www.ece.rice.edu/~knightly/], for his extensive experience on
|
||||
networking QoS.
|
||||
|
||||
3.11. Global reputation system: Congestion on high reputation servers?
|
||||
|
||||
If the notion of reputation is global (as in 2.3 or 2.4), circuits that
|
||||
go through successive high reputation servers would be the fastest and
|
||||
most reliable. This would incentivize everyone, regardless of their own
|
||||
reputation, to choose only the highest reputation servers in its
|
||||
circuits, causing an over-congestion on those servers.
|
||||
|
||||
One could argue, though, that once those servers are over-congested,
|
||||
their bandwidth per circuit drops, which would in turn lower their
|
||||
reputation in the future. A question is whether this would overall
|
||||
stabilize.
|
||||
|
||||
Another possible way is to keep a cap on reputation. In this way, a
|
||||
fraction of servers would have the same high reputation, thus balancing
|
||||
such load.
|
||||
|
||||
3.12. Another anonymity attack: learning from service levels.
|
||||
|
||||
If reputation is local, it may be possible for an evil node to learn
|
||||
the identity of the origin through provision of differential service.
|
||||
For instance, the evil node provides crappy bandwidth to everyone,
|
||||
until it finds a circuit that it wants to trace the origin, then it
|
||||
provides good bandwidth. Now, as only those directly or indirectly
|
||||
observing this circuit would like the evil node, it can test each node
|
||||
by building a circuit via each node to another evil node. If the
|
||||
bandwidth is high, it is (somewhat) likely that the node was a part of
|
||||
the circuit.
|
||||
|
||||
This problem does not exist if the reputation is global and nodes only
|
||||
follow the global reputation, i.e., completely ignore their own view.
|
||||
|
||||
3.13. DoS through high priority traffic.
|
||||
|
||||
Assume there is an evil node with high reputation (or high value on
|
||||
Alice) and this evil node wants to deny the service to Alice. What it
|
||||
needs to do is to send a lot of traffic to Alice. To Alice, all traffic
|
||||
from this evil node is of high priority. If the choice of circuits are
|
||||
too based toward high priority circuits, Alice would spend most of her
|
||||
available bandwidth on this circuit, thus providing poor bandwidth to
|
||||
everyone else. Everyone else would start to dislike Alice, making it
|
||||
even harder for her to forward other nodes' traffic. This could cause
|
||||
Alice to have a low reputation, and the only high bandwidth circuit
|
||||
Alice could use would be via the evil node.
|
||||
|
||||
3.14. If you run a fast server, can you run your client elsewhere?
|
||||
|
||||
A lot of people want to run a fast server at a colocation facility,
|
||||
and then reap the rewards using their cablemodem or DSL Tor client.
|
||||
|
||||
If we use anonymous micropayments, where reputation can literally
|
||||
be transferred, this is trivial.
|
||||
|
||||
If we pick a design where servers accrue reputation and can only
|
||||
use it themselves, though, the clients can configure the servers as
|
||||
their entry nodes and "inherit" their reputation. In this approach
|
||||
we would let servers configure a set of IP addresses or keys that get
|
||||
"like local" service.
|
||||
|
||||
4. Sample designs.
|
||||
|
||||
4.1. Two classes of service for circuits.
|
||||
|
||||
Whenever a circuit is built, it is specified by the origin which class,
|
||||
either "premium" or "normal", this circuit belongs. A premium circuit
|
||||
gets preferred treatment at each node. A node "spends" its value, which
|
||||
it earned a priori by providing service, to the next node by sending
|
||||
and receiving bytes. Once a node has overspent its values, the circuit
|
||||
cannot stay as premium. It either breaks or converts into a normal
|
||||
circuit. Each node also reserves a small portion of bandwidth for
|
||||
normal circuits to prevent starvation.
|
||||
|
||||
Pro: Even if a node has no value to spend, it can still use normal
|
||||
circuits. This allow casual user to use Tor without forcing them to run
|
||||
a server.
|
||||
|
||||
Pro: Nodes have incentive to forward traffic as quick and as much as
|
||||
possible to accumulate value.
|
||||
|
||||
Con: There is no proactive method for a node to rebalance its debt. It
|
||||
has to wait until there happens to be a circuit in the opposite
|
||||
direction.
|
||||
|
||||
Con: A node needs to build circuits in such a way that each node in the
|
||||
circuit has to have good values to the next node. This requires
|
||||
non-local knowledge and makes circuits less reliable as the values are
|
||||
used up in the circuit.
|
||||
|
||||
Con: May discourage nodes to forward traffic in some circuits, as they
|
||||
worry about spending more useful values to get less useful values in
|
||||
return.
|
||||
|
||||
4.2. Treat all the traffic from the node with the same service;
|
||||
hard reputation system.
|
||||
|
||||
This design is similar to 4.1, except that instead of having two
|
||||
classes of circuits, there is only one. All the circuits are
|
||||
prioritized based on the value of the interacting node.
|
||||
|
||||
Pro: It is simpler to design and give priority based on connections,
|
||||
not circuits.
|
||||
|
||||
Con: A node only needs to keep a few guard nodes happy to forward their
|
||||
traffic.
|
||||
|
||||
Con: Same as in 4.1, may discourage nodes to forward traffic in some
|
||||
circuits, as they worry about spending more useful values to get less
|
||||
useful values in return.
|
||||
|
||||
4.3. Treat all the traffic from the node with the same service;
|
||||
soft reputation system.
|
||||
|
||||
Rather than a guaranteed system with accounting (as 4.1 and 4.2),
|
||||
we instead try for a best-effort system. All bytes are in the same
|
||||
class of service. You keep track of other Tors by key, and give them
|
||||
service proportional to the service they have given you. That is, in
|
||||
the past when you have tried to push bytes through them, you track the
|
||||
number of bytes and the average bandwidth, and use that to weight the
|
||||
priority of their connections if they try to push bytes through you.
|
||||
|
||||
Now you're going to get minimum service if you don't ever push bytes
|
||||
for other people, and you get increasingly improved service the more
|
||||
active you are. We should have memories fade over time (we'll have
|
||||
to tune that, which could be quite hard).
|
||||
|
||||
Pro: Sybil attacks are pointless because new identities get lowest
|
||||
priority.
|
||||
|
||||
Pro: Smoothly handles periods of both low and high network load. Rather
|
||||
than keeping track of the ratio/difference between what he's done for
|
||||
you and what you've done for him, simply keep track of what he's done
|
||||
for you, and give him priority based on that.
|
||||
|
||||
Based on 3.3 above, it seems we should reward all the nodes in our
|
||||
path, not just the first one -- otherwise the node can provide good
|
||||
service only to its guards. On the other hand, there might be a
|
||||
second-order effect where you want nodes to like you so that *when*
|
||||
your guards choose you for a circuit, they'll be able to get good
|
||||
performance. This tradeoff needs more simulation/analysis.
|
||||
|
||||
This approach focuses on incenting people to relay traffic, but it
|
||||
doesn't do much for incenting them to allow exits. It may help in
|
||||
one way through: if there are few exits, then they will attract a
|
||||
lot of use, so lots of people will like them, so when they try to
|
||||
use the network they will find their first hop to be particularly
|
||||
pleasant. After that they're like the rest of the world though. (An
|
||||
alternative would be to reward exit nodes with higher values. At the
|
||||
extreme, we could even ask the directory servers to suggest the extra
|
||||
values, based on the current availability of exit nodes.)
|
||||
|
||||
Pro: this is a pretty easy design to add; and it can be phased in
|
||||
incrementally simply by having new nodes behave differently.
|
||||
|
||||
4.4. Centralized opinions from the reputation servers.
|
||||
|
||||
Have a set of official measurers who spot-check servers from the
|
||||
directory to see if they really do offer roughly the bandwidth
|
||||
they advertise. Include these observations in the directory. (For
|
||||
simplicity, the directory servers could be the measurers.) Then Tor
|
||||
servers give priority to other servers. We'd like to weight the
|
||||
priority by advertised bandwidth to encourage people to donate more,
|
||||
but it seems hard to distinguish between a slow server and a busy
|
||||
server.
|
||||
|
||||
The spot-checking can be done anonymously to prevent selectively
|
||||
performing only for the measurers, because hey, we have an anonymity
|
||||
network.
|
||||
|
||||
We could also reward exit nodes by giving them better priority, but
|
||||
like above this only will affect their first hop. Another problem
|
||||
is that it's darn hard to spot-check whether a server allows exits
|
||||
to all the pieces of the Internet that it claims to. If necessary,
|
||||
perhaps this can be solved by a distributed reporting mechanism,
|
||||
where clients that can reach a site from one exit but not another
|
||||
anonymously submit that site to the measurers, who verify.
|
||||
|
||||
A last problem is that since directory servers will be doing their
|
||||
tests directly (easy to detect) or indirectly (through other Tor
|
||||
servers), then we know that we can get away with poor performance for
|
||||
people that aren't listed in the directory. Maybe we can turn this
|
||||
around and call it a feature though -- another reason to get listed
|
||||
in the directory.
|
||||
|
||||
5. Recommendations and next steps.
|
||||
|
||||
5.1. Simulation.
|
||||
|
||||
For simulation trace, we can use two: one is what we obtained from Tor
|
||||
and one from existing web traces.
|
||||
|
||||
We want to simulate all the four cases in 4.1-4. For 4.4, we may want
|
||||
to look at two variations: (1) the directory servers check the
|
||||
bandwidth themselves through Tor; (2) each node reports their perceived
|
||||
values on other nodes, while the directory servers use EigenTrust to
|
||||
compute global reputation and broadcast those.
|
||||
|
||||
5.2. Deploying into existing Tor network.
|
||||
|
@ -14,9 +14,8 @@ tor-fw-helper - Manage upstream firewall/NAT devices
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
**tor-fw-helper** [-h|--help] [-T|--test] [-v|--verbose] [-g|--fetch-public-ip]
|
||||
-i|--internal-or-port __TCP port__ [-e|--external-or-port _TCP port_]
|
||||
[-d|--internal-dir-port _TCP port_] [-p|--external-dir-port _TCP port_]
|
||||
**tor-fw-helper** [-h|--help] [-T|--test-commandline] [-v|--verbose] [-g|--fetch-public-ip]
|
||||
[-p __external port__:__internal_port__]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -31,18 +30,19 @@ OPTIONS
|
||||
**-h** or **--help**::
|
||||
Display help text and exit.
|
||||
|
||||
**-v**::
|
||||
**-v** or **--verbose**::
|
||||
Display verbose output.
|
||||
|
||||
**-T** or **--test**::
|
||||
**-T** or **--test-commandline**::
|
||||
Display test information and print the test information in
|
||||
tor-fw-helper.log
|
||||
|
||||
**-g** or **--fetch-public-ip**::
|
||||
Fetch the the public ip address for each supported NAT helper method.
|
||||
|
||||
**-p** or **--forward-port** __external_port__:__internal_port__::
|
||||
Forward external_port to internal_port.
|
||||
**-p** or **--port** __external_port__:__internal_port__::
|
||||
Forward external_port to internal_port. This option can appear
|
||||
more than once.
|
||||
|
||||
BUGS
|
||||
----
|
||||
|
@ -1049,6 +1049,12 @@ The following options are useful only for clients (that is, if
|
||||
If UseEntryGuardsAsDirectoryGuards is enabled, we try to make sure we
|
||||
have at least NUM routers to use as directory guards. (Default: 3)
|
||||
|
||||
**GuardLifetime** __N__ **days**|**weeks**|**months**::
|
||||
If nonzero, and UseEntryGuards is set, minimum time to keep a guard before
|
||||
picking a new one. If zero, we use the GuardLifetime parameter from the
|
||||
consensus directory. No value here may be less than 1 month or greater
|
||||
than 5 years; out-of-range values are clamped. (Default: 0)
|
||||
|
||||
**SafeSocks** **0**|**1**::
|
||||
When this option is enabled, Tor will reject application connections that
|
||||
use unsafe variants of the socks protocol -- ones that only provide an IP
|
||||
@ -1426,6 +1432,9 @@ is non-zero):
|
||||
same circuit. (Each server only needs to list the other servers in its
|
||||
family; it doesn't need to list itself, but it won't hurt.) Do not list
|
||||
any bridge relay as it would compromise its concealment.
|
||||
+
|
||||
When listing a node, it's better to list it by fingerprint than by
|
||||
nickname: fingerprints are more reliable.
|
||||
|
||||
**Nickname** __name__::
|
||||
Set the server's nickname to \'name'. Nicknames must be between 1 and 19
|
||||
@ -2013,6 +2022,11 @@ The following options are used for running a testing Tor network.
|
||||
time. Changing this requires that **TestingTorNetwork** is set. (Default:
|
||||
10 minutes)
|
||||
|
||||
**TestingMinFastFlagThreshold** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**::
|
||||
Minimum value for the Fast flag. Overrides the ordinary minimum taken
|
||||
from the consensus when TestingTorNetwork is set. (Default: 0.)
|
||||
|
||||
|
||||
SIGNALS
|
||||
-------
|
||||
|
||||
@ -2139,7 +2153,7 @@ __HiddenServiceDirectory__**/client_keys**::
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
**privoxy**(1), **tsocks**(1), **torify**(1) +
|
||||
**privoxy**(1), **torsocks**(1), **torify**(1) +
|
||||
|
||||
**https://www.torproject.org/**
|
||||
|
||||
|
@ -9,7 +9,7 @@ torify(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
torify - wrapper for torsocks or tsocks and tor
|
||||
torify - wrapper for torsocks and tor
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
@ -18,36 +18,24 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
**torify** is a simple wrapper that attempts to find the best underlying Tor
|
||||
wrapper available on a system. It calls torsocks or tsocks with a tor specific
|
||||
wrapper available on a system. It calls torsocks with a tor specific
|
||||
configuration file. +
|
||||
|
||||
torsocks is an improved wrapper that explicitly rejects UDP, safely resolves DNS
|
||||
lookups and properly socksifies your TCP connections. +
|
||||
|
||||
tsocks itself is a wrapper between the tsocks library and the application that
|
||||
you would like to run socksified. +
|
||||
|
||||
Please note that since both method use LD_PRELOAD, torify cannot be applied to
|
||||
suid binaries.
|
||||
|
||||
WARNING
|
||||
-------
|
||||
You should also be aware that the way tsocks currently works only TCP
|
||||
connections are socksified. Be aware that this will in most circumstances not
|
||||
include hostname lookups which would still be routed through your normal system
|
||||
resolver to your usual resolving nameservers. The **tor-resolve**(1) tool can be
|
||||
useful as a workaround in some cases. The Tor FAQ at
|
||||
https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ might have further
|
||||
information on this subject. +
|
||||
|
||||
When used with torsocks, torify should not leak DNS requests or UDP data. +
|
||||
|
||||
Both will leak ICMP data.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
**tor**(1), **tor-resolve**(1), **torsocks**(1), **tsocks**(1),
|
||||
**tsocks.conf**(5).
|
||||
**tor**(1), **tor-resolve**(1), **torsocks**(1)
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
|
@ -817,7 +817,8 @@ tor_addr_is_loopback(const tor_addr_t *addr)
|
||||
case AF_INET6: {
|
||||
/* ::1 */
|
||||
uint32_t *a32 = tor_addr_to_in6_addr32(addr);
|
||||
return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) && (a32[3] == 1);
|
||||
return (a32[0] == 0) && (a32[1] == 0) && (a32[2] == 0) &&
|
||||
(ntohl(a32[3]) == 1);
|
||||
}
|
||||
case AF_INET:
|
||||
/* 127.0.0.1 */
|
||||
@ -1565,32 +1566,6 @@ addr_mask_get_bits(uint32_t mask)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Compare two addresses <b>a1</b> and <b>a2</b> for equality under a
|
||||
* netmask of <b>mbits</b> bits. Return -1, 0, or 1.
|
||||
*
|
||||
* XXXX_IP6 Temporary function to allow masks as bitcounts everywhere. This
|
||||
* will be replaced with an IPv6-aware version as soon as 32-bit addresses are
|
||||
* no longer passed around.
|
||||
*/
|
||||
int
|
||||
addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits)
|
||||
{
|
||||
if (bits > 32)
|
||||
bits = 32;
|
||||
else if (bits == 0)
|
||||
return 0;
|
||||
|
||||
a1 >>= (32-bits);
|
||||
a2 >>= (32-bits);
|
||||
|
||||
if (a1 < a2)
|
||||
return -1;
|
||||
else if (a1 > a2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Parse a string <b>s</b> in the format of (*|port(-maxport)?)?, setting the
|
||||
* various *out pointers as appropriate. Return 0 on success, -1 on failure.
|
||||
*/
|
||||
@ -1643,93 +1618,6 @@ parse_port_range(const char *port, uint16_t *port_min_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Parse a string <b>s</b> in the format of
|
||||
* (IP(/mask|/mask-bits)?|*)(:(*|port(-maxport))?)?, setting the various
|
||||
* *out pointers as appropriate. Return 0 on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
parse_addr_and_port_range(const char *s, uint32_t *addr_out,
|
||||
maskbits_t *maskbits_out, uint16_t *port_min_out,
|
||||
uint16_t *port_max_out)
|
||||
{
|
||||
char *address;
|
||||
char *mask, *port, *endptr;
|
||||
struct in_addr in;
|
||||
int bits;
|
||||
|
||||
tor_assert(s);
|
||||
tor_assert(addr_out);
|
||||
tor_assert(maskbits_out);
|
||||
tor_assert(port_min_out);
|
||||
tor_assert(port_max_out);
|
||||
|
||||
address = tor_strdup(s);
|
||||
/* Break 'address' into separate strings.
|
||||
*/
|
||||
mask = strchr(address,'/');
|
||||
port = strchr(mask?mask:address,':');
|
||||
if (mask)
|
||||
*mask++ = '\0';
|
||||
if (port)
|
||||
*port++ = '\0';
|
||||
/* Now "address" is the IP|'*' part...
|
||||
* "mask" is the Mask|Maskbits part...
|
||||
* and "port" is the *|port|min-max part.
|
||||
*/
|
||||
|
||||
if (strcmp(address,"*")==0) {
|
||||
*addr_out = 0;
|
||||
} else if (tor_inet_aton(address, &in) != 0) {
|
||||
*addr_out = ntohl(in.s_addr);
|
||||
} else {
|
||||
log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.",
|
||||
escaped(address));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!mask) {
|
||||
if (strcmp(address,"*")==0)
|
||||
*maskbits_out = 0;
|
||||
else
|
||||
*maskbits_out = 32;
|
||||
} else {
|
||||
endptr = NULL;
|
||||
bits = (int) strtol(mask, &endptr, 10);
|
||||
if (!*endptr) {
|
||||
/* strtol handled the whole mask. */
|
||||
if (bits < 0 || bits > 32) {
|
||||
log_warn(LD_GENERAL,
|
||||
"Bad number of mask bits on address range; rejecting.");
|
||||
goto err;
|
||||
}
|
||||
*maskbits_out = bits;
|
||||
} else if (tor_inet_aton(mask, &in) != 0) {
|
||||
bits = addr_mask_get_bits(ntohl(in.s_addr));
|
||||
if (bits < 0) {
|
||||
log_warn(LD_GENERAL,
|
||||
"Mask %s on address range isn't a prefix; dropping",
|
||||
escaped(mask));
|
||||
goto err;
|
||||
}
|
||||
*maskbits_out = bits;
|
||||
} else {
|
||||
log_warn(LD_GENERAL,
|
||||
"Malformed mask %s on address range; rejecting.",
|
||||
escaped(mask));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_port_range(port, port_min_out, port_max_out)<0)
|
||||
goto err;
|
||||
|
||||
tor_free(address);
|
||||
return 0;
|
||||
err:
|
||||
tor_free(address);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
|
||||
* write it as a string into the <b>buf_len</b>-byte buffer in
|
||||
* <b>buf</b>.
|
||||
|
@ -219,11 +219,7 @@ int addr_port_lookup(int severity, const char *addrport, char **address,
|
||||
uint32_t *addr, uint16_t *port_out);
|
||||
int parse_port_range(const char *port, uint16_t *port_min_out,
|
||||
uint16_t *port_max_out);
|
||||
int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
|
||||
maskbits_t *maskbits_out, uint16_t *port_min_out,
|
||||
uint16_t *port_max_out);
|
||||
int addr_mask_get_bits(uint32_t mask);
|
||||
int addr_mask_cmp_bits(uint32_t a1, uint32_t a2, maskbits_t bits);
|
||||
/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
|
||||
#define INET_NTOA_BUF_LEN 16
|
||||
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
|
||||
|
@ -137,8 +137,13 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
|
||||
|
||||
fd = open(path, flags, mode);
|
||||
#ifdef FD_CLOEXEC
|
||||
if (fd >= 0)
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
}
|
||||
@ -150,8 +155,13 @@ tor_fopen_cloexec(const char *path, const char *mode)
|
||||
{
|
||||
FILE *result = fopen(path, mode);
|
||||
#ifdef FD_CLOEXEC
|
||||
if (result != NULL)
|
||||
fcntl(fileno(result), F_SETFD, FD_CLOEXEC);
|
||||
if (result != NULL) {
|
||||
if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
fclose(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
@ -1024,7 +1034,15 @@ tor_open_socket(int domain, int type, int protocol)
|
||||
return s;
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC);
|
||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
#if defined(_WIN32)
|
||||
closesocket(s);
|
||||
#else
|
||||
close(s);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
goto socket_ok; /* So that socket_ok will not be unused. */
|
||||
@ -1059,7 +1077,11 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
|
||||
return s;
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC);
|
||||
if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno));
|
||||
close(s);
|
||||
return TOR_INVALID_SOCKET;
|
||||
}
|
||||
#endif
|
||||
|
||||
goto socket_ok; /* So that socket_ok will not be unused. */
|
||||
@ -1083,17 +1105,31 @@ get_n_open_sockets(void)
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Turn <b>socket</b> into a nonblocking socket.
|
||||
/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1
|
||||
* on failure.
|
||||
*/
|
||||
void
|
||||
int
|
||||
set_socket_nonblocking(tor_socket_t socket)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
unsigned long nonblocking = 1;
|
||||
ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking);
|
||||
#else
|
||||
fcntl(socket, F_SETFL, O_NONBLOCK);
|
||||
int flags;
|
||||
|
||||
flags = fcntl(socket, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
flags |= O_NONBLOCK;
|
||||
if (fcntl(socket, F_SETFL, flags) == -1) {
|
||||
log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1136,10 +1172,22 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
|
||||
return -errno;
|
||||
|
||||
#if defined(FD_CLOEXEC)
|
||||
if (SOCKET_OK(fd[0]))
|
||||
fcntl(fd[0], F_SETFD, FD_CLOEXEC);
|
||||
if (SOCKET_OK(fd[1]))
|
||||
fcntl(fd[1], F_SETFD, FD_CLOEXEC);
|
||||
if (SOCKET_OK(fd[0])) {
|
||||
r = fcntl(fd[0], F_SETFD, FD_CLOEXEC);
|
||||
if (r == -1) {
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
if (SOCKET_OK(fd[1])) {
|
||||
r = fcntl(fd[1], F_SETFD, FD_CLOEXEC);
|
||||
if (r == -1) {
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
goto sockets_ok; /* So that sockets_ok will not be unused. */
|
||||
|
||||
@ -2265,8 +2313,33 @@ compute_num_cpus_impl(void)
|
||||
return (int)info.dwNumberOfProcessors;
|
||||
else
|
||||
return -1;
|
||||
#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
|
||||
long cpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
#elif defined(HAVE_SYSCONF)
|
||||
#ifdef _SC_NPROCESSORS_CONF
|
||||
long cpus_conf = sysconf(_SC_NPROCESSORS_CONF);
|
||||
#else
|
||||
long cpus_conf = -1;
|
||||
#endif
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
long cpus_onln = -1;
|
||||
#endif
|
||||
long cpus = -1;
|
||||
|
||||
if (cpus_conf > 0 && cpus_onln < 0) {
|
||||
cpus = cpus_conf;
|
||||
} else if (cpus_onln > 0 && cpus_conf < 0) {
|
||||
cpus = cpus_onln;
|
||||
} else if (cpus_onln > 0 && cpus_conf > 0) {
|
||||
if (cpus_onln < cpus_conf) {
|
||||
log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
|
||||
"are available. Telling Tor to only use %ld. You can over"
|
||||
"ride this with the NumCPUs option",
|
||||
cpus_conf, cpus_onln, cpus_onln);
|
||||
}
|
||||
cpus = cpus_onln;
|
||||
}
|
||||
|
||||
if (cpus >= 1 && cpus < INT_MAX)
|
||||
return (int)cpus;
|
||||
else
|
||||
|
@ -518,7 +518,7 @@ int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
|
||||
const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
|
||||
int tor_inet_pton(int af, const char *src, void *dst);
|
||||
int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2));
|
||||
void set_socket_nonblocking(tor_socket_t socket);
|
||||
int set_socket_nonblocking(tor_socket_t socket);
|
||||
int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
|
||||
int network_init(void);
|
||||
|
||||
|
@ -675,11 +675,6 @@ median_int32(int32_t *array, int n_elements)
|
||||
{
|
||||
return find_nth_int32(array, n_elements, (n_elements-1)/2);
|
||||
}
|
||||
static INLINE long
|
||||
median_long(long *array, int n_elements)
|
||||
{
|
||||
return find_nth_long(array, n_elements, (n_elements-1)/2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -113,8 +113,8 @@ crypto_get_rsa_padding_overhead(int padding)
|
||||
{
|
||||
switch (padding)
|
||||
{
|
||||
case RSA_PKCS1_OAEP_PADDING: return 42;
|
||||
case RSA_PKCS1_PADDING: return 11;
|
||||
case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
|
||||
case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD;
|
||||
default: tor_assert(0); return -1;
|
||||
}
|
||||
}
|
||||
@ -1294,23 +1294,6 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff <b>s</b> is in the correct format for a fingerprint.
|
||||
*/
|
||||
int
|
||||
crypto_pk_check_fingerprint_syntax(const char *s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < FINGERPRINT_LEN; ++i) {
|
||||
if ((i%5) == 4) {
|
||||
if (!TOR_ISSPACE(s[i])) return 0;
|
||||
} else {
|
||||
if (!TOR_ISXDIGIT(s[i])) return 0;
|
||||
}
|
||||
}
|
||||
if (s[FINGERPRINT_LEN]) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* symmetric crypto */
|
||||
|
||||
/** Return a pointer to the key set for the cipher in <b>env</b>.
|
||||
@ -3000,6 +2983,12 @@ memwipe(void *mem, uint8_t byte, size_t sz)
|
||||
}
|
||||
|
||||
#ifdef TOR_IS_MULTITHREADED
|
||||
|
||||
#ifndef OPENSSL_THREADS
|
||||
#error OpenSSL has been built without thread support. Tor requires an \
|
||||
OpenSSL library with thread support enabled.
|
||||
#endif
|
||||
|
||||
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
|
||||
static void
|
||||
openssl_locking_cb_(int mode, int n, const char *file, int line)
|
||||
|
@ -183,7 +183,6 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
|
||||
int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
|
||||
int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
|
||||
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
|
||||
int crypto_pk_check_fingerprint_syntax(const char *s);
|
||||
|
||||
/* symmetric crypto */
|
||||
const char *crypto_cipher_get_key(crypto_cipher_t *env);
|
||||
|
@ -169,7 +169,7 @@ curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
|
||||
|
||||
end:
|
||||
if (content) {
|
||||
memwipe(content, 0, st.st_size);
|
||||
memwipe(content, 0, (size_t) st.st_size);
|
||||
tor_free(content);
|
||||
}
|
||||
if (r != 0) {
|
||||
|
@ -1997,6 +1997,10 @@ tor_tls_free(tor_tls_t *tls)
|
||||
if (!tls)
|
||||
return;
|
||||
tor_assert(tls->ssl);
|
||||
{
|
||||
size_t r,w;
|
||||
tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
|
||||
}
|
||||
#ifdef SSL_set_tlsext_host_name
|
||||
SSL_set_tlsext_host_name(tls->ssl, NULL);
|
||||
#endif
|
||||
@ -2048,6 +2052,13 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/** Total number of bytes that we've used TLS to send. Used to track TLS
|
||||
* overhead. */
|
||||
static uint64_t total_bytes_written_over_tls = 0;
|
||||
/** Total number of bytes that TLS has put on the network for us. Used to
|
||||
* track TLS overhead. */
|
||||
static uint64_t total_bytes_written_by_tls = 0;
|
||||
|
||||
/** Underlying function for TLS writing. Write up to <b>n</b>
|
||||
* characters from <b>cp</b> onto <b>tls</b>. On success, returns the
|
||||
* number of characters written. On failure, returns TOR_TLS_ERROR,
|
||||
@ -2074,6 +2085,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
|
||||
r = SSL_write(tls->ssl, cp, (int)n);
|
||||
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
|
||||
if (err == TOR_TLS_DONE) {
|
||||
total_bytes_written_over_tls += r;
|
||||
return r;
|
||||
}
|
||||
if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
|
||||
@ -2563,10 +2575,23 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
|
||||
"r=%lu, last_read=%lu, w=%lu, last_written=%lu",
|
||||
r, tls->last_read_count, w, tls->last_write_count);
|
||||
}
|
||||
total_bytes_written_by_tls += *n_written;
|
||||
tls->last_read_count = r;
|
||||
tls->last_write_count = w;
|
||||
}
|
||||
|
||||
/** Return a ratio of the bytes that TLS has sent to the bytes that we've told
|
||||
* it to send. Used to track whether our TLS records are getting too tiny. */
|
||||
double
|
||||
tls_get_write_overhead_ratio(void)
|
||||
{
|
||||
if (total_bytes_written_over_tls == 0)
|
||||
return 1.0;
|
||||
|
||||
return U64_TO_DBL(total_bytes_written_by_tls) /
|
||||
U64_TO_DBL(total_bytes_written_over_tls);
|
||||
}
|
||||
|
||||
/** Implement check_no_tls_errors: If there are any pending OpenSSL
|
||||
* errors, log an error message. */
|
||||
void
|
||||
|
@ -95,6 +95,8 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls,
|
||||
size_t *rbuf_capacity, size_t *rbuf_bytes,
|
||||
size_t *wbuf_capacity, size_t *wbuf_bytes);
|
||||
|
||||
double tls_get_write_overhead_ratio(void);
|
||||
|
||||
int tor_tls_used_v1_handshake(tor_tls_t *tls);
|
||||
int tor_tls_received_v3_certificate(tor_tls_t *tls);
|
||||
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
|
||||
|
@ -1176,119 +1176,10 @@ escaped(const char *s)
|
||||
return escaped_val_;
|
||||
}
|
||||
|
||||
/** Rudimentary string wrapping code: given a un-wrapped <b>string</b> (no
|
||||
* newlines!), break the string into newline-terminated lines of no more than
|
||||
* <b>width</b> characters long (not counting newline) and insert them into
|
||||
* <b>out</b> in order. Precede the first line with prefix0, and subsequent
|
||||
* lines with prefixRest.
|
||||
*/
|
||||
/* This uses a stupid greedy wrapping algorithm right now:
|
||||
* - For each line:
|
||||
* - Try to fit as much stuff as possible, but break on a space.
|
||||
* - If the first "word" of the line will extend beyond the allowable
|
||||
* width, break the word at the end of the width.
|
||||
*/
|
||||
void
|
||||
wrap_string(smartlist_t *out, const char *string, size_t width,
|
||||
const char *prefix0, const char *prefixRest)
|
||||
{
|
||||
size_t p0Len, pRestLen, pCurLen;
|
||||
const char *eos, *prefixCur;
|
||||
tor_assert(out);
|
||||
tor_assert(string);
|
||||
tor_assert(width);
|
||||
if (!prefix0)
|
||||
prefix0 = "";
|
||||
if (!prefixRest)
|
||||
prefixRest = "";
|
||||
|
||||
p0Len = strlen(prefix0);
|
||||
pRestLen = strlen(prefixRest);
|
||||
tor_assert(width > p0Len && width > pRestLen);
|
||||
eos = strchr(string, '\0');
|
||||
tor_assert(eos);
|
||||
pCurLen = p0Len;
|
||||
prefixCur = prefix0;
|
||||
|
||||
while ((eos-string)+pCurLen > width) {
|
||||
const char *eol = string + width - pCurLen;
|
||||
while (eol > string && *eol != ' ')
|
||||
--eol;
|
||||
/* eol is now the last space that can fit, or the start of the string. */
|
||||
if (eol > string) {
|
||||
size_t line_len = (eol-string) + pCurLen + 2;
|
||||
char *line = tor_malloc(line_len);
|
||||
memcpy(line, prefixCur, pCurLen);
|
||||
memcpy(line+pCurLen, string, eol-string);
|
||||
line[line_len-2] = '\n';
|
||||
line[line_len-1] = '\0';
|
||||
smartlist_add(out, line);
|
||||
string = eol + 1;
|
||||
} else {
|
||||
size_t line_len = width + 2;
|
||||
char *line = tor_malloc(line_len);
|
||||
memcpy(line, prefixCur, pCurLen);
|
||||
memcpy(line+pCurLen, string, width - pCurLen);
|
||||
line[line_len-2] = '\n';
|
||||
line[line_len-1] = '\0';
|
||||
smartlist_add(out, line);
|
||||
string += width-pCurLen;
|
||||
}
|
||||
prefixCur = prefixRest;
|
||||
pCurLen = pRestLen;
|
||||
}
|
||||
|
||||
if (string < eos) {
|
||||
size_t line_len = (eos-string) + pCurLen + 2;
|
||||
char *line = tor_malloc(line_len);
|
||||
memcpy(line, prefixCur, pCurLen);
|
||||
memcpy(line+pCurLen, string, eos-string);
|
||||
line[line_len-2] = '\n';
|
||||
line[line_len-1] = '\0';
|
||||
smartlist_add(out, line);
|
||||
}
|
||||
}
|
||||
|
||||
/* =====
|
||||
* Time
|
||||
* ===== */
|
||||
|
||||
/**
|
||||
* Converts struct timeval to a double value.
|
||||
* Preserves microsecond precision, but just barely.
|
||||
* Error is approx +/- 0.1 usec when dealing with epoch values.
|
||||
*/
|
||||
double
|
||||
tv_to_double(const struct timeval *tv)
|
||||
{
|
||||
double conv = tv->tv_sec;
|
||||
conv += tv->tv_usec/1000000.0;
|
||||
return conv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts timeval to milliseconds.
|
||||
*/
|
||||
int64_t
|
||||
tv_to_msec(const struct timeval *tv)
|
||||
{
|
||||
int64_t conv = ((int64_t)tv->tv_sec)*1000L;
|
||||
/* Round ghetto-style */
|
||||
conv += ((int64_t)tv->tv_usec+500)/1000L;
|
||||
return conv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts timeval to microseconds.
|
||||
*/
|
||||
int64_t
|
||||
tv_to_usec(const struct timeval *tv)
|
||||
{
|
||||
int64_t conv = ((int64_t)tv->tv_sec)*1000000L;
|
||||
conv += tv->tv_usec;
|
||||
return conv;
|
||||
}
|
||||
|
||||
/** Return the number of microseconds elapsed between *start and *end.
|
||||
*/
|
||||
long
|
||||
@ -2537,10 +2428,13 @@ unescape_string(const char *s, char **result, size_t *size_out)
|
||||
* key portion and *<b>value_out</b> to a new string holding the value portion
|
||||
* of the line, and return a pointer to the start of the next line. If we run
|
||||
* out of data, return a pointer to the end of the string. If we encounter an
|
||||
* error, return NULL.
|
||||
* error, return NULL and set *<b>err_out</b> (if provided) to an error
|
||||
* message.
|
||||
*/
|
||||
const char *
|
||||
parse_config_line_from_str(const char *line, char **key_out, char **value_out)
|
||||
parse_config_line_from_str_verbose(const char *line, char **key_out,
|
||||
char **value_out,
|
||||
const char **err_out)
|
||||
{
|
||||
/* I believe the file format here is supposed to be:
|
||||
FILE = (EMPTYLINE | LINE)* (EMPTYLASTLINE | LASTLINE)?
|
||||
@ -2614,12 +2508,18 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
|
||||
|
||||
/* Find the end of the line. */
|
||||
if (*line == '\"') { // XXX No continuation handling is done here
|
||||
if (!(line = unescape_string(line, value_out, NULL)))
|
||||
return NULL;
|
||||
if (!(line = unescape_string(line, value_out, NULL))) {
|
||||
if (err_out)
|
||||
*err_out = "Invalid escape sequence in quoted string";
|
||||
return NULL;
|
||||
}
|
||||
while (*line == ' ' || *line == '\t')
|
||||
++line;
|
||||
if (*line && *line != '#' && *line != '\n')
|
||||
if (*line && *line != '#' && *line != '\n') {
|
||||
if (err_out)
|
||||
*err_out = "Excess data after quoted string";
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* Look for the end of the line. */
|
||||
while (*line && *line != '\n' && (*line != '#' || continuation)) {
|
||||
|
@ -112,7 +112,6 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
|
||||
#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS)
|
||||
#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS)
|
||||
#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS)
|
||||
#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
|
||||
#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS)
|
||||
#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS)
|
||||
#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS)
|
||||
@ -173,6 +172,17 @@ int n_bits_set_u8(uint8_t v);
|
||||
* overflow. */
|
||||
#define CEIL_DIV(a,b) (((a)+(b)-1)/(b))
|
||||
|
||||
/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise
|
||||
* return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if
|
||||
* <b>b</b> is larger than <b>max</b>.
|
||||
*
|
||||
* Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of
|
||||
* its arguments more than once! */
|
||||
#define CLAMP(min,v,max) \
|
||||
( ((v) < (min)) ? (min) : \
|
||||
((v) > (max)) ? (max) : \
|
||||
(v) )
|
||||
|
||||
/* String manipulation */
|
||||
|
||||
/** Allowable characters in a hexadecimal string. */
|
||||
@ -216,8 +226,6 @@ int tor_digest256_is_zero(const char *digest);
|
||||
char *esc_for_log(const char *string) ATTR_MALLOC;
|
||||
const char *escaped(const char *string);
|
||||
struct smartlist_t;
|
||||
void wrap_string(struct smartlist_t *out, const char *string, size_t width,
|
||||
const char *prefix0, const char *prefixRest);
|
||||
int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(scanf, 2, 0)))
|
||||
@ -240,9 +248,6 @@ void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||
|
||||
/* Time helpers */
|
||||
double tv_to_double(const struct timeval *tv);
|
||||
int64_t tv_to_msec(const struct timeval *tv);
|
||||
int64_t tv_to_usec(const struct timeval *tv);
|
||||
long tv_udiff(const struct timeval *start, const struct timeval *end);
|
||||
long tv_mdiff(const struct timeval *start, const struct timeval *end);
|
||||
int tor_timegm(const struct tm *tm, time_t *time_out);
|
||||
@ -375,8 +380,11 @@ char *read_file_to_str(const char *filename, int flags, struct stat *stat_out)
|
||||
char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
|
||||
size_t *sz_out)
|
||||
ATTR_MALLOC;
|
||||
const char *parse_config_line_from_str(const char *line,
|
||||
char **key_out, char **value_out);
|
||||
const char *parse_config_line_from_str_verbose(const char *line,
|
||||
char **key_out, char **value_out,
|
||||
const char **err_out);
|
||||
#define parse_config_line_from_str(line,key_out,value_out) \
|
||||
parse_config_line_from_str_verbose((line),(key_out),(value_out),NULL)
|
||||
char *expand_filename(const char *filename);
|
||||
struct smartlist_t *tor_listdir(const char *dirname);
|
||||
int path_is_relative(const char *filename);
|
||||
|
20949
src/config/geoip
20949
src/config/geoip
File diff suppressed because it is too large
Load Diff
@ -2306,7 +2306,12 @@ _evdns_nameserver_add_impl(const struct sockaddr *address,
|
||||
ioctlsocket(ns->socket, FIONBIO, &nonblocking);
|
||||
}
|
||||
#else
|
||||
fcntl(ns->socket, F_SETFL, O_NONBLOCK);
|
||||
if (fcntl(ns->socket, F_SETFL, O_NONBLOCK) == -1) {
|
||||
evdns_log(EVDNS_LOG_WARN, "Error %s (%d) while settings file status flags.",
|
||||
tor_socket_strerror(errno), errno);
|
||||
err = 2;
|
||||
goto out2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (global_bind_addr_is_set &&
|
||||
|
@ -560,7 +560,7 @@ addressmap_register(const char *address, char *new_address, time_t expires,
|
||||
log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
|
||||
safe_str_client(address),
|
||||
safe_str_client(ent->new_address));
|
||||
control_event_address_mapped(address, ent->new_address, expires, NULL);
|
||||
control_event_address_mapped(address, ent->new_address, expires, NULL, 1);
|
||||
}
|
||||
|
||||
/** An attempt to resolve <b>address</b> failed at some OR.
|
||||
|
@ -1751,6 +1751,14 @@ channel_write_cell(channel_t *chan, cell_t *cell)
|
||||
tor_assert(chan);
|
||||
tor_assert(cell);
|
||||
|
||||
if (chan->state == CHANNEL_STATE_CLOSING) {
|
||||
log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with "
|
||||
"global ID "U64_FORMAT, cell, chan,
|
||||
U64_PRINTF_ARG(chan->global_identifier));
|
||||
tor_free(cell);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug(LD_CHANNEL,
|
||||
"Writing cell_t %p to channel %p with global ID "
|
||||
U64_FORMAT,
|
||||
@ -1777,6 +1785,14 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
|
||||
tor_assert(chan);
|
||||
tor_assert(packed_cell);
|
||||
|
||||
if (chan->state == CHANNEL_STATE_CLOSING) {
|
||||
log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p "
|
||||
"with global ID "U64_FORMAT, packed_cell, chan,
|
||||
U64_PRINTF_ARG(chan->global_identifier));
|
||||
packed_cell_free(packed_cell);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug(LD_CHANNEL,
|
||||
"Writing packed_cell_t %p to channel %p with global ID "
|
||||
U64_FORMAT,
|
||||
@ -1805,6 +1821,14 @@ channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
|
||||
tor_assert(chan);
|
||||
tor_assert(var_cell);
|
||||
|
||||
if (chan->state == CHANNEL_STATE_CLOSING) {
|
||||
log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p "
|
||||
"with global ID "U64_FORMAT, var_cell, chan,
|
||||
U64_PRINTF_ARG(chan->global_identifier));
|
||||
var_cell_free(var_cell);
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug(LD_CHANNEL,
|
||||
"Writing var_cell_t %p to channel %p with global ID "
|
||||
U64_FORMAT,
|
||||
|
@ -1208,7 +1208,7 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
|
||||
tor_assert(chan->conn->handshake_state);
|
||||
end = cell->payload + cell->payload_len;
|
||||
for (cp = cell->payload; cp+1 < end; ++cp) {
|
||||
for (cp = cell->payload; cp+1 < end; cp += 2) {
|
||||
uint16_t v = ntohs(get_uint16(cp));
|
||||
if (is_or_protocol_version_known(v) && v > highest_supported_version)
|
||||
highest_supported_version = v;
|
||||
|
@ -803,6 +803,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
||||
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0);
|
||||
}
|
||||
|
||||
pathbias_count_build_success(circ);
|
||||
circuit_rep_hist_note_result(circ);
|
||||
circuit_has_opened(circ); /* do other actions as necessary */
|
||||
|
||||
if (!can_complete_circuit && !circ->build_state->onehop_tunnel) {
|
||||
const or_options_t *options = get_options();
|
||||
can_complete_circuit=1;
|
||||
@ -819,10 +823,6 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
|
||||
}
|
||||
}
|
||||
|
||||
pathbias_count_build_success(circ);
|
||||
circuit_rep_hist_note_result(circ);
|
||||
circuit_has_opened(circ); /* do other actions as necessary */
|
||||
|
||||
/* We're done with measurement circuits here. Just close them */
|
||||
if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
|
||||
@ -901,7 +901,7 @@ circuit_note_clock_jumped(int seconds_elapsed)
|
||||
control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s",
|
||||
"CLOCK_JUMPED");
|
||||
circuit_mark_all_unused_circs();
|
||||
circuit_expire_all_dirty_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
}
|
||||
|
||||
/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
|
||||
@ -1378,7 +1378,7 @@ pathbias_should_count(origin_circuit_t *circ)
|
||||
if (circ->build_state->desired_path_len != 1 ||
|
||||
!circ->build_state->onehop_tunnel) {
|
||||
if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) {
|
||||
log_notice(LD_BUG,
|
||||
log_info(LD_BUG,
|
||||
"One-hop circuit has length %d. Path state is %s. "
|
||||
"Circuit is a %s currently %s.%s",
|
||||
circ->build_state->desired_path_len,
|
||||
@ -1539,7 +1539,7 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
||||
guard->circ_successes++;
|
||||
entry_guards_changed();
|
||||
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s",
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
} else {
|
||||
@ -1558,7 +1558,7 @@ pathbias_count_build_success(origin_circuit_t *circ)
|
||||
|
||||
if (guard->circ_attempts < guard->circ_successes) {
|
||||
log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) "
|
||||
"for guard %s=%s",
|
||||
"for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
}
|
||||
@ -1626,7 +1626,7 @@ pathbias_count_use_attempt(origin_circuit_t *circ)
|
||||
entry_guards_changed();
|
||||
|
||||
log_debug(LD_CIRC,
|
||||
"Marked circuit %d (%f/%f) as used for guard %s=%s.",
|
||||
"Marked circuit %d (%f/%f) as used for guard %s ($%s).",
|
||||
circ->global_identifier,
|
||||
guard->use_successes, guard->use_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
@ -1734,9 +1734,16 @@ pathbias_count_use_success(origin_circuit_t *circ)
|
||||
guard->use_successes++;
|
||||
entry_guards_changed();
|
||||
|
||||
if (guard->use_attempts < guard->use_successes) {
|
||||
log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) "
|
||||
"for guard %s=%s",
|
||||
guard->use_successes, guard->use_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
}
|
||||
|
||||
log_debug(LD_CIRC,
|
||||
"Marked circuit %d (%f/%f) as used successfully for guard "
|
||||
"%s=%s.",
|
||||
"%s ($%s).",
|
||||
circ->global_identifier, guard->use_successes,
|
||||
guard->use_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
@ -2010,6 +2017,9 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason)
|
||||
pathbias_count_use_failed(ocirc);
|
||||
break;
|
||||
|
||||
case PATH_STATE_NEW_CIRC:
|
||||
case PATH_STATE_BUILD_ATTEMPTED:
|
||||
case PATH_STATE_ALREADY_COUNTED:
|
||||
default:
|
||||
// Other states are uninteresting. No stats to count.
|
||||
break;
|
||||
@ -2253,7 +2263,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
if (pathbias_get_dropguards(options)) {
|
||||
if (!guard->path_bias_disabled) {
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s=%s is failing to carry an extremely large "
|
||||
"Your Guard %s ($%s) is failing to carry an extremely large "
|
||||
"amount of stream on its circuits. "
|
||||
"To avoid potential route manipulation attacks, Tor has "
|
||||
"disabled use of this guard. "
|
||||
@ -2279,7 +2289,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
} else if (!guard->path_bias_use_extreme) {
|
||||
guard->path_bias_use_extreme = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s=%s is failing to carry an extremely large "
|
||||
"Your Guard %s ($%s) is failing to carry an extremely large "
|
||||
"amount of streams on its circuits. "
|
||||
"This could indicate a route manipulation attack, network "
|
||||
"overload, bad local network connectivity, or a bug. "
|
||||
@ -2303,7 +2313,7 @@ pathbias_measure_use_rate(entry_guard_t *guard)
|
||||
if (!guard->path_bias_use_noticed) {
|
||||
guard->path_bias_use_noticed = 1;
|
||||
log_notice(LD_CIRC,
|
||||
"Your Guard %s=%s is failing to carry more streams on its "
|
||||
"Your Guard %s ($%s) is failing to carry more streams on its "
|
||||
"circuits than usual. "
|
||||
"Most likely this means the Tor network is overloaded "
|
||||
"or your network connection is poor. "
|
||||
@ -2359,7 +2369,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
if (pathbias_get_dropguards(options)) {
|
||||
if (!guard->path_bias_disabled) {
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s=%s is failing an extremely large "
|
||||
"Your Guard %s ($%s) is failing an extremely large "
|
||||
"amount of circuits. "
|
||||
"To avoid potential route manipulation attacks, Tor has "
|
||||
"disabled use of this guard. "
|
||||
@ -2385,7 +2395,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
} else if (!guard->path_bias_extreme) {
|
||||
guard->path_bias_extreme = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s=%s is failing an extremely large "
|
||||
"Your Guard %s ($%s) is failing an extremely large "
|
||||
"amount of circuits. "
|
||||
"This could indicate a route manipulation attack, "
|
||||
"extreme network overload, or a bug. "
|
||||
@ -2409,7 +2419,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
if (!guard->path_bias_warned) {
|
||||
guard->path_bias_warned = 1;
|
||||
log_warn(LD_CIRC,
|
||||
"Your Guard %s=%s is failing a very large "
|
||||
"Your Guard %s ($%s) is failing a very large "
|
||||
"amount of circuits. "
|
||||
"Most likely this means the Tor network is "
|
||||
"overloaded, but it could also mean an attack against "
|
||||
@ -2434,7 +2444,7 @@ pathbias_measure_close_rate(entry_guard_t *guard)
|
||||
if (!guard->path_bias_noticed) {
|
||||
guard->path_bias_noticed = 1;
|
||||
log_notice(LD_CIRC,
|
||||
"Your Guard %s=%s is failing more circuits than "
|
||||
"Your Guard %s ($%s) is failing more circuits than "
|
||||
"usual. "
|
||||
"Most likely this means the Tor network is overloaded. "
|
||||
"Success counts are %ld/%ld. Use counts are %ld/%ld. "
|
||||
@ -2478,6 +2488,9 @@ pathbias_scale_close_rates(entry_guard_t *guard)
|
||||
int opened_built = pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_BUILD_SUCCEEDED,
|
||||
PATH_STATE_USE_FAILED);
|
||||
/* Verify that the counts are sane before and after scaling */
|
||||
int counts_are_sane = (guard->circ_attempts >= guard->circ_successes);
|
||||
|
||||
guard->circ_attempts -= opened_attempts;
|
||||
guard->circ_successes -= opened_built;
|
||||
|
||||
@ -2495,10 +2508,20 @@ pathbias_scale_close_rates(entry_guard_t *guard)
|
||||
|
||||
log_info(LD_CIRC,
|
||||
"Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard "
|
||||
"%s=%s",
|
||||
"%s ($%s)",
|
||||
guard->circ_successes, guard->successful_circuits_closed,
|
||||
guard->circ_attempts, opened_built, opened_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
|
||||
/* Have the counts just become invalid by this scaling attempt? */
|
||||
if (counts_are_sane && guard->circ_attempts < guard->circ_successes) {
|
||||
log_notice(LD_BUG,
|
||||
"Scaling has mangled pathbias counts to %f/%f (%d/%d open) "
|
||||
"for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts, opened_built,
|
||||
opened_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2521,6 +2544,9 @@ pathbias_scale_use_rates(entry_guard_t *guard)
|
||||
double scale_ratio = pathbias_get_scale_ratio(options);
|
||||
int opened_attempts = pathbias_count_circs_in_states(guard,
|
||||
PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED);
|
||||
/* Verify that the counts are sane before and after scaling */
|
||||
int counts_are_sane = (guard->use_attempts >= guard->use_successes);
|
||||
|
||||
guard->use_attempts -= opened_attempts;
|
||||
|
||||
guard->use_attempts *= scale_ratio;
|
||||
@ -2529,9 +2555,20 @@ pathbias_scale_use_rates(entry_guard_t *guard)
|
||||
guard->use_attempts += opened_attempts;
|
||||
|
||||
log_info(LD_CIRC,
|
||||
"Scaled pathbias use counts to %f/%f (%d open) for guard %s=%s",
|
||||
guard->use_successes, guard->use_attempts, opened_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
"Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)",
|
||||
guard->use_successes, guard->use_attempts, opened_attempts,
|
||||
guard->nickname, hex_str(guard->identity, DIGEST_LEN));
|
||||
|
||||
/* Have the counts just become invalid by this scaling attempt? */
|
||||
if (counts_are_sane && guard->use_attempts < guard->use_successes) {
|
||||
log_notice(LD_BUG,
|
||||
"Scaling has mangled pathbias usage counts to %f/%f "
|
||||
"(%d open) for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts,
|
||||
opened_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
}
|
||||
|
||||
entry_guards_changed();
|
||||
}
|
||||
}
|
||||
@ -2554,7 +2591,7 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard)
|
||||
pathbias_scale_close_rates(guard);
|
||||
guard->circ_attempts++;
|
||||
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s",
|
||||
log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)",
|
||||
guard->circ_successes, guard->circ_attempts, guard->nickname,
|
||||
hex_str(guard->identity, DIGEST_LEN));
|
||||
return 0;
|
||||
@ -3398,6 +3435,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
|
||||
});
|
||||
}
|
||||
/* and exclude current entry guards and their families, if applicable */
|
||||
/*XXXX025 use the using_as_guard flag to accomplish this.*/
|
||||
if (options->UseEntryGuards) {
|
||||
SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nodelist.h"
|
||||
#include "onion.h"
|
||||
#include "onion_fast.h"
|
||||
#include "policies.h"
|
||||
#include "relay.h"
|
||||
#include "rendclient.h"
|
||||
#include "rendcommon.h"
|
||||
@ -531,6 +532,9 @@ circuit_purpose_to_string(uint8_t purpose)
|
||||
case CIRCUIT_PURPOSE_CONTROLLER:
|
||||
return "Circuit made by controller";
|
||||
|
||||
case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
|
||||
return "Path-bias testing circuit";
|
||||
|
||||
default:
|
||||
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
|
||||
return buf;
|
||||
@ -653,6 +657,7 @@ circuit_free(circuit_t *circ)
|
||||
memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len);
|
||||
tor_free(ocirc->socks_password);
|
||||
}
|
||||
addr_policy_list_free(ocirc->prepend_policy);
|
||||
} else {
|
||||
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
|
||||
/* Remember cell statistics for this circuit before deallocating. */
|
||||
@ -1204,6 +1209,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
||||
if ((!need_uptime || circ->build_state->need_uptime) &&
|
||||
(!need_capacity || circ->build_state->need_capacity) &&
|
||||
(internal == circ->build_state->is_internal) &&
|
||||
!circ->unusable_for_new_conns &&
|
||||
circ->remaining_relay_early_cells &&
|
||||
circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN &&
|
||||
!circ->build_state->onehop_tunnel &&
|
||||
@ -1299,20 +1305,17 @@ circuit_mark_all_unused_circs(void)
|
||||
* This is useful for letting the user change pseudonyms, so new
|
||||
* streams will not be linkable to old streams.
|
||||
*/
|
||||
/* XXX024 this is a bad name for what this function does */
|
||||
void
|
||||
circuit_expire_all_dirty_circs(void)
|
||||
circuit_mark_all_dirty_circs_as_unusable(void)
|
||||
{
|
||||
circuit_t *circ;
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
for (circ=global_circuitlist; circ; circ = circ->next) {
|
||||
if (CIRCUIT_IS_ORIGIN(circ) &&
|
||||
!circ->marked_for_close &&
|
||||
circ->timestamp_dirty)
|
||||
/* XXXX024 This is a screwed-up way to say "This is too dirty
|
||||
* for new circuits. */
|
||||
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
|
||||
circ->timestamp_dirty) {
|
||||
mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ or_circuit_t *circuit_get_intro_point(const char *digest);
|
||||
origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
|
||||
extend_info_t *info, int flags);
|
||||
void circuit_mark_all_unused_circs(void);
|
||||
void circuit_expire_all_dirty_circs(void);
|
||||
void circuit_mark_all_dirty_circs_as_unusable(void);
|
||||
void circuit_mark_for_close_(circuit_t *circ, int reason,
|
||||
int line, const char *file);
|
||||
int circuit_get_cpath_len(origin_circuit_t *circ);
|
||||
|
@ -417,19 +417,16 @@ circuit_build_times_get_initial_timeout(void)
|
||||
* Check if we have LearnCircuitBuildTimeout, and if we don't,
|
||||
* always use CircuitBuildTimeout, no questions asked.
|
||||
*/
|
||||
if (get_options()->LearnCircuitBuildTimeout) {
|
||||
if (!unit_tests && get_options()->CircuitBuildTimeout) {
|
||||
timeout = get_options()->CircuitBuildTimeout*1000;
|
||||
if (timeout < circuit_build_times_min_timeout()) {
|
||||
log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
|
||||
circuit_build_times_min_timeout()/1000);
|
||||
timeout = circuit_build_times_min_timeout();
|
||||
}
|
||||
} else {
|
||||
timeout = circuit_build_times_initial_timeout();
|
||||
if (!unit_tests && get_options()->CircuitBuildTimeout) {
|
||||
timeout = get_options()->CircuitBuildTimeout*1000;
|
||||
if (get_options()->LearnCircuitBuildTimeout &&
|
||||
timeout < circuit_build_times_min_timeout()) {
|
||||
log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds",
|
||||
circuit_build_times_min_timeout()/1000);
|
||||
timeout = circuit_build_times_min_timeout();
|
||||
}
|
||||
} else {
|
||||
timeout = get_options()->CircuitBuildTimeout*1000;
|
||||
timeout = circuit_build_times_initial_timeout();
|
||||
}
|
||||
|
||||
return timeout;
|
||||
@ -1235,11 +1232,11 @@ circuit_build_times_network_close(circuit_build_times_t *cbt,
|
||||
format_local_iso_time(last_live_buf, cbt->liveness.network_last_live);
|
||||
format_local_iso_time(start_time_buf, start_time);
|
||||
format_local_iso_time(now_buf, now);
|
||||
log_warn(LD_BUG,
|
||||
"Circuit somehow completed a hop while the network was "
|
||||
"not live. Network was last live at %s, but circuit launched "
|
||||
"at %s. It's now %s.", last_live_buf, start_time_buf,
|
||||
now_buf);
|
||||
log_notice(LD_CIRC,
|
||||
"A circuit somehow completed a hop while the network was "
|
||||
"not live. The network was last live at %s, but the circuit "
|
||||
"launched at %s. It's now %s. This could mean your clock "
|
||||
"changed.", last_live_buf, start_time_buf, now_buf);
|
||||
}
|
||||
cbt->liveness.nonlive_timeouts++;
|
||||
if (cbt->liveness.nonlive_timeouts == 1) {
|
||||
|
@ -85,10 +85,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
}
|
||||
|
||||
if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
||||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED)
|
||||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
||||
if (circ->timestamp_dirty &&
|
||||
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (origin_circ->unusable_for_new_conns)
|
||||
return 0;
|
||||
|
||||
/* decide if this circ is suitable for this conn */
|
||||
|
||||
@ -105,6 +109,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
return 0;
|
||||
|
||||
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
tor_addr_t addr;
|
||||
const int family = tor_addr_parse(&addr, conn->socks_request->address);
|
||||
if (!exitnode && !build_state->onehop_tunnel) {
|
||||
log_debug(LD_CIRC,"Not considering circuit with unknown router.");
|
||||
return 0; /* this circuit is screwed and doesn't know it yet,
|
||||
@ -125,9 +131,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
return 0; /* this is a circuit to somewhere else */
|
||||
if (tor_digest_is_zero(digest)) {
|
||||
/* we don't know the digest; have to compare addr:port */
|
||||
tor_addr_t addr;
|
||||
int r = tor_addr_parse(&addr, conn->socks_request->address);
|
||||
if (r < 0 ||
|
||||
if (family < 0 ||
|
||||
!tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
|
||||
build_state->chosen_exit->port != conn->socks_request->port)
|
||||
return 0;
|
||||
@ -139,6 +143,13 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (origin_circ->prepend_policy && family != -1) {
|
||||
int r = compare_tor_addr_to_addr_policy(&addr,
|
||||
conn->socks_request->port,
|
||||
origin_circ->prepend_policy);
|
||||
if (r == ADDR_POLICY_REJECTED)
|
||||
return 0;
|
||||
}
|
||||
if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) {
|
||||
/* can't exit from this router */
|
||||
return 0;
|
||||
@ -518,15 +529,25 @@ circuit_expire_building(void)
|
||||
if (timercmp(&victim->timestamp_began, &cutoff, >))
|
||||
continue; /* it's still young, leave it alone */
|
||||
|
||||
if (!any_opened_circs) {
|
||||
/* We need to double-check the opened state here because
|
||||
* we don't want to consider opened 1-hop dircon circuits for
|
||||
* deciding when to relax the timeout, but we *do* want to relax
|
||||
* those circuits too if nothing else is opened *and* they still
|
||||
* aren't either. */
|
||||
if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) {
|
||||
/* It's still young enough that we wouldn't close it, right? */
|
||||
if (timercmp(&victim->timestamp_began, &close_cutoff, >)) {
|
||||
if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
|
||||
int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
|
||||
== CPATH_STATE_OPEN;
|
||||
log_info(LD_CIRC,
|
||||
"No circuits are opened. Relaxing timeout for "
|
||||
"a circuit with channel state %s. %d guards are live.",
|
||||
"No circuits are opened. Relaxing timeout for circuit %d "
|
||||
"(a %s %d-hop circuit in state %s with channel state %s). "
|
||||
"%d guards are live.",
|
||||
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
|
||||
circuit_purpose_to_string(victim->purpose),
|
||||
TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
|
||||
circuit_state_to_string(victim->state),
|
||||
channel_state_to_string(victim->n_chan->state),
|
||||
num_live_entry_guards(0));
|
||||
|
||||
@ -541,10 +562,14 @@ circuit_expire_building(void)
|
||||
} else {
|
||||
static ratelim_t relax_timeout_limit = RATELIM_INIT(3600);
|
||||
log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC,
|
||||
"No circuits are opened. Relaxed timeout for "
|
||||
"a circuit with channel state %s to %ldms. "
|
||||
"However, it appears the circuit has timed out anyway. "
|
||||
"%d guards are live.",
|
||||
"No circuits are opened. Relaxed timeout for circuit %d "
|
||||
"(a %s %d-hop circuit in state %s with channel state %s) to "
|
||||
"%ldms. However, it appears the circuit has timed out "
|
||||
"anyway. %d guards are live.",
|
||||
TO_ORIGIN_CIRCUIT(victim)->global_identifier,
|
||||
circuit_purpose_to_string(victim->purpose),
|
||||
TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len,
|
||||
circuit_state_to_string(victim->state),
|
||||
channel_state_to_string(victim->n_chan->state),
|
||||
(long)circ_times.close_ms, num_live_entry_guards(0));
|
||||
}
|
||||
@ -660,7 +685,7 @@ circuit_expire_building(void)
|
||||
circuit_purpose_to_string(victim->purpose));
|
||||
} else if (circuit_build_times_count_close(&circ_times,
|
||||
first_hop_succeeded,
|
||||
victim->timestamp_began.tv_sec)) {
|
||||
victim->timestamp_created.tv_sec)) {
|
||||
circuit_build_times_set_timeout(&circ_times);
|
||||
}
|
||||
}
|
||||
@ -799,9 +824,12 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
|
||||
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
|
||||
(!circ->timestamp_dirty ||
|
||||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
|
||||
cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
|
||||
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
cpath_build_state_t *build_state = origin_circ->build_state;
|
||||
if (build_state->is_internal || build_state->onehop_tunnel)
|
||||
continue;
|
||||
if (!origin_circ->unusable_for_new_conns)
|
||||
continue;
|
||||
|
||||
exitnode = build_state_get_exit_node(build_state);
|
||||
if (exitnode && (!need_uptime || build_state->need_uptime)) {
|
||||
@ -843,6 +871,7 @@ circuit_predict_and_launch_new(void)
|
||||
/* First, count how many of each type of circuit we have already. */
|
||||
for (circ=global_circuitlist;circ;circ = circ->next) {
|
||||
cpath_build_state_t *build_state;
|
||||
origin_circuit_t *origin_circ;
|
||||
if (!CIRCUIT_IS_ORIGIN(circ))
|
||||
continue;
|
||||
if (circ->marked_for_close)
|
||||
@ -851,7 +880,10 @@ circuit_predict_and_launch_new(void)
|
||||
continue; /* only count clean circs */
|
||||
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
||||
continue; /* only pay attention to general-purpose circs */
|
||||
build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
|
||||
origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
if (origin_circ->unusable_for_new_conns)
|
||||
continue;
|
||||
build_state = origin_circ->build_state;
|
||||
if (build_state->onehop_tunnel)
|
||||
continue;
|
||||
num++;
|
||||
@ -2275,3 +2307,23 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
|
||||
}
|
||||
}
|
||||
|
||||
/** Mark <b>circ</b> so that no more connections can be attached to it. */
|
||||
void
|
||||
mark_circuit_unusable_for_new_conns(origin_circuit_t *circ)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
tor_assert(circ);
|
||||
|
||||
/* XXXX025 This is a kludge; we're only keeping it around in case there's
|
||||
* something that doesn't check unusable_for_new_conns, and to avoid
|
||||
* deeper refactoring of our expiration logic. */
|
||||
if (! circ->base_.timestamp_dirty)
|
||||
circ->base_.timestamp_dirty = approx_time();
|
||||
if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty)
|
||||
circ->base_.timestamp_dirty = 1; /* prevent underflow */
|
||||
else
|
||||
circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness;
|
||||
|
||||
circ->unusable_for_new_conns = 1;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose);
|
||||
|
||||
int hostname_in_track_host_exits(const or_options_t *options,
|
||||
const char *address);
|
||||
void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
@ -255,6 +255,7 @@ static config_var_t option_vars_[] = {
|
||||
#endif
|
||||
OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"),
|
||||
OBSOLETE("Group"),
|
||||
V(GuardLifetime, INTERVAL, "0 minutes"),
|
||||
V(HardwareAccel, BOOL, "0"),
|
||||
V(HeartbeatPeriod, INTERVAL, "6 hours"),
|
||||
V(AccelName, STRING, NULL),
|
||||
@ -300,6 +301,7 @@ static config_var_t option_vars_[] = {
|
||||
V(MaxClientCircuitsPending, UINT, "32"),
|
||||
OBSOLETE("MaxOnionsPending"),
|
||||
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
|
||||
V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
|
||||
OBSOLETE("MonthlyAccountingStart"),
|
||||
V(MyFamily, STRING, NULL),
|
||||
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
|
||||
@ -339,6 +341,8 @@ static config_var_t option_vars_[] = {
|
||||
V(PerConnBWRate, MEMUNIT, "0"),
|
||||
V(PidFile, STRING, NULL),
|
||||
V(TestingTorNetwork, BOOL, "0"),
|
||||
V(TestingMinExitFlagThreshold, MEMUNIT, "0"),
|
||||
V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
|
||||
V(OptimisticData, AUTOBOOL, "auto"),
|
||||
V(PortForwarding, BOOL, "0"),
|
||||
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
|
||||
@ -1502,7 +1506,7 @@ options_act(const or_options_t *old_options)
|
||||
"preferred or excluded node lists. "
|
||||
"Abandoning previous circuits.");
|
||||
circuit_mark_all_unused_circs();
|
||||
circuit_expire_all_dirty_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
revise_trackexithosts = 1;
|
||||
}
|
||||
|
||||
@ -2481,7 +2485,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too low. Increasing "
|
||||
"to 0.25");
|
||||
options->PathsNeededToBuildCircuits = 0.25;
|
||||
} else if (options->PathsNeededToBuildCircuits < 0.95) {
|
||||
} else if (options->PathsNeededToBuildCircuits > 0.95) {
|
||||
log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too high. Decreasing "
|
||||
"to 0.95");
|
||||
options->PathsNeededToBuildCircuits = 0.95;
|
||||
@ -2601,9 +2605,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
if (options->UseBridges && options->EntryNodes)
|
||||
REJECT("You cannot set both UseBridges and EntryNodes.");
|
||||
|
||||
if (options->EntryNodes && !options->UseEntryGuards)
|
||||
log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. "
|
||||
"EntryNodes will be ignored.");
|
||||
if (options->EntryNodes && !options->UseEntryGuards) {
|
||||
REJECT("If EntryNodes is set, UseEntryGuards must be enabled.");
|
||||
}
|
||||
|
||||
options->AllowInvalid_ = 0;
|
||||
if (options->AllowInvalidNodes) {
|
||||
@ -2721,15 +2725,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
"http://freehaven.net/anonbib/#hs-attack06 for details.");
|
||||
}
|
||||
|
||||
if (!(options->LearnCircuitBuildTimeout) &&
|
||||
options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
|
||||
if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout &&
|
||||
options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
|
||||
log_warn(LD_CONFIG,
|
||||
"CircuitBuildTimeout is shorter (%d seconds) than recommended "
|
||||
"(%d seconds), and LearnCircuitBuildTimeout is disabled. "
|
||||
"CircuitBuildTimeout is shorter (%d seconds) than the recommended "
|
||||
"minimum (%d seconds), and LearnCircuitBuildTimeout is disabled. "
|
||||
"If tor isn't working, raise this value or enable "
|
||||
"LearnCircuitBuildTimeout.",
|
||||
options->CircuitBuildTimeout,
|
||||
RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT );
|
||||
} else if (!options->LearnCircuitBuildTimeout &&
|
||||
!options->CircuitBuildTimeout) {
|
||||
log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't "
|
||||
"a CircuitBuildTimeout. I'll pick a plausible default.");
|
||||
}
|
||||
|
||||
if (options->PathBiasNoticeRate > 1.0) {
|
||||
|
@ -91,12 +91,15 @@ config_get_lines(const char *string, config_line_t **result, int extended)
|
||||
{
|
||||
config_line_t *list = NULL, **next;
|
||||
char *k, *v;
|
||||
const char *parse_err;
|
||||
|
||||
next = &list;
|
||||
do {
|
||||
k = v = NULL;
|
||||
string = parse_config_line_from_str(string, &k, &v);
|
||||
string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
|
||||
if (!string) {
|
||||
log_warn(LD_CONFIG, "Error while parsing configuration: %s",
|
||||
parse_err?parse_err:"<unknown>");
|
||||
config_free_lines(list);
|
||||
tor_free(k);
|
||||
tor_free(v);
|
||||
@ -1100,6 +1103,8 @@ static struct unit_table_t time_units[] = {
|
||||
{ "days", 24*60*60 },
|
||||
{ "week", 7*24*60*60 },
|
||||
{ "weeks", 7*24*60*60 },
|
||||
{ "month", 2629728, }, /* about 30.437 days */
|
||||
{ "months", 2629728, },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
|
@ -918,8 +918,11 @@ make_socket_reuseable(tor_socket_t sock)
|
||||
* right after somebody else has let it go. But REUSEADDR on win32
|
||||
* means you can bind to the port _even when somebody else
|
||||
* already has it bound_. So, don't do that on Win32. */
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
|
||||
(socklen_t)sizeof(one));
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
|
||||
(socklen_t)sizeof(one)) == -1) {
|
||||
log_warn(LD_NET, "Error setting SO_REUSEADDR flag: %s",
|
||||
tor_socket_strerror(errno));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1102,7 +1105,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
set_socket_nonblocking(s);
|
||||
if (set_socket_nonblocking(s) == -1) {
|
||||
tor_close_socket(s);
|
||||
goto err;
|
||||
}
|
||||
|
||||
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
|
||||
conn = TO_CONN(lis_conn);
|
||||
@ -1265,7 +1271,10 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
||||
(int)news,(int)conn->s);
|
||||
|
||||
make_socket_reuseable(news);
|
||||
set_socket_nonblocking(news);
|
||||
if (set_socket_nonblocking(news) == -1) {
|
||||
tor_close_socket(news);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options->ConstrainedSockets)
|
||||
set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize);
|
||||
@ -1494,7 +1503,11 @@ connection_connect(connection_t *conn, const char *address,
|
||||
}
|
||||
}
|
||||
|
||||
set_socket_nonblocking(s);
|
||||
if (set_socket_nonblocking(s) == -1) {
|
||||
*socket_error = tor_socket_errno(s);
|
||||
tor_close_socket(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options->ConstrainedSockets)
|
||||
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
|
||||
@ -3426,6 +3439,10 @@ connection_handle_write_impl(connection_t *conn, int force)
|
||||
if (result < 0) {
|
||||
if (CONN_IS_EDGE(conn))
|
||||
connection_edge_end_errno(TO_EDGE_CONN(conn));
|
||||
if (conn->type == CONN_TYPE_AP) {
|
||||
/* writing failed; we couldn't send a SOCKS reply if we wanted to */
|
||||
TO_ENTRY_CONN(conn)->socks_request->has_finished = 1;
|
||||
}
|
||||
|
||||
connection_close_immediate(conn); /* Don't flush; connection is dead. */
|
||||
connection_mark_for_close(conn);
|
||||
|
@ -651,7 +651,9 @@ connection_ap_expire_beginning(void)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
|
||||
circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT &&
|
||||
circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
|
||||
log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. "
|
||||
"The purpose on the circuit was %s; it was in state %s, "
|
||||
"path_state %s.",
|
||||
@ -674,12 +676,10 @@ connection_ap_expire_beginning(void)
|
||||
/* un-mark it as ending, since we're going to reuse it */
|
||||
conn->edge_has_sent_end = 0;
|
||||
conn->end_reason = 0;
|
||||
/* kludge to make us not try this circuit again, yet to allow
|
||||
* current streams on it to survive if they can: make it
|
||||
* unattractive to use for new streams */
|
||||
/* XXXX024 this is a kludgy way to do this. */
|
||||
tor_assert(circ->timestamp_dirty);
|
||||
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
|
||||
/* make us not try this circuit again, but allow
|
||||
* current streams on it to survive if they can */
|
||||
mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
|
||||
|
||||
/* give our stream another 'cutoff' seconds to try */
|
||||
conn->base_.timestamp_lastread += cutoff;
|
||||
if (entry_conn->num_socks_retries < 250) /* avoid overflow */
|
||||
@ -1806,9 +1806,7 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
|
||||
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
||||
|
||||
/* Mark this circuit "unusable for new streams". */
|
||||
/* XXXX024 this is a kludgy way to do this. */
|
||||
tor_assert(circ->base_.timestamp_dirty);
|
||||
circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
|
||||
mark_circuit_unusable_for_new_conns(circ);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1899,9 +1897,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
|
||||
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
|
||||
|
||||
/* Mark this circuit "unusable for new streams". */
|
||||
/* XXXX024 this is a kludgy way to do this. */
|
||||
tor_assert(circ->base_.timestamp_dirty);
|
||||
circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
|
||||
mark_circuit_unusable_for_new_conns(circ);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1945,13 +1941,14 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
|
||||
string_addr, payload_len) < 0)
|
||||
return -1; /* circuit is closed, don't continue */
|
||||
|
||||
tor_free(base_conn->address); /* Maybe already set by dnsserv. */
|
||||
base_conn->address = tor_strdup("(Tor_internal)");
|
||||
if (!base_conn->address) {
|
||||
/* This might be unnecessary. XXXX */
|
||||
base_conn->address = tor_dup_addr(&base_conn->addr);
|
||||
}
|
||||
base_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
|
||||
log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT
|
||||
", n_circ_id %u",
|
||||
base_conn->s, (unsigned)circ->base_.n_circ_id);
|
||||
control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0);
|
||||
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0);
|
||||
return 0;
|
||||
}
|
||||
@ -2043,25 +2040,21 @@ tell_controller_about_resolved_result(entry_connection_t *conn,
|
||||
int ttl,
|
||||
time_t expires)
|
||||
{
|
||||
|
||||
if (ttl >= 0 && (answer_type == RESOLVED_TYPE_IPV4 ||
|
||||
answer_type == RESOLVED_TYPE_HOSTNAME)) {
|
||||
return; /* we already told the controller. */
|
||||
} else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
|
||||
expires = time(NULL) + ttl;
|
||||
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) {
|
||||
char *cp = tor_dup_ip(ntohl(get_uint32(answer)));
|
||||
control_event_address_mapped(conn->socks_request->address,
|
||||
cp, expires, NULL);
|
||||
cp, expires, NULL, 0);
|
||||
tor_free(cp);
|
||||
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
|
||||
char *cp = tor_strndup(answer, answer_len);
|
||||
control_event_address_mapped(conn->socks_request->address,
|
||||
cp, expires, NULL);
|
||||
cp, expires, NULL, 0);
|
||||
tor_free(cp);
|
||||
} else {
|
||||
control_event_address_mapped(conn->socks_request->address,
|
||||
"<error>",
|
||||
time(NULL)+ttl,
|
||||
"error=yes");
|
||||
"<error>", time(NULL)+ttl,
|
||||
"error=yes", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2119,8 +2112,9 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn,
|
||||
conn->socks_request->has_finished = 1;
|
||||
return;
|
||||
} else {
|
||||
/* This must be a request from the controller. We already sent
|
||||
* a mapaddress if there's a ttl. */
|
||||
/* This must be a request from the controller. Since answers to those
|
||||
* requests are not cached, they do not generate an ADDRMAP event on
|
||||
* their own. */
|
||||
tell_controller_about_resolved_result(conn, answer_type, answer_len,
|
||||
(char*)answer, ttl, expires);
|
||||
conn->socks_request->has_finished = 1;
|
||||
@ -2201,9 +2195,11 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
|
||||
|
||||
tor_assert(conn->socks_request); /* make sure it's an AP stream */
|
||||
|
||||
control_event_stream_status(conn,
|
||||
status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
|
||||
endreason);
|
||||
if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) {
|
||||
control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ?
|
||||
STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED,
|
||||
endreason);
|
||||
}
|
||||
|
||||
/* Flag this stream's circuit as having completed a stream successfully
|
||||
* (for path bias) */
|
||||
|
@ -2939,7 +2939,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
|
||||
failed = smartlist_new();
|
||||
SMARTLIST_FOREACH(args, const char *, arg, {
|
||||
if (!is_keyval_pair(arg)) {
|
||||
if (dnsserv_launch_request(arg, is_reverse)<0)
|
||||
if (dnsserv_launch_request(arg, is_reverse, conn)<0)
|
||||
smartlist_add(failed, (char*)arg);
|
||||
}
|
||||
});
|
||||
@ -2947,7 +2947,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
|
||||
send_control_done(conn);
|
||||
SMARTLIST_FOREACH(failed, const char *, arg, {
|
||||
control_event_address_mapped(arg, arg, time(NULL),
|
||||
"internal");
|
||||
"internal", 0);
|
||||
});
|
||||
|
||||
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
||||
@ -3742,7 +3742,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
|
||||
}
|
||||
}
|
||||
|
||||
if (tp == STREAM_EVENT_NEW) {
|
||||
if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) {
|
||||
tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d",
|
||||
ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port);
|
||||
} else {
|
||||
@ -3752,11 +3752,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
|
||||
if (tp == STREAM_EVENT_NEW_RESOLVE) {
|
||||
purpose = " PURPOSE=DNS_REQUEST";
|
||||
} else if (tp == STREAM_EVENT_NEW) {
|
||||
if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request ||
|
||||
(conn->socks_request &&
|
||||
SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)))
|
||||
purpose = " PURPOSE=DNS_REQUEST";
|
||||
else if (conn->use_begindir) {
|
||||
if (conn->use_begindir) {
|
||||
connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn;
|
||||
int linked_dir_purpose = -1;
|
||||
if (linked && linked->type == CONN_TYPE_DIR)
|
||||
@ -4028,15 +4024,17 @@ control_event_descriptors_changed(smartlist_t *routers)
|
||||
*/
|
||||
int
|
||||
control_event_address_mapped(const char *from, const char *to, time_t expires,
|
||||
const char *error)
|
||||
const char *error, const int cached)
|
||||
{
|
||||
if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP))
|
||||
return 0;
|
||||
|
||||
if (expires < 3 || expires == TIME_MAX)
|
||||
send_control_event(EVENT_ADDRMAP, ALL_FORMATS,
|
||||
"650 ADDRMAP %s %s NEVER %s\r\n", from, to,
|
||||
error?error:"");
|
||||
"650 ADDRMAP %s %s NEVER %s%s"
|
||||
"CACHED=\"%s\"\r\n",
|
||||
from, to, error?error:"", error?" ":"",
|
||||
cached?"YES":"NO");
|
||||
else {
|
||||
char buf[ISO_TIME_LEN+1];
|
||||
char buf2[ISO_TIME_LEN+1];
|
||||
@ -4044,10 +4042,10 @@ control_event_address_mapped(const char *from, const char *to, time_t expires,
|
||||
format_iso_time(buf2,expires);
|
||||
send_control_event(EVENT_ADDRMAP, ALL_FORMATS,
|
||||
"650 ADDRMAP %s %s \"%s\""
|
||||
" %s%sEXPIRES=\"%s\"\r\n",
|
||||
" %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n",
|
||||
from, to, buf,
|
||||
error?error:"", error?" ":"",
|
||||
buf2);
|
||||
buf2, cached?"YES":"NO");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -53,7 +53,8 @@ int control_event_stream_bandwidth_used(void);
|
||||
void control_event_logmsg(int severity, uint32_t domain, const char *msg);
|
||||
int control_event_descriptors_changed(smartlist_t *routers);
|
||||
int control_event_address_mapped(const char *from, const char *to,
|
||||
time_t expires, const char *error);
|
||||
time_t expires, const char *error,
|
||||
const int cached);
|
||||
int control_event_or_authdir_new_descriptor(const char *action,
|
||||
const char *desc,
|
||||
size_t desclen,
|
||||
|
@ -535,13 +535,16 @@ spawn_cpuworker(void)
|
||||
|
||||
conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
|
||||
|
||||
set_socket_nonblocking(fd);
|
||||
|
||||
/* set up conn so it's got all the data we need to remember */
|
||||
conn->s = fd;
|
||||
conn->address = tor_strdup("localhost");
|
||||
tor_addr_make_unspec(&conn->addr);
|
||||
|
||||
if (set_socket_nonblocking(fd) == -1) {
|
||||
connection_free(conn); /* this closes fd */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connection_add(conn) < 0) { /* no space, forget it */
|
||||
log_warn(LD_NET,"connection_add for cpuworker failed. Giving up.");
|
||||
connection_free(conn); /* this closes fd */
|
||||
|
302
src/or/dirserv.c
302
src/or/dirserv.c
@ -66,6 +66,13 @@ static cached_dir_t *the_directory = NULL;
|
||||
/** For authoritative directories: the current (v1) network status. */
|
||||
static cached_dir_t the_runningrouters;
|
||||
|
||||
/** Total number of routers with measured bandwidth; this is set by
|
||||
* dirserv_count_measured_bws() before the loop in
|
||||
* dirserv_generate_networkstatus_vote_obj() and checked by
|
||||
* dirserv_get_credible_bandwidth() and
|
||||
* dirserv_compute_performance_thresholds() */
|
||||
static int routers_with_measured_bw = 0;
|
||||
|
||||
static void directory_remove_invalid(void);
|
||||
static cached_dir_t *dirserv_regenerate_directory(void);
|
||||
static char *format_versions_list(config_line_t *ln);
|
||||
@ -85,9 +92,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
|
||||
time_t publish_cutoff);
|
||||
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
|
||||
const char **msg);
|
||||
|
||||
/************** Measured Bandwidth parsing code ******/
|
||||
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
|
||||
static uint32_t dirserv_get_bandwidth_for_router(const routerinfo_t *ri);
|
||||
static uint32_t dirserv_get_credible_bandwidth(const routerinfo_t *ri);
|
||||
|
||||
/************** Fingerprint handling code ************/
|
||||
|
||||
@ -1824,7 +1830,7 @@ dirserv_thinks_router_is_unreliable(time_t now,
|
||||
}
|
||||
}
|
||||
if (need_capacity) {
|
||||
uint32_t bw = router_get_advertised_bandwidth(router);
|
||||
uint32_t bw = dirserv_get_bandwidth_for_router(router);
|
||||
if (bw < fast_bandwidth)
|
||||
return 1;
|
||||
}
|
||||
@ -1876,15 +1882,29 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
|
||||
#define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER 4096
|
||||
|
||||
/** Helper for dirserv_compute_performance_thresholds(): Decide whether to
|
||||
* include a router in our calculations, and return true iff we should. */
|
||||
* include a router in our calculations, and return true iff we should; the
|
||||
* require_mbw parameter is passed in by
|
||||
* dirserv_compute_performance_thresholds() and controls whether we ever
|
||||
* count routers with only advertised bandwidths */
|
||||
static int
|
||||
router_counts_toward_thresholds(const node_t *node, time_t now,
|
||||
const digestmap_t *omit_as_sybil)
|
||||
const digestmap_t *omit_as_sybil,
|
||||
int require_mbw)
|
||||
{
|
||||
/* Have measured bw? */
|
||||
int have_mbw =
|
||||
dirserv_has_measured_bw(node->ri->cache_info.identity_digest);
|
||||
uint64_t min_bw = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER;
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
if (options->TestingTorNetwork) {
|
||||
min_bw = (int64_t)options->TestingMinExitFlagThreshold;
|
||||
}
|
||||
|
||||
return node->ri && router_is_active(node->ri, node, now) &&
|
||||
!digestmap_get(omit_as_sybil, node->ri->cache_info.identity_digest) &&
|
||||
(router_get_advertised_bandwidth(node->ri) >=
|
||||
ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER);
|
||||
(dirserv_get_credible_bandwidth(node->ri) >= min_bw) &&
|
||||
(have_mbw || !require_mbw);
|
||||
}
|
||||
|
||||
/** Look through the routerlist, the Mean Time Between Failure history, and
|
||||
@ -1906,6 +1926,11 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
time_t now = time(NULL);
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/* Require mbw? */
|
||||
int require_mbw =
|
||||
(routers_with_measured_bw >
|
||||
options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0;
|
||||
|
||||
/* initialize these all here, in case there are no routers */
|
||||
stable_uptime = 0;
|
||||
stable_mtbf = 0;
|
||||
@ -1938,7 +1963,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
|
||||
/* Now, fill in the arrays. */
|
||||
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
|
||||
if (router_counts_toward_thresholds(node, now, omit_as_sybil)) {
|
||||
if (router_counts_toward_thresholds(node, now, omit_as_sybil,
|
||||
require_mbw)) {
|
||||
routerinfo_t *ri = node->ri;
|
||||
const char *id = ri->cache_info.identity_digest;
|
||||
uint32_t bw;
|
||||
@ -1947,7 +1973,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
|
||||
mtbfs[n_active] = rep_hist_get_stability(id, now);
|
||||
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
|
||||
bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
|
||||
bandwidths[n_active] = bw = dirserv_get_credible_bandwidth(ri);
|
||||
total_bandwidth += bw;
|
||||
if (node->is_exit && !node->is_bad_exit) {
|
||||
total_exit_bandwidth += bw;
|
||||
@ -1985,6 +2011,9 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
|
||||
ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
|
||||
INT32_MAX);
|
||||
if (options->TestingTorNetwork) {
|
||||
min_fast = (int32_t)options->TestingMinFastFlagThreshold;
|
||||
}
|
||||
max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold",
|
||||
INT32_MAX, min_fast, INT32_MAX);
|
||||
if (fast_bandwidth < (uint32_t)min_fast)
|
||||
@ -2003,7 +2032,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
n_familiar = 0;
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
|
||||
if (router_counts_toward_thresholds(node, now, omit_as_sybil)) {
|
||||
if (router_counts_toward_thresholds(node, now,
|
||||
omit_as_sybil, require_mbw)) {
|
||||
routerinfo_t *ri = node->ri;
|
||||
const char *id = ri->cache_info.identity_digest;
|
||||
long tk = rep_hist_get_weighted_time_known(id, now);
|
||||
@ -2046,6 +2076,203 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
|
||||
tor_free(wfus);
|
||||
}
|
||||
|
||||
/** Measured bandwidth cache entry */
|
||||
typedef struct mbw_cache_entry_s {
|
||||
long mbw;
|
||||
time_t as_of;
|
||||
} mbw_cache_entry_t;
|
||||
|
||||
/** Measured bandwidth cache - keys are identity_digests, values are
|
||||
* mbw_cache_entry_t *. */
|
||||
static digestmap_t *mbw_cache = NULL;
|
||||
|
||||
/** Store a measured bandwidth cache entry when reading the measured
|
||||
* bandwidths file. */
|
||||
void
|
||||
dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
|
||||
time_t as_of)
|
||||
{
|
||||
mbw_cache_entry_t *e = NULL;
|
||||
|
||||
tor_assert(parsed_line);
|
||||
|
||||
/* Allocate a cache if we need */
|
||||
if (!mbw_cache) mbw_cache = digestmap_new();
|
||||
|
||||
/* Check if we have an existing entry */
|
||||
e = digestmap_get(mbw_cache, parsed_line->node_id);
|
||||
/* If we do, we can re-use it */
|
||||
if (e) {
|
||||
/* Check that we really are newer, and update */
|
||||
if (as_of > e->as_of) {
|
||||
e->mbw = parsed_line->bw;
|
||||
e->as_of = as_of;
|
||||
}
|
||||
} else {
|
||||
/* We'll have to insert a new entry */
|
||||
e = tor_malloc(sizeof(*e));
|
||||
e->mbw = parsed_line->bw;
|
||||
e->as_of = as_of;
|
||||
digestmap_set(mbw_cache, parsed_line->node_id, e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear and free the measured bandwidth cache */
|
||||
void
|
||||
dirserv_clear_measured_bw_cache(void)
|
||||
{
|
||||
if (mbw_cache) {
|
||||
/* Free the map and all entries */
|
||||
digestmap_free(mbw_cache, tor_free_);
|
||||
mbw_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Scan the measured bandwidth cache and remove expired entries */
|
||||
void
|
||||
dirserv_expire_measured_bw_cache(time_t now)
|
||||
{
|
||||
|
||||
if (mbw_cache) {
|
||||
/* Iterate through the cache and check each entry */
|
||||
DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) {
|
||||
if (now > e->as_of + MAX_MEASUREMENT_AGE) {
|
||||
tor_free(e);
|
||||
MAP_DEL_CURRENT(k);
|
||||
}
|
||||
} DIGESTMAP_FOREACH_END;
|
||||
|
||||
/* Check if we cleared the whole thing and free if so */
|
||||
if (digestmap_size(mbw_cache) == 0) {
|
||||
digestmap_free(mbw_cache, tor_free_);
|
||||
mbw_cache = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the current size of the measured bandwidth cache */
|
||||
int
|
||||
dirserv_get_measured_bw_cache_size(void)
|
||||
{
|
||||
if (mbw_cache) return digestmap_size(mbw_cache);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/** Query the cache by identity digest, return value indicates whether
|
||||
* we found it. The bw_out and as_of_out pointers receive the cached
|
||||
* bandwidth value and the time it was cached if not NULL. */
|
||||
int
|
||||
dirserv_query_measured_bw_cache(const char *node_id, long *bw_out,
|
||||
time_t *as_of_out)
|
||||
{
|
||||
mbw_cache_entry_t *v = NULL;
|
||||
int rv = 0;
|
||||
|
||||
if (mbw_cache && node_id) {
|
||||
v = digestmap_get(mbw_cache, node_id);
|
||||
if (v) {
|
||||
/* Found something */
|
||||
rv = 1;
|
||||
if (bw_out) *bw_out = v->mbw;
|
||||
if (as_of_out) *as_of_out = v->as_of;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Predicate wrapper for dirserv_query_measured_bw_cache() */
|
||||
int
|
||||
dirserv_has_measured_bw(const char *node_id)
|
||||
{
|
||||
return dirserv_query_measured_bw_cache(node_id, NULL, NULL);
|
||||
}
|
||||
|
||||
/** Get the best estimate of a router's bandwidth for dirauth purposes,
|
||||
* preferring measured to advertised values if available. */
|
||||
|
||||
static uint32_t
|
||||
dirserv_get_bandwidth_for_router(const routerinfo_t *ri)
|
||||
{
|
||||
uint32_t bw = 0;
|
||||
/*
|
||||
* Yeah, measured bandwidths in measured_bw_line_t are (implicitly
|
||||
* signed) longs and the ones router_get_advertised_bandwidth() returns
|
||||
* are uint32_t.
|
||||
*/
|
||||
long mbw = 0;
|
||||
|
||||
if (ri) {
|
||||
/*
|
||||
* * First try to see if we have a measured bandwidth; don't bother with
|
||||
* as_of_out here, on the theory that a stale measured bandwidth is still
|
||||
* better to trust than an advertised one.
|
||||
*/
|
||||
if (dirserv_query_measured_bw_cache(ri->cache_info.identity_digest,
|
||||
&mbw, NULL)) {
|
||||
/* Got one! */
|
||||
bw = (uint32_t)mbw;
|
||||
} else {
|
||||
/* If not, fall back to advertised */
|
||||
bw = router_get_advertised_bandwidth(ri);
|
||||
}
|
||||
}
|
||||
|
||||
return bw;
|
||||
}
|
||||
|
||||
/** Look through the routerlist, and using the measured bandwidth cache count
|
||||
* how many measured bandwidths we know. This is used to decide whether we
|
||||
* ever trust advertised bandwidths for purposes of assigning flags. */
|
||||
static void
|
||||
dirserv_count_measured_bws(routerlist_t *rl)
|
||||
{
|
||||
/* Initialize this first */
|
||||
routers_with_measured_bw = 0;
|
||||
|
||||
tor_assert(rl);
|
||||
tor_assert(rl->routers);
|
||||
|
||||
/* Iterate over the routerlist and count measured bandwidths */
|
||||
SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
|
||||
/* Check if we know a measured bandwidth for this one */
|
||||
if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) {
|
||||
++routers_with_measured_bw;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
}
|
||||
|
||||
/** Return the bandwidth we believe for assigning flags; prefer measured
|
||||
* over advertised, and if we have above a threshold quantity of measured
|
||||
* bandwidths, we don't want to ever give flags to unmeasured routers, so
|
||||
* return 0. */
|
||||
static uint32_t
|
||||
dirserv_get_credible_bandwidth(const routerinfo_t *ri)
|
||||
{
|
||||
int threshold;
|
||||
uint32_t bw = 0;
|
||||
long mbw;
|
||||
|
||||
tor_assert(ri);
|
||||
/* Check if we have a measured bandwidth, and check the threshold if not */
|
||||
if (!(dirserv_query_measured_bw_cache(ri->cache_info.identity_digest,
|
||||
&mbw, NULL))) {
|
||||
threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
|
||||
if (routers_with_measured_bw > threshold) {
|
||||
/* Return zero for unmeasured bandwidth if we are above threshold */
|
||||
bw = 0;
|
||||
} else {
|
||||
/* Return an advertised bandwidth otherwise */
|
||||
bw = router_get_advertised_bandwidth(ri);
|
||||
}
|
||||
} else {
|
||||
/* We have the measured bandwidth in mbw */
|
||||
bw = (uint32_t)mbw;
|
||||
}
|
||||
|
||||
return bw;
|
||||
}
|
||||
|
||||
/** Give a statement of our current performance thresholds for inclusion
|
||||
* in a vote document. */
|
||||
char *
|
||||
@ -2216,9 +2443,10 @@ routerstatus_format_entry(char *buf, size_t buf_len,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This assert can fire for the control port, because
|
||||
/* This assert could fire for the control port, because
|
||||
* it can request NS documents before all descriptors
|
||||
* have been fetched. */
|
||||
* have been fetched. Therefore, we only do this test when
|
||||
* format != NS_CONTROL_PORT. */
|
||||
if (tor_memneq(desc->cache_info.signed_descriptor_digest,
|
||||
rs->descriptor_digest,
|
||||
DIGEST_LEN)) {
|
||||
@ -2327,8 +2555,8 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
|
||||
else if (!first_is_running && second_is_running)
|
||||
return 1;
|
||||
|
||||
bw_first = router_get_advertised_bandwidth(first);
|
||||
bw_second = router_get_advertised_bandwidth(second);
|
||||
bw_first = dirserv_get_bandwidth_for_router(first);
|
||||
bw_second = dirserv_get_bandwidth_for_router(second);
|
||||
|
||||
if (bw_first > bw_second)
|
||||
return -1;
|
||||
@ -2468,7 +2696,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
|
||||
int listbaddirs, int vote_on_hsdirs)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
uint32_t routerbw = router_get_advertised_bandwidth(ri);
|
||||
uint32_t routerbw = dirserv_get_credible_bandwidth(ri);
|
||||
|
||||
memset(rs, 0, sizeof(routerstatus_t));
|
||||
|
||||
@ -2670,8 +2898,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
||||
char line[256];
|
||||
FILE *fp = tor_fopen_cloexec(from_file, "r");
|
||||
int applied_lines = 0;
|
||||
time_t file_time;
|
||||
time_t file_time, now;
|
||||
int ok;
|
||||
|
||||
if (fp == NULL) {
|
||||
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
|
||||
from_file);
|
||||
@ -2695,7 +2924,8 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
|
||||
now = time(NULL);
|
||||
if ((now - file_time) > MAX_MEASUREMENT_AGE) {
|
||||
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
|
||||
(unsigned)(time(NULL) - file_time));
|
||||
fclose(fp);
|
||||
@ -2709,12 +2939,17 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
||||
measured_bw_line_t parsed_line;
|
||||
if (fgets(line, sizeof(line), fp) && strlen(line)) {
|
||||
if (measured_bw_line_parse(&parsed_line, line) != -1) {
|
||||
/* Also cache the line for dirserv_get_bandwidth_for_router() */
|
||||
dirserv_cache_measured_bw(&parsed_line, file_time);
|
||||
if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
|
||||
applied_lines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now would be a nice time to clean the cache, too */
|
||||
dirserv_expire_measured_bw_cache(now);
|
||||
|
||||
fclose(fp);
|
||||
log_info(LD_DIRSERV,
|
||||
"Bandwidth measurement file successfully read. "
|
||||
@ -2778,6 +3013,22 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
if (!contact)
|
||||
contact = "(none)";
|
||||
|
||||
/*
|
||||
* Do this so dirserv_compute_performance_thresholds() and
|
||||
* set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
|
||||
*/
|
||||
if (options->V3BandwidthsFile) {
|
||||
dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
|
||||
} else {
|
||||
/*
|
||||
* No bandwidths file; clear the measured bandwidth cache in case we had
|
||||
* one last time around.
|
||||
*/
|
||||
if (dirserv_get_measured_bw_cache_size() > 0) {
|
||||
dirserv_clear_measured_bw_cache();
|
||||
}
|
||||
}
|
||||
|
||||
/* precompute this part, since we need it to decide what "stable"
|
||||
* means. */
|
||||
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
|
||||
@ -2794,6 +3045,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
rep_hist_make_router_pessimal(sybil_id, now);
|
||||
} DIGESTMAP_FOREACH_END;
|
||||
|
||||
/* Count how many have measured bandwidths so we know how to assign flags;
|
||||
* this must come before dirserv_compute_performance_thresholds() */
|
||||
dirserv_count_measured_bws(rl);
|
||||
|
||||
dirserv_compute_performance_thresholds(rl, omit_as_sybil);
|
||||
|
||||
routerstatuses = smartlist_new();
|
||||
@ -2838,9 +3093,18 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
smartlist_free(routers);
|
||||
digestmap_free(omit_as_sybil, NULL);
|
||||
|
||||
/* This pass through applies the measured bw lines to the routerstatuses */
|
||||
if (options->V3BandwidthsFile) {
|
||||
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
|
||||
routerstatuses);
|
||||
} else {
|
||||
/*
|
||||
* No bandwidths file; clear the measured bandwidth cache in case we had
|
||||
* one last time around.
|
||||
*/
|
||||
if (dirserv_get_measured_bw_cache_size() > 0) {
|
||||
dirserv_clear_measured_bw_cache();
|
||||
}
|
||||
}
|
||||
|
||||
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
|
||||
@ -3908,5 +4172,7 @@ dirserv_free_all(void)
|
||||
cached_v2_networkstatus = NULL;
|
||||
strmap_free(cached_consensuses, free_cached_dir_);
|
||||
cached_consensuses = NULL;
|
||||
|
||||
dirserv_clear_measured_bw_cache();
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,6 @@ int directory_fetches_from_authorities(const or_options_t *options);
|
||||
int directory_fetches_dir_info_early(const or_options_t *options);
|
||||
int directory_fetches_dir_info_later(const or_options_t *options);
|
||||
int directory_caches_v2_dir_info(const or_options_t *options);
|
||||
#define directory_caches_v1_dir_info(o) directory_caches_v2_dir_info(o)
|
||||
int directory_caches_unknown_auth_certs(const or_options_t *options);
|
||||
int directory_caches_dir_info(const or_options_t *options);
|
||||
int directory_permits_begindir_requests(const or_options_t *options);
|
||||
@ -138,10 +137,23 @@ void cached_dir_decref(cached_dir_t *d);
|
||||
cached_dir_t *new_cached_dir(char *s, time_t published);
|
||||
|
||||
#ifdef DIRSERV_PRIVATE
|
||||
|
||||
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
|
||||
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
|
||||
|
||||
int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
|
||||
|
||||
int measured_bw_line_apply(measured_bw_line_t *parsed_line,
|
||||
smartlist_t *routerstatuses);
|
||||
|
||||
void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
|
||||
time_t as_of);
|
||||
void dirserv_clear_measured_bw_cache(void);
|
||||
void dirserv_expire_measured_bw_cache(time_t now);
|
||||
int dirserv_get_measured_bw_cache_size(void);
|
||||
int dirserv_query_measured_bw_cache(const char *node_id, long *bw_out,
|
||||
time_t *as_of_out);
|
||||
int dirserv_has_measured_bw(const char *node_id);
|
||||
#endif
|
||||
|
||||
int dirserv_read_measured_bandwidths(const char *from_file,
|
||||
|
@ -1913,7 +1913,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
}
|
||||
|
||||
/* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
|
||||
if (consensus_method >= 11) {
|
||||
if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) {
|
||||
is_exit = is_exit && !is_bad_exit;
|
||||
}
|
||||
|
||||
@ -2210,7 +2210,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
||||
}
|
||||
// Verify balancing parameters
|
||||
if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) {
|
||||
networkstatus_verify_bw_weights(c);
|
||||
networkstatus_verify_bw_weights(c, consensus_method);
|
||||
}
|
||||
networkstatus_vote_free(c);
|
||||
}
|
||||
|
@ -34,6 +34,9 @@
|
||||
/** Lowest consensus method that generates microdescriptors */
|
||||
#define MIN_METHOD_FOR_MICRODESC 8
|
||||
|
||||
/** Lowest consensus method that doesn't count bad exits as exits for weight */
|
||||
#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11
|
||||
|
||||
/** Lowest consensus method that ensures a majority of authorities voted
|
||||
* for a param. */
|
||||
#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
|
||||
|
@ -147,7 +147,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
|
||||
return;
|
||||
}
|
||||
|
||||
control_event_stream_status(entry_conn, STREAM_EVENT_NEW, 0);
|
||||
control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0);
|
||||
|
||||
/* Now, unless a controller asked us to leave streams unattached,
|
||||
* throw the connection over to get rewritten (which will
|
||||
@ -170,7 +170,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
|
||||
* response; -1 if we couldn't launch the request.
|
||||
*/
|
||||
int
|
||||
dnsserv_launch_request(const char *name, int reverse)
|
||||
dnsserv_launch_request(const char *name, int reverse,
|
||||
control_connection_t *control_conn)
|
||||
{
|
||||
entry_connection_t *entry_conn;
|
||||
edge_connection_t *conn;
|
||||
@ -181,6 +182,10 @@ dnsserv_launch_request(const char *name, int reverse)
|
||||
conn = ENTRY_TO_EDGE_CONN(entry_conn);
|
||||
conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
|
||||
|
||||
tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr);
|
||||
TO_CONN(conn)->port = control_conn->base_.port;
|
||||
TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr);
|
||||
|
||||
if (reverse)
|
||||
entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
|
||||
else
|
||||
@ -203,6 +208,8 @@ dnsserv_launch_request(const char *name, int reverse)
|
||||
return -1;
|
||||
}
|
||||
|
||||
control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0);
|
||||
|
||||
/* Now, unless a controller asked us to leave streams unattached,
|
||||
* throw the connection over to get rewritten (which will
|
||||
* answer it immediately if it's in the cache, or completely bogus, or
|
||||
|
@ -20,7 +20,8 @@ void dnsserv_resolved(entry_connection_t *conn,
|
||||
const char *answer,
|
||||
int ttl);
|
||||
void dnsserv_reject_request(entry_connection_t *conn);
|
||||
int dnsserv_launch_request(const char *name, int is_reverse);
|
||||
int dnsserv_launch_request(const char *name, int is_reverse,
|
||||
control_connection_t *control_conn);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "entrynodes.h"
|
||||
#include "main.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "policies.h"
|
||||
#include "router.h"
|
||||
@ -332,6 +333,9 @@ control_event_guard_deferred(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Largest amount that we'll backdate chosen_on_date */
|
||||
#define CHOSEN_ON_DATE_SLOP (30*86400)
|
||||
|
||||
/** Add a new (preferably stable and fast) router to our
|
||||
* entry_guards list. Return a pointer to the router if we succeed,
|
||||
* or NULL if we can't find any more suitable entries.
|
||||
@ -367,13 +371,22 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
|
||||
} else {
|
||||
const routerstatus_t *rs;
|
||||
rs = router_pick_directory_server(MICRODESC_DIRINFO|V3_DIRINFO,
|
||||
PDS_PREFER_TUNNELED_DIR_CONNS_);
|
||||
PDS_PREFER_TUNNELED_DIR_CONNS_|PDS_FOR_GUARD);
|
||||
if (!rs)
|
||||
return NULL;
|
||||
node = node_get_by_id(rs->identity_digest);
|
||||
if (!node)
|
||||
return NULL;
|
||||
}
|
||||
if (node->using_as_guard)
|
||||
return NULL;
|
||||
if (entry_guard_get_by_id_digest(node->identity) != NULL) {
|
||||
log_info(LD_CIRC, "I was about to add a duplicate entry guard.");
|
||||
/* This can happen if we choose a guard, then the node goes away, then
|
||||
* comes back. */
|
||||
((node_t*) node)->using_as_guard = 1;
|
||||
return NULL;
|
||||
}
|
||||
entry = tor_malloc_zero(sizeof(entry_guard_t));
|
||||
log_info(LD_CIRC, "Chose %s as new entry guard.",
|
||||
node_describe(node));
|
||||
@ -391,6 +404,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
|
||||
* this guard. For details, see the Jan 2010 or-dev thread. */
|
||||
entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
|
||||
entry->chosen_by_version = tor_strdup(VERSION);
|
||||
((node_t*)node)->using_as_guard = 1;
|
||||
if (prepend)
|
||||
smartlist_insert(entry_guards, 0, entry);
|
||||
else
|
||||
@ -435,6 +449,32 @@ entry_guard_free(entry_guard_t *e)
|
||||
tor_free(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum lifetime of working entry guard, in seconds,
|
||||
* as given in the consensus networkstatus. (Plus CHOSEN_ON_DATE_SLOP,
|
||||
* so that we can do the chosen_on_date randomization while achieving the
|
||||
* desired minimum lifetime.)
|
||||
*/
|
||||
static int32_t
|
||||
guards_get_lifetime(void)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
#define DFLT_GUARD_LIFETIME (86400 * 60) /* Two months. */
|
||||
#define MIN_GUARD_LIFETIME (86400 * 30) /* One months. */
|
||||
#define MAX_GUARD_LIFETIME (86400 * 1826) /* Five years. */
|
||||
|
||||
if (options->GuardLifetime >= 1) {
|
||||
return CLAMP(MIN_GUARD_LIFETIME,
|
||||
options->GuardLifetime,
|
||||
MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP;
|
||||
}
|
||||
|
||||
return networkstatus_get_param(NULL, "GuardLifetime",
|
||||
DFLT_GUARD_LIFETIME,
|
||||
MIN_GUARD_LIFETIME,
|
||||
MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP;
|
||||
}
|
||||
|
||||
/** Remove any entry guard which was selected by an unknown version of Tor,
|
||||
* or which was selected by a version of Tor that's known to select
|
||||
* entry guards badly, or which was selected more 2 months ago. */
|
||||
@ -444,6 +484,7 @@ static int
|
||||
remove_obsolete_entry_guards(time_t now)
|
||||
{
|
||||
int changed = 0, i;
|
||||
int32_t guard_lifetime = guards_get_lifetime();
|
||||
|
||||
for (i = 0; i < smartlist_len(entry_guards); ++i) {
|
||||
entry_guard_t *entry = smartlist_get(entry_guards, i);
|
||||
@ -474,8 +515,8 @@ remove_obsolete_entry_guards(time_t now)
|
||||
}
|
||||
tor_free(tor_ver);
|
||||
}
|
||||
if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) {
|
||||
/* It's been 2 months since the date listed in our state file. */
|
||||
if (!version_is_bad && entry->chosen_on_date + guard_lifetime < now) {
|
||||
/* It's been too long since the date listed in our state file. */
|
||||
msg = "was selected several months ago";
|
||||
date_is_bad = 1;
|
||||
}
|
||||
@ -730,6 +771,21 @@ entry_nodes_should_be_added(void)
|
||||
should_add_entry_nodes = 1;
|
||||
}
|
||||
|
||||
/** Update the using_as_guard fields of all the nodes. We do this after we
|
||||
* remove entry guards from the list: This is the only function that clears
|
||||
* the using_as_guard field. */
|
||||
static void
|
||||
update_node_guard_status(void)
|
||||
{
|
||||
smartlist_t *nodes = nodelist_get_list();
|
||||
SMARTLIST_FOREACH(nodes, node_t *, node, node->using_as_guard = 0);
|
||||
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
|
||||
node_t *node = node_get_mutable_by_id(entry->identity);
|
||||
if (node)
|
||||
node->using_as_guard = 1;
|
||||
} SMARTLIST_FOREACH_END(entry);
|
||||
}
|
||||
|
||||
/** Adjust the entry guards list so that it only contains entries from
|
||||
* EntryNodes, adding new entries from EntryNodes to the list as needed. */
|
||||
static void
|
||||
@ -814,6 +870,8 @@ entry_guards_set_from_config(const or_options_t *options)
|
||||
SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
|
||||
entry_guard_free(e));
|
||||
|
||||
update_node_guard_status();
|
||||
|
||||
smartlist_free(entry_nodes);
|
||||
smartlist_free(worse_entry_nodes);
|
||||
smartlist_free(entry_fps);
|
||||
@ -1153,6 +1211,21 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use_cnt < success_cnt) {
|
||||
int severity = LOG_INFO;
|
||||
/* If this state file was written by a Tor that would have
|
||||
* already fixed it, then the overcounting bug is still there.. */
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) {
|
||||
severity = LOG_NOTICE;
|
||||
}
|
||||
log_fn(severity, LD_BUG,
|
||||
"State file contains unexpectedly high usage success "
|
||||
"counts %lf/%lf for Guard %s ($%s)",
|
||||
success_cnt, use_cnt,
|
||||
node->nickname, hex_str(node->identity, DIGEST_LEN));
|
||||
success_cnt = use_cnt;
|
||||
}
|
||||
|
||||
node->use_attempts = use_cnt;
|
||||
node->use_successes = success_cnt;
|
||||
|
||||
@ -1203,6 +1276,21 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
||||
unusable = 0;
|
||||
}
|
||||
|
||||
if (hop_cnt < success_cnt) {
|
||||
int severity = LOG_INFO;
|
||||
/* If this state file was written by a Tor that would have
|
||||
* already fixed it, then the overcounting bug is still there.. */
|
||||
if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) {
|
||||
severity = LOG_NOTICE;
|
||||
}
|
||||
log_fn(severity, LD_BUG,
|
||||
"State file contains unexpectedly high success counts "
|
||||
"%lf/%lf for Guard %s ($%s)",
|
||||
success_cnt, hop_cnt,
|
||||
node->nickname, hex_str(node->identity, DIGEST_LEN));
|
||||
success_cnt = hop_cnt;
|
||||
}
|
||||
|
||||
node->circ_attempts = hop_cnt;
|
||||
node->circ_successes = success_cnt;
|
||||
|
||||
@ -1269,6 +1357,8 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
||||
* few lines, so we don't have to re-dirty it */
|
||||
if (remove_obsolete_entry_guards(now))
|
||||
entry_guards_dirty = 1;
|
||||
|
||||
update_node_guard_status();
|
||||
}
|
||||
digestmap_free(added_by, tor_free_);
|
||||
return *msg ? -1 : 0;
|
||||
|
@ -506,10 +506,6 @@ accounting_run_housekeeping(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
/** When we have no idea how fast we are, how long do we assume it will take
|
||||
* us to exhaust our bandwidth? */
|
||||
#define GUESS_TIME_TO_USE_BANDWIDTH (24*60*60)
|
||||
|
||||
/** Based on our interval and our estimated bandwidth, choose a
|
||||
* deterministic (but random-ish) time to wake up. */
|
||||
static void
|
||||
|
@ -158,10 +158,6 @@ int can_complete_circuit=0;
|
||||
/** How long do we let a directory connection stall before expiring it? */
|
||||
#define DIR_CONN_MAX_STALL (5*60)
|
||||
|
||||
/** How long do we let OR connections handshake before we decide that
|
||||
* they are obsolete? */
|
||||
#define TLS_HANDSHAKE_TIMEOUT (60)
|
||||
|
||||
/** Decides our behavior when no logs are configured/before any
|
||||
* logs have been configured. For 0, we log notice to stdout as normal.
|
||||
* For 1, we log warnings only. For 2, we log nothing.
|
||||
@ -1129,7 +1125,7 @@ signewnym_impl(time_t now)
|
||||
return;
|
||||
}
|
||||
|
||||
circuit_expire_all_dirty_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
addressmap_clear_transient();
|
||||
rend_client_purge_state();
|
||||
time_of_last_signewnym = now;
|
||||
@ -1848,7 +1844,7 @@ do_hup(void)
|
||||
/* Rotate away from the old dirty circuits. This has to be done
|
||||
* after we've read the new options, but before we start using
|
||||
* circuits for directory fetches. */
|
||||
circuit_expire_all_dirty_circs();
|
||||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
|
||||
/* retry appropriate downloads */
|
||||
router_reset_status_download_failures();
|
||||
|
@ -71,7 +71,7 @@ HT_GENERATE(microdesc_map, microdesc_t, node,
|
||||
* *<b>annotation_len_out</b> to the number of bytes written as
|
||||
* annotations. */
|
||||
static ssize_t
|
||||
dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
|
||||
dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out)
|
||||
{
|
||||
ssize_t r = 0;
|
||||
size_t written;
|
||||
@ -81,10 +81,10 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
|
||||
char annotation[ISO_TIME_LEN+32];
|
||||
format_iso_time(buf, md->last_listed);
|
||||
tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
|
||||
if (fputs(annotation, f) < 0) {
|
||||
if (write_all(fd, annotation, strlen(annotation), 0) < 0) {
|
||||
log_warn(LD_DIR,
|
||||
"Couldn't write microdescriptor annotation: %s",
|
||||
strerror(ferror(f)));
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
r += strlen(annotation);
|
||||
@ -93,13 +93,13 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out)
|
||||
*annotation_len_out = 0;
|
||||
}
|
||||
|
||||
md->off = (off_t) ftell(f);
|
||||
written = fwrite(md->body, 1, md->bodylen, f);
|
||||
md->off = tor_fd_getpos(fd);
|
||||
written = write_all(fd, md->body, md->bodylen, 0);
|
||||
if (written != md->bodylen) {
|
||||
log_warn(LD_DIR,
|
||||
"Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
|
||||
(unsigned long)written, (unsigned long)md->bodylen,
|
||||
strerror(ferror(f)));
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
r += md->bodylen;
|
||||
@ -198,15 +198,15 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
|
||||
{
|
||||
smartlist_t *added;
|
||||
open_file_t *open_file = NULL;
|
||||
FILE *f = NULL;
|
||||
int fd = -1;
|
||||
// int n_added = 0;
|
||||
ssize_t size = 0;
|
||||
|
||||
if (where == SAVED_NOWHERE && !no_save) {
|
||||
f = start_writing_to_stdio_file(cache->journal_fname,
|
||||
OPEN_FLAGS_APPEND|O_BINARY,
|
||||
0600, &open_file);
|
||||
if (!f) {
|
||||
fd = start_writing_to_file(cache->journal_fname,
|
||||
OPEN_FLAGS_APPEND|O_BINARY,
|
||||
0600, &open_file);
|
||||
if (fd < 0) {
|
||||
log_warn(LD_DIR, "Couldn't append to journal in %s: %s",
|
||||
cache->journal_fname, strerror(errno));
|
||||
return NULL;
|
||||
@ -228,9 +228,9 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
|
||||
}
|
||||
|
||||
/* Okay, it's a new one. */
|
||||
if (f) {
|
||||
if (fd >= 0) {
|
||||
size_t annotation_len;
|
||||
size = dump_microdescriptor(f, md, &annotation_len);
|
||||
size = dump_microdescriptor(fd, md, &annotation_len);
|
||||
if (size < 0) {
|
||||
/* we already warned in dump_microdescriptor */
|
||||
abort_writing_to_file(open_file);
|
||||
@ -252,8 +252,14 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache,
|
||||
cache->total_len_seen += md->bodylen;
|
||||
} SMARTLIST_FOREACH_END(md);
|
||||
|
||||
if (f)
|
||||
finish_writing_to_file(open_file); /*XXX Check me.*/
|
||||
if (fd >= 0) {
|
||||
if (finish_writing_to_file(open_file) < 0) {
|
||||
log_warn(LD_DIR, "Error appending to microdescriptor file: %s",
|
||||
strerror(errno));
|
||||
smartlist_clear(added);
|
||||
return added;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
networkstatus_t *ns = networkstatus_get_latest_consensus();
|
||||
@ -406,11 +412,11 @@ int
|
||||
microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
|
||||
{
|
||||
open_file_t *open_file;
|
||||
FILE *f;
|
||||
int fd = -1;
|
||||
microdesc_t **mdp;
|
||||
smartlist_t *wrote;
|
||||
ssize_t size;
|
||||
off_t off = 0;
|
||||
off_t off = 0, off_real;
|
||||
int orig_size, new_size;
|
||||
|
||||
if (cache == NULL) {
|
||||
@ -430,10 +436,10 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
|
||||
orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
|
||||
orig_size += (int)cache->journal_len;
|
||||
|
||||
f = start_writing_to_stdio_file(cache->cache_fname,
|
||||
OPEN_FLAGS_REPLACE|O_BINARY,
|
||||
0600, &open_file);
|
||||
if (!f)
|
||||
fd = start_writing_to_file(cache->cache_fname,
|
||||
OPEN_FLAGS_REPLACE|O_BINARY,
|
||||
0600, &open_file);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
wrote = smartlist_new();
|
||||
@ -444,7 +450,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
|
||||
if (md->no_save)
|
||||
continue;
|
||||
|
||||
size = dump_microdescriptor(f, md, &annotation_len);
|
||||
size = dump_microdescriptor(fd, md, &annotation_len);
|
||||
if (size < 0) {
|
||||
/* XXX handle errors from dump_microdescriptor() */
|
||||
/* log? return -1? die? coredump the universe? */
|
||||
@ -453,6 +459,14 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
|
||||
tor_assert(((size_t)size) == annotation_len + md->bodylen);
|
||||
md->off = off + annotation_len;
|
||||
off += size;
|
||||
off_real = tor_fd_getpos(fd);
|
||||
if (off_real != off) {
|
||||
log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache."
|
||||
"By my count, I'm at "I64_FORMAT
|
||||
", but I should be at "I64_FORMAT,
|
||||
I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real));
|
||||
off = off_real;
|
||||
}
|
||||
if (md->saved_location != SAVED_IN_CACHE) {
|
||||
tor_free(md->body);
|
||||
md->saved_location = SAVED_IN_CACHE;
|
||||
@ -460,11 +474,15 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
|
||||
smartlist_add(wrote, md);
|
||||
}
|
||||
|
||||
if (finish_writing_to_file(open_file) < 0) {
|
||||
log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cache->cache_content)
|
||||
tor_munmap_file(cache->cache_content);
|
||||
|
||||
finish_writing_to_file(open_file); /*XXX Check me.*/
|
||||
|
||||
cache->cache_content = tor_mmap_file(cache->cache_fname);
|
||||
|
||||
if (!cache->cache_content && smartlist_len(wrote)) {
|
||||
@ -532,7 +550,7 @@ microdesc_check_counts(void)
|
||||
/** Deallocate a single microdescriptor. Note: the microdescriptor MUST have
|
||||
* previously been removed from the cache if it had ever been inserted. */
|
||||
void
|
||||
microdesc_free(microdesc_t *md)
|
||||
microdesc_free_(microdesc_t *md, const char *fname, int lineno)
|
||||
{
|
||||
if (!md)
|
||||
return;
|
||||
@ -543,12 +561,12 @@ microdesc_free(microdesc_t *md)
|
||||
microdesc_cache_t *cache = get_microdesc_cache();
|
||||
microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md);
|
||||
if (md2 == md) {
|
||||
log_warn(LD_BUG, "microdesc_free() called, but md was still in "
|
||||
"microdesc_map");
|
||||
log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still "
|
||||
"in microdesc_map", fname, lineno);
|
||||
HT_REMOVE(microdesc_map, &cache->map, md);
|
||||
} else {
|
||||
log_warn(LD_BUG, "microdesc_free() called with held_in_map set, but "
|
||||
"microdesc was not in the map.");
|
||||
log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_in_map "
|
||||
"set, but microdesc was not in the map.", fname, lineno);
|
||||
}
|
||||
tor_fragile_assert();
|
||||
}
|
||||
@ -562,11 +580,13 @@ microdesc_free(microdesc_t *md)
|
||||
}
|
||||
});
|
||||
if (found) {
|
||||
log_warn(LD_BUG, "microdesc_free() called, but md was still referenced "
|
||||
"%d node(s); held_by_nodes == %u", found, md->held_by_nodes);
|
||||
log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still "
|
||||
"referenced %d node(s); held_by_nodes == %u",
|
||||
fname, lineno, found, md->held_by_nodes);
|
||||
} else {
|
||||
log_warn(LD_BUG, "microdesc_free() called with held_by_nodes set to %u, "
|
||||
"but md was not referenced by any nodes", md->held_by_nodes);
|
||||
log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_by_nodes "
|
||||
"set to %u, but md was not referenced by any nodes",
|
||||
fname, lineno, md->held_by_nodes);
|
||||
}
|
||||
tor_fragile_assert();
|
||||
}
|
||||
|
@ -39,7 +39,9 @@ smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns,
|
||||
int downloadable_only,
|
||||
digestmap_t *skip);
|
||||
|
||||
void microdesc_free(microdesc_t *md);
|
||||
void microdesc_free_(microdesc_t *md, const char *fname, int line);
|
||||
#define microdesc_free(md) \
|
||||
microdesc_free_((md), __FILE__, __LINE__)
|
||||
void microdesc_free_all(void);
|
||||
|
||||
void update_microdesc_downloads(time_t now);
|
||||
|
@ -1432,18 +1432,6 @@ consensus_is_waiting_for_certs(void)
|
||||
? 1 : 0;
|
||||
}
|
||||
|
||||
/** Return the network status with a given identity digest. */
|
||||
networkstatus_v2_t *
|
||||
networkstatus_v2_get_by_digest(const char *digest)
|
||||
{
|
||||
SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
|
||||
{
|
||||
if (tor_memeq(ns->identity_digest, digest, DIGEST_LEN))
|
||||
return ns;
|
||||
});
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the most recent consensus that we have downloaded, or NULL if we
|
||||
* don't have one. */
|
||||
networkstatus_t *
|
||||
|
@ -75,7 +75,6 @@ void update_certificate_downloads(time_t now);
|
||||
int consensus_is_waiting_for_certs(void);
|
||||
int client_would_use_router(const routerstatus_t *rs, time_t now,
|
||||
const or_options_t *options);
|
||||
networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest);
|
||||
networkstatus_t *networkstatus_get_latest_consensus(void);
|
||||
networkstatus_t *networkstatus_get_latest_consensus_by_flavor(
|
||||
consensus_flavor_t f);
|
||||
|
@ -688,6 +688,24 @@ node_exit_policy_rejects_all(const node_t *node)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Return true iff the exit policy for <b>node</b> is such that we can treat
|
||||
* rejecting an address of type <b>family</b> unexpectedly as a sign of that
|
||||
* node's failure. */
|
||||
int
|
||||
node_exit_policy_is_exact(const node_t *node, sa_family_t family)
|
||||
{
|
||||
if (family == AF_UNSPEC) {
|
||||
return 1; /* Rejecting an address but not telling us what address
|
||||
* is a bad sign. */
|
||||
} else if (family == AF_INET) {
|
||||
return node->ri != NULL;
|
||||
} else if (family == AF_INET6) {
|
||||
return 0;
|
||||
}
|
||||
tor_fragile_assert();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Return list of tor_addr_port_t with all OR ports (in the sense IP
|
||||
* addr + TCP port) for <b>node</b>. Caller must free all elements
|
||||
* using tor_free() and free the list using smartlist_free().
|
||||
@ -1400,7 +1418,7 @@ get_frac_paths_needed_for_circs(const or_options_t *options,
|
||||
const networkstatus_t *ns)
|
||||
{
|
||||
#define DFLT_PCT_USABLE_NEEDED 60
|
||||
if (options->PathsNeededToBuildCircuits >= 1.0) {
|
||||
if (options->PathsNeededToBuildCircuits >= 0.0) {
|
||||
return options->PathsNeededToBuildCircuits;
|
||||
} else {
|
||||
return networkstatus_get_param(ns, "min_paths_for_circs_pct",
|
||||
|
@ -41,6 +41,7 @@ int node_get_purpose(const node_t *node);
|
||||
(node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE)
|
||||
int node_is_me(const node_t *node);
|
||||
int node_exit_policy_rejects_all(const node_t *node);
|
||||
int node_exit_policy_is_exact(const node_t *node, sa_family_t family);
|
||||
smartlist_t *node_get_all_orports(const node_t *node);
|
||||
int node_allows_single_hop_exits(const node_t *node);
|
||||
const char *node_get_nickname(const node_t *node);
|
||||
|
40
src/or/or.h
40
src/or/or.h
@ -1417,8 +1417,8 @@ typedef struct or_connection_t {
|
||||
unsigned int is_outgoing:1;
|
||||
unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */
|
||||
unsigned int wide_circ_ids:1;
|
||||
uint8_t link_proto; /**< What protocol version are we using? 0 for
|
||||
* "none negotiated yet." */
|
||||
uint16_t link_proto; /**< What protocol version are we using? 0 for
|
||||
* "none negotiated yet." */
|
||||
|
||||
or_handshake_state_t *handshake_state; /**< If we are setting this connection
|
||||
* up, state information to do so. */
|
||||
@ -2249,6 +2249,9 @@ typedef struct node_t {
|
||||
/** Local info: we treat this node as if it rejects everything */
|
||||
unsigned int rejects_all:1;
|
||||
|
||||
/** Local info: this node is in our list of guards */
|
||||
unsigned int using_as_guard:1;
|
||||
|
||||
/* Local info: derived. */
|
||||
|
||||
/** True if the IPv6 OR port is preferred over the IPv4 OR port. */
|
||||
@ -2942,6 +2945,10 @@ typedef struct origin_circuit_t {
|
||||
*/
|
||||
ENUM_BF(path_state_t) path_state : 3;
|
||||
|
||||
/* If this flag is set, we should not consider attaching any more
|
||||
* connections to this circuit. */
|
||||
unsigned int unusable_for_new_conns : 1;
|
||||
|
||||
/**
|
||||
* Tristate variable to guard against pathbias miscounting
|
||||
* due to circuit purpose transitions changing the decision
|
||||
@ -3059,6 +3066,10 @@ typedef struct origin_circuit_t {
|
||||
* ISO_STREAM. */
|
||||
uint64_t associated_isolated_stream_global_id;
|
||||
/**@}*/
|
||||
/** A list of addr_policy_t for this circuit in particular. Used by
|
||||
* adjust_exit_policy_from_exitpolicy_failure.
|
||||
*/
|
||||
smartlist_t *prepend_policy;
|
||||
} origin_circuit_t;
|
||||
|
||||
struct onion_queue_t;
|
||||
@ -3868,6 +3879,10 @@ typedef struct {
|
||||
* consensus vote on the 'params' line. */
|
||||
char *ConsensusParams;
|
||||
|
||||
/** Authority only: minimum number of measured bandwidths we must see
|
||||
* before we only beliee measured bandwidths to assign flags. */
|
||||
int MinMeasuredBWsForAuthToIgnoreAdvertised;
|
||||
|
||||
/** The length of time that we think an initial consensus should be fresh.
|
||||
* Only altered on testing networks. */
|
||||
int TestingV3AuthInitialVotingInterval;
|
||||
@ -3895,6 +3910,12 @@ typedef struct {
|
||||
* of certain configuration options. */
|
||||
int TestingTorNetwork;
|
||||
|
||||
/** Minimum value for the Exit flag threshold on testing networks. */
|
||||
uint64_t TestingMinExitFlagThreshold;
|
||||
|
||||
/** Minimum value for the Fast flag threshold on testing networks. */
|
||||
uint64_t TestingMinFastFlagThreshold;
|
||||
|
||||
/** If true, and we have GeoIP data, and we're a bridge, keep a per-country
|
||||
* count of how many client addresses have contacted us so that we can help
|
||||
* the bridge authority guess which countries have blocked access to us. */
|
||||
@ -4012,6 +4033,8 @@ typedef struct {
|
||||
* should guess a suitable value. */
|
||||
int SSLKeyLifetime;
|
||||
|
||||
/** How long (seconds) do we keep a guard before picking a new one? */
|
||||
int GuardLifetime;
|
||||
} or_options_t;
|
||||
|
||||
/** Persistent state for an onion router, as saved to disk. */
|
||||
@ -4465,15 +4488,6 @@ typedef struct vote_timing_t {
|
||||
|
||||
/********************************* geoip.c **************************/
|
||||
|
||||
/** Round all GeoIP results to the next multiple of this value, to avoid
|
||||
* leaking information. */
|
||||
#define DIR_RECORD_USAGE_GRANULARITY 8
|
||||
/** Time interval: Flush geoip data to disk this often. */
|
||||
#define DIR_ENTRY_RECORD_USAGE_RETAIN_IPS (24*60*60)
|
||||
/** How long do we have to have observed per-country request history before
|
||||
* we are willing to talk about it? */
|
||||
#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (12*60*60)
|
||||
|
||||
/** Indicates an action that we might be noting geoip statistics on.
|
||||
* Note that if we're noticing CONNECT, we're a bridge, and if we're noticing
|
||||
* the others, we're not.
|
||||
@ -4793,6 +4807,10 @@ typedef struct dir_server_t {
|
||||
#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
|
||||
#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4)
|
||||
|
||||
/** This node is to be chosen as a directory guard, so don't choose any
|
||||
* node that's currently a guard. */
|
||||
#define PDS_FOR_GUARD (1<<5)
|
||||
|
||||
#define PDS_PREFER_TUNNELED_DIR_CONNS_ (1<<16)
|
||||
|
||||
/** Possible ways to weight routers when choosing one randomly. See
|
||||
|
@ -837,6 +837,24 @@ append_exit_policy_string(smartlist_t **policy, const char *more)
|
||||
}
|
||||
}
|
||||
|
||||
/** Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. */
|
||||
void
|
||||
addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
|
||||
{
|
||||
addr_policy_t p, *add;
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.policy_type = ADDR_POLICY_REJECT;
|
||||
p.maskbits = tor_addr_family(addr) == AF_INET6 ? 128 : 32;
|
||||
tor_addr_copy(&p.addr, addr);
|
||||
p.prt_min = 1;
|
||||
p.prt_max = 65535;
|
||||
|
||||
add = addr_policy_get_canonical_entry(&p);
|
||||
if (!*dest)
|
||||
*dest = smartlist_new();
|
||||
smartlist_add(*dest, add);
|
||||
}
|
||||
|
||||
/** Detect and excise "dead code" from the policy *<b>dest</b>. */
|
||||
static void
|
||||
exit_policy_remove_redundancies(smartlist_t *dest)
|
||||
|
@ -47,6 +47,8 @@ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
|
||||
int rejectprivate, const char *local_address,
|
||||
int add_default_policy);
|
||||
void policies_exit_policy_append_reject_star(smartlist_t **dest);
|
||||
void addr_policy_append_reject_addr(smartlist_t **dest,
|
||||
const tor_addr_t *addr);
|
||||
void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter);
|
||||
int exit_policy_is_general_exit(smartlist_t *policy);
|
||||
int policy_is_reject_star(const smartlist_t *policy, sa_family_t family);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "channel.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "circuitlist.h"
|
||||
#include "circuituse.h"
|
||||
#include "config.h"
|
||||
#include "connection.h"
|
||||
#include "connection_edge.h"
|
||||
@ -53,6 +54,10 @@ static int circuit_resume_edge_reading_helper(edge_connection_t *conn,
|
||||
static int circuit_consider_stop_edge_reading(circuit_t *circ,
|
||||
crypt_path_t *layer_hint);
|
||||
static int circuit_queue_streams_are_blocked(circuit_t *circ);
|
||||
static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
|
||||
entry_connection_t *conn,
|
||||
node_t *node,
|
||||
const tor_addr_t *addr);
|
||||
|
||||
/** Stop reading on edge connections when we have this many cells
|
||||
* waiting on the appropriate queue. */
|
||||
@ -710,7 +715,6 @@ connection_ap_process_end_not_open(
|
||||
relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
|
||||
entry_connection_t *conn, crypt_path_t *layer_hint)
|
||||
{
|
||||
struct in_addr in;
|
||||
node_t *exitrouter;
|
||||
int reason = *(cell->payload+RELAY_HEADER_SIZE);
|
||||
int control_reason;
|
||||
@ -753,10 +757,10 @@ connection_ap_process_end_not_open(
|
||||
stream_end_reason_to_string(reason));
|
||||
exitrouter = node_get_mutable_by_id(chosen_exit_digest);
|
||||
switch (reason) {
|
||||
case END_STREAM_REASON_EXITPOLICY:
|
||||
case END_STREAM_REASON_EXITPOLICY: {
|
||||
tor_addr_t addr;
|
||||
tor_addr_make_unspec(&addr);
|
||||
if (rh->length >= 5) {
|
||||
tor_addr_t addr;
|
||||
|
||||
int ttl = -1;
|
||||
tor_addr_make_unspec(&addr);
|
||||
if (rh->length == 5 || rh->length == 9) {
|
||||
@ -808,16 +812,11 @@ connection_ap_process_end_not_open(
|
||||
}
|
||||
}
|
||||
/* check if he *ought* to have allowed it */
|
||||
if (exitrouter &&
|
||||
(rh->length < 5 ||
|
||||
(tor_inet_aton(conn->socks_request->address, &in) &&
|
||||
!conn->chosen_exit_name))) {
|
||||
log_info(LD_APP,
|
||||
"Exitrouter %s seems to be more restrictive than its exit "
|
||||
"policy. Not using this router as exit for now.",
|
||||
node_describe(exitrouter));
|
||||
policies_set_node_exitpolicy_to_reject_all(exitrouter);
|
||||
}
|
||||
|
||||
adjust_exit_policy_from_exitpolicy_failure(circ,
|
||||
conn,
|
||||
exitrouter,
|
||||
&addr);
|
||||
|
||||
if (conn->chosen_exit_optional ||
|
||||
conn->chosen_exit_retries) {
|
||||
@ -837,6 +836,7 @@ connection_ap_process_end_not_open(
|
||||
return 0;
|
||||
/* else, conn will get closed below */
|
||||
break;
|
||||
}
|
||||
case END_STREAM_REASON_CONNECTREFUSED:
|
||||
if (!conn->chosen_exit_optional)
|
||||
break; /* break means it'll close, below */
|
||||
@ -851,9 +851,7 @@ connection_ap_process_end_not_open(
|
||||
/* We haven't retried too many times; reattach the connection. */
|
||||
circuit_log_path(LOG_INFO,LD_APP,circ);
|
||||
/* Mark this circuit "unusable for new streams". */
|
||||
/* XXXX024 this is a kludgy way to do this. */
|
||||
tor_assert(circ->base_.timestamp_dirty);
|
||||
circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
|
||||
mark_circuit_unusable_for_new_conns(circ);
|
||||
|
||||
if (conn->chosen_exit_optional) {
|
||||
/* stop wanting a specific exit */
|
||||
@ -901,6 +899,47 @@ connection_ap_process_end_not_open(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Called when we have gotten an END_REASON_EXITPOLICY failure on <b>circ</b>
|
||||
* for <b>conn</b>, while attempting to connect via <b>node</b>. If the node
|
||||
* told us which address it rejected, then <b>addr</b> is that address;
|
||||
* otherwise it is AF_UNSPEC.
|
||||
*
|
||||
* If we are sure the node should have allowed this address, mark the node as
|
||||
* having a reject *:* exit policy. Otherwise, mark the circuit as unusable
|
||||
* for this particular address.
|
||||
**/
|
||||
static void
|
||||
adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
|
||||
entry_connection_t *conn,
|
||||
node_t *node,
|
||||
const tor_addr_t *addr)
|
||||
{
|
||||
int make_reject_all = 0;
|
||||
const sa_family_t family = tor_addr_family(addr);
|
||||
|
||||
if (node) {
|
||||
tor_addr_t tmp;
|
||||
int asked_for_family = tor_addr_parse(&tmp, conn->socks_request->address);
|
||||
if (family == AF_UNSPEC) {
|
||||
make_reject_all = 1;
|
||||
} else if (node_exit_policy_is_exact(node, family) &&
|
||||
asked_for_family != -1 && !conn->chosen_exit_name) {
|
||||
make_reject_all = 1;
|
||||
}
|
||||
|
||||
if (make_reject_all) {
|
||||
log_info(LD_APP,
|
||||
"Exitrouter %s seems to be more restrictive than its exit "
|
||||
"policy. Not using this router as exit for now.",
|
||||
node_describe(node));
|
||||
policies_set_node_exitpolicy_to_reject_all(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (family != AF_UNSPEC)
|
||||
addr_policy_append_reject_addr(&circ->prepend_policy, addr);
|
||||
}
|
||||
|
||||
/** Helper: change the socks_request->address field on conn to the
|
||||
* dotted-quad representation of <b>new_addr</b>,
|
||||
* and send an appropriate REMAP event. */
|
||||
@ -1101,12 +1140,15 @@ connection_edge_process_relay_cell_not_open(
|
||||
2+answer_len));
|
||||
else
|
||||
ttl = -1;
|
||||
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
|
||||
uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
|
||||
if (get_options()->ClientDNSRejectInternalAddresses &&
|
||||
is_internal_IP(addr, 0)) {
|
||||
if (answer_type == RESOLVED_TYPE_IPV4 ||
|
||||
answer_type == RESOLVED_TYPE_IPV6) {
|
||||
tor_addr_t addr;
|
||||
if (decode_address_from_payload(&addr, cell->payload+RELAY_HEADER_SIZE,
|
||||
rh->length) &&
|
||||
tor_addr_is_internal(&addr, 0) &&
|
||||
get_options()->ClientDNSRejectInternalAddresses) {
|
||||
log_info(LD_APP,"Got a resolve with answer %s. Rejecting.",
|
||||
fmt_addr32(addr));
|
||||
fmt_addr(&addr));
|
||||
connection_ap_handshake_socks_resolved(entry_conn,
|
||||
RESOLVED_TYPE_ERROR_TRANSIENT,
|
||||
0, NULL, 0, TIME_MAX);
|
||||
@ -1398,6 +1440,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
"'truncate' unsupported at origin. Dropping.");
|
||||
return 0;
|
||||
}
|
||||
if (circ->n_hop) {
|
||||
if (circ->n_chan)
|
||||
log_warn(LD_BUG, "n_chan and n_hop set on the same circuit!");
|
||||
extend_info_free(circ->n_hop);
|
||||
circ->n_hop = NULL;
|
||||
tor_free(circ->n_chan_create_cell);
|
||||
circuit_set_state(circ, CIRCUIT_STATE_OPEN);
|
||||
}
|
||||
if (circ->n_chan) {
|
||||
uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE);
|
||||
circuit_clear_cell_queue(circ, circ->n_chan);
|
||||
|
@ -1452,13 +1452,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
|
||||
command);
|
||||
}
|
||||
|
||||
/** Return the number of entries in our rendezvous descriptor cache. */
|
||||
int
|
||||
rend_cache_size(void)
|
||||
{
|
||||
return strmap_size(rend_cache);
|
||||
}
|
||||
|
||||
/** Allocate and return a new rend_data_t with the same
|
||||
* contents as <b>query</b>. */
|
||||
rend_data_t *
|
||||
|
@ -49,7 +49,6 @@ int rend_cache_store(const char *desc, size_t desc_len, int published,
|
||||
int rend_cache_store_v2_desc_as_client(const char *desc,
|
||||
const rend_data_t *rend_query);
|
||||
int rend_cache_store_v2_desc_as_dir(const char *desc);
|
||||
int rend_cache_size(void);
|
||||
int rend_encode_v2_descriptors(smartlist_t *descs_out,
|
||||
rend_service_descriptor_t *desc, time_t now,
|
||||
uint8_t period, rend_auth_type_t auth_type,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user