Merge branch 'maint-0.2.4' into release-0.2.4

This commit is contained in:
Roger Dingledine 2013-04-11 01:29:24 -04:00
commit 887eba9895
115 changed files with 6581 additions and 17068 deletions

6
changes/bug6174 Normal file
View 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
View 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
View 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
View 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
View 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
View 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.

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

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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the April 3 2013 Maxmind GeoLite Country database.

11
changes/log-noise Normal file
View 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
View 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.

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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