mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Merge remote branch 'origin/master' into bug2046
This commit is contained in:
@@ -146,6 +146,8 @@
|
||||
/src/test/Makefile.in
|
||||
/src/test/test
|
||||
/src/test/test-child
|
||||
/src/test/test.exe
|
||||
/src/test/test-child.exe
|
||||
|
||||
|
||||
# /src/tools/
|
||||
|
||||
@@ -391,7 +391,7 @@ Changes in version 0.2.2.26-beta - 2011-05-17
|
||||
- Authorities now clean their microdesc cache periodically and when
|
||||
reading from disk initially, not only when adding new descriptors.
|
||||
This prevents a bug where we could lose microdescriptors. Bugfix
|
||||
on 0.2.2.6-alpha. 2230
|
||||
on 0.2.2.6-alpha. Fixes bug 2230.
|
||||
- Do not crash when our configuration file becomes unreadable, for
|
||||
example due to a permissions change, between when we start up
|
||||
and when a controller calls SAVECONF. Fixes bug 3135; bugfix
|
||||
@@ -1019,6 +1019,57 @@ Changes in version 0.2.2.23-alpha - 2011-03-08
|
||||
git://git.torproject.org/torspec.git
|
||||
|
||||
|
||||
Changes in version 0.2.1.30 - 2011-02-23
|
||||
Tor 0.2.1.30 fixes a variety of less critical bugs. The main other
|
||||
change is a slight tweak to Tor's TLS handshake that makes relays
|
||||
and bridges that run this new version reachable from Iran again.
|
||||
We don't expect this tweak will win the arms race long-term, but it
|
||||
buys us time until we roll out a better solution.
|
||||
|
||||
o Major bugfixes:
|
||||
- Stop sending a CLOCK_SKEW controller status event whenever
|
||||
we fetch directory information from a relay that has a wrong clock.
|
||||
Instead, only inform the controller when it's a trusted authority
|
||||
that claims our clock is wrong. Bugfix on 0.1.2.6-alpha; fixes
|
||||
the rest of bug 1074.
|
||||
- Fix a bounds-checking error that could allow an attacker to
|
||||
remotely crash a directory authority. Bugfix on 0.2.1.5-alpha.
|
||||
Found by "piebeer".
|
||||
- If relays set RelayBandwidthBurst but not RelayBandwidthRate,
|
||||
Tor would ignore their RelayBandwidthBurst setting,
|
||||
potentially using more bandwidth than expected. Bugfix on
|
||||
0.2.0.1-alpha. Reported by Paul Wouters. Fixes bug 2470.
|
||||
- Ignore and warn if the user mistakenly sets "PublishServerDescriptor
|
||||
hidserv" in her torrc. The 'hidserv' argument never controlled
|
||||
publication of hidden service descriptors. Bugfix on 0.2.0.1-alpha.
|
||||
|
||||
o Minor features:
|
||||
- Adjust our TLS Diffie-Hellman parameters to match those used by
|
||||
Apache's mod_ssl.
|
||||
- Update to the February 1 2011 Maxmind GeoLite Country database.
|
||||
|
||||
o Minor bugfixes:
|
||||
- Check for and reject overly long directory certificates and
|
||||
directory tokens before they have a chance to hit any assertions.
|
||||
Bugfix on 0.2.1.28. Found by "doorss".
|
||||
- Bring the logic that gathers routerinfos and assesses the
|
||||
acceptability of circuits into line. This prevents a Tor OP from
|
||||
getting locked in a cycle of choosing its local OR as an exit for a
|
||||
path (due to a .exit request) and then rejecting the circuit because
|
||||
its OR is not listed yet. It also prevents Tor clients from using an
|
||||
OR running in the same instance as an exit (due to a .exit request)
|
||||
if the OR does not meet the same requirements expected of an OR
|
||||
running elsewhere. Fixes bug 1859; bugfix on 0.1.0.1-rc.
|
||||
|
||||
o Packaging changes:
|
||||
- Stop shipping the Tor specs files and development proposal documents
|
||||
in the tarball. They are now in a separate git repository at
|
||||
git://git.torproject.org/torspec.git
|
||||
- Do not include Git version tags as though they are SVN tags when
|
||||
generating a tarball from inside a repository that has switched
|
||||
between branches. Bugfix on 0.2.1.15-rc; fixes bug 2402.
|
||||
|
||||
|
||||
Changes in version 0.2.2.22-alpha - 2011-01-25
|
||||
Tor 0.2.2.22-alpha fixes a few more less-critical security issues. The
|
||||
main other change is a slight tweak to Tor's TLS handshake that makes
|
||||
@@ -2679,8 +2730,9 @@ Changes in version 0.2.2.5-alpha - 2009-10-11
|
||||
o Major bugfixes:
|
||||
- Make the tarball compile again. Oops. Bugfix on 0.2.2.4-alpha.
|
||||
|
||||
o New directory authorities:
|
||||
- Move dizum to an alternate IP address.
|
||||
o Directory authorities:
|
||||
- Temporarily (just for this release) move dizum to an alternate
|
||||
IP address.
|
||||
|
||||
|
||||
Changes in version 0.2.2.4-alpha - 2009-10-10
|
||||
|
||||
@@ -15,6 +15,7 @@ EXTRA_DIST = \
|
||||
ChangeLog \
|
||||
INSTALL \
|
||||
LICENSE \
|
||||
Makefile.nmake \
|
||||
README \
|
||||
ReleaseNotes \
|
||||
tor.spec \
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
all:
|
||||
cd src/common
|
||||
$(MAKE) /F Makefile.nmake
|
||||
cd ../../src/or
|
||||
$(MAKE) /F Makefile.nmake
|
||||
@@ -0,0 +1,5 @@
|
||||
o Minor features:
|
||||
- CONF_CHANGED event is provided so that controllers can be notified
|
||||
of any configuration changes made by other controllers/SETCONF/HUP.
|
||||
Implements #1692.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
o Minor features:
|
||||
- Replace files in stats/ rather than appending to them. Now that we
|
||||
include statistics in extra-info descriptors, it makes no sense to
|
||||
keep old statistics forever. Implements #2930.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
o Minor bugfixes:
|
||||
- The "--quiet" and "--hush" options now apply not only to Tor's
|
||||
behavior before user-configured logs are added, but also to
|
||||
Tor's behavior in the absense of configured logs. Fixes bug
|
||||
3550; bugfix on 0.2.0.10-alpha.
|
||||
@@ -0,0 +1,3 @@
|
||||
o Minor bugfixes:
|
||||
- Fix a spurious warning when parsing SOCKS requests with
|
||||
bufferevents enabled. Fixes bug 3615; bugfix on 0.2.3.2-alpha.
|
||||
@@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- Selectively disable deprecation warnings on OS X because Lion started
|
||||
deprecating the shipped copy of openssl. Fixes bug 3643.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
o Minor bugfixes:
|
||||
- Get rid of a harmless warning that could happen on relays running
|
||||
with bufferevents. The warning was caused by someone doing an http
|
||||
request to a relay's orport. Also don't warn for a few related
|
||||
non-errors. Fixes bug 3700; bugfix on 0.2.3.1-alpha.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
o Major bugfixes:
|
||||
|
||||
- Remove an extra pair of quotation marks around the error
|
||||
message in control-port STATUS_GENERAL BUG events. Bugfix on
|
||||
0.1.2.6-alpha; fixes bug 3732.
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
o Major bugfixes:
|
||||
- Write control ports to disk only after switching UID and
|
||||
creating the data directory. This way, we don't fail when
|
||||
starting up with a nonexistant DataDirectory and a
|
||||
ControlPortWriteToFile setting based on that directory. Fixes
|
||||
bug 3747; bugfix on Tor 0.2.2.26-beta.
|
||||
@@ -0,0 +1,4 @@
|
||||
o Minor bugfixes:
|
||||
- When unable to format an address as a string, report its value
|
||||
as "???" rather than reusing the last formatted address. Bugfix
|
||||
on 0.2.1.5-alpha.
|
||||
@@ -0,0 +1,3 @@
|
||||
o Minor features:
|
||||
- Update to the August 2 2011 Maxmind GeoLite Country database.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
o Major bugfixes (IOCP):
|
||||
- When using IOCP on windows, we need to enable Libevent windows threading
|
||||
support. Bugfix on 0.2.3.1-alpha.
|
||||
@@ -0,0 +1,3 @@
|
||||
o Minor features (build compatibility):
|
||||
- Limited, experimental support for building with nmake and MSVC.
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
o Major features:
|
||||
- When using an exit nodes running 0.2.3.1-alpha and later,
|
||||
clients can now "optimistically" send data on a stream before
|
||||
the exit node reports that the stream has opened. This can save
|
||||
a round trip when starting connections with protocols where the
|
||||
client speaks first. This behavior is controlled by a (currently
|
||||
disabled) networkstatus consensus parameter. To turn it on or
|
||||
off manually, use the "OptimisticData" torrc option. Implements
|
||||
proposal 181; code by Ian Goldberg.
|
||||
@@ -0,0 +1,22 @@
|
||||
o Major features:
|
||||
- You can now configure Tor so that streams from different
|
||||
applications are isolated on different circuits, to prevent an
|
||||
attacker who sees your streams leaving an exit node from linking
|
||||
your sessions to one another. To do this, choose some way to
|
||||
distinguish the applications -- have them connect to different
|
||||
SocksPorts, or have one of them use SOCKS4 while the other uses
|
||||
SOCKS5, or have them pass different authentication strings to
|
||||
the SOCKS proxy. Then use the new SocksPort syntax to configure
|
||||
the degree of isolation you need. This implements Proposal 171.
|
||||
|
||||
o Minor features:
|
||||
- There's a new syntax for specifying multiple client ports (such as
|
||||
SOCKSPort, TransPort, DNSPort, NATDPort): you can now just declare
|
||||
multiple ...Port entries with full addr:port syntax on each.
|
||||
The old ...ListenAddress format is still supported, but you can't
|
||||
mix it with the new SOCKSPort syntax.
|
||||
|
||||
o Code simplifications and refactoring:
|
||||
- Rewrote the listener-selection logic so that parsing which ports
|
||||
we want to listen on is now separate form binding to the ports
|
||||
we want.
|
||||
@@ -0,0 +1,12 @@
|
||||
o Build changes:
|
||||
- Building Tor with bufferevent support now requires Libevent
|
||||
2.0.13-stable or later. Previous versions of Libevent had bugs
|
||||
in SSL-related bufferevents and related issues that would make
|
||||
Tor work badly with bufferevents. Requiring 2.0.13-stable also
|
||||
means that Tor with bufferevents can take advantage of Libevent
|
||||
APIs introduced after 2.0.8-rc.
|
||||
|
||||
o Minor bugfixes:
|
||||
- Use evbuffer_copyout() in inspect_evbuffer(). This fixes a memory
|
||||
leak, and lets Libevent worry about how to best copy data out
|
||||
of a buffer.
|
||||
+11
-2
@@ -438,7 +438,7 @@ int x = 1;
|
||||
AC_MSG_CHECKING([whether Libevent is new enough for bufferevents])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <event2/event.h>
|
||||
#if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000800
|
||||
#if !defined(LIBEVENT_VERSION_NUMBER) || LIBEVENT_VERSION_NUMBER < 0x02000d00
|
||||
#error
|
||||
int x = y(zz);
|
||||
#else
|
||||
@@ -446,7 +446,7 @@ int x = 1;
|
||||
#endif
|
||||
])], [ AC_MSG_RESULT([yes]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([Libevent does not seem new enough to support bufferevents. We require 2.0.8-rc or later]) ] )
|
||||
AC_MSG_ERROR([Libevent does not seem new enough to support bufferevents. We require 2.0.13-stable or later]) ] )
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1123,6 +1123,15 @@ else
|
||||
enable_gcc_warnings_advisory=no
|
||||
fi
|
||||
|
||||
# OS X Lion started deprecating the system openssl. Let's just disable
|
||||
# all deprecation warnings on OS X.
|
||||
case "$host_os" in
|
||||
|
||||
darwin*)
|
||||
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Add some more warnings which we use in development but not in the
|
||||
# released versions. (Some relevant gcc versions can't handle these.)
|
||||
if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xyes; then
|
||||
|
||||
+87
-23
@@ -464,7 +464,7 @@ CLIENT OPTIONS
|
||||
--------------
|
||||
|
||||
The following options are useful only for clients (that is, if
|
||||
**SocksPort** is non-zero):
|
||||
**SocksPort**, **TransPort**, **DNSPort**, or **NATDPort** is non-zero):
|
||||
|
||||
**AllowInvalidNodes** **entry**|**exit**|**middle**|**introduction**|**rendezvous**|**...**::
|
||||
If some Tor servers are obviously not working right, the directory
|
||||
@@ -682,17 +682,49 @@ The following options are useful only for clients (that is, if
|
||||
the same circuit. Currently, two addresses are "too close" if they lie in
|
||||
the same /16 range. (Default: 1)
|
||||
|
||||
**SocksPort** __PORT__|**auto**::
|
||||
Advertise this port to listen for connections from Socks-speaking
|
||||
**SOCKSPort** \['address':]__port__|**auto** [_isolation flags_]::
|
||||
Open this port to listen for connections from SOCKS-speaking
|
||||
applications. Set this to 0 if you don't want to allow application
|
||||
connections via SOCKS. Set it to "auto" to have Tor pick a port for
|
||||
you. (Default: 9050)
|
||||
you. This directive can be specified multiple times to bind
|
||||
to multiple addresses/ports. (Default: 9050) +
|
||||
+
|
||||
The _isolation flags_ arguments give Tor rules for which streams
|
||||
received on this SOCKSPort are allowed to share circuits with one
|
||||
another. Recognized isolation flags are:
|
||||
**IsolateClientAddr**;;
|
||||
Don't share a circuits with streams from a different
|
||||
client address. (On by default and strongly recommended;
|
||||
you can disable it with **NoIsolateClientAddr**.)
|
||||
**IsolateSOCKSAuth**;;
|
||||
Don't share a circuits with streams for which different
|
||||
SOCKS authentication was provided. (On by default;
|
||||
you can disable it with **NoIsolateSOCKSAuth**.)
|
||||
**IsolateClientProtocol**;;
|
||||
Don't share circuits with streams using a different protocol.
|
||||
(SOCKS 4, SOCKS 5, TransPort connections, NATDPort connections,
|
||||
and DNSPort requests are all considered to be different protocols.)
|
||||
**IsolateDestPort**;;
|
||||
Don't share a circuits with streams targetting a different
|
||||
destination port.
|
||||
**IsolateDestAddr**;;
|
||||
Don't share a circuits with streams targetting a different
|
||||
destination address.
|
||||
**SessionGroup=**__INT__;;
|
||||
If no other isolation rules would prevent it, allow streams
|
||||
on this port to share circuits with streams from every other
|
||||
port with the same session group. (By default, streams received
|
||||
on different ports are always isolated from one another.)
|
||||
|
||||
**SocksListenAddress** __IP__[:__PORT__]::
|
||||
**SOCKSListenAddress** __IP__[:__PORT__]::
|
||||
Bind to this address to listen for connections from Socks-speaking
|
||||
applications. (Default: 127.0.0.1) You can also specify a port (e.g.
|
||||
192.168.0.1:9100). This directive can be specified multiple times to bind
|
||||
to multiple addresses/ports.
|
||||
to multiple addresses/ports. (DEPRECATED: As of 0.2.3.x-alpha, you can
|
||||
now use multiple SOCKSPort entries, and provide addresses for SOCKSPort
|
||||
entries, so SOCKSListenAddress no longer has a purpose. For backward
|
||||
compatibility, SOCKSListenAddress is only allowed when SOCKSPort is just
|
||||
a port number.)
|
||||
|
||||
**SocksPolicy** __policy__,__policy__,__...__::
|
||||
Set an entrance policy for this server, to limit who can connect to the
|
||||
@@ -795,28 +827,44 @@ The following options are useful only for clients (that is, if
|
||||
operating as a relay, and it will never use the public key step if it
|
||||
doesn't yet know the onion key of the first hop. (Default: 1)
|
||||
|
||||
**TransPort** __PORT__|**auto**::
|
||||
If non-zero, enables transparent proxy support on __PORT__ (by convention,
|
||||
9040). Requires OS support for transparent proxies, such as BSDs' pf or
|
||||
**TransPort** \['address':]__port__|**auto** [_isolation flags_]::
|
||||
Open this port to listen for transparent proxy connections. Set this to
|
||||
0 if you don't want to allow transparent proxy connections. Set the port
|
||||
to "auto" to have Tor pick a port for you. This directive can be
|
||||
specified multiple times to bind to multiple addresses/ports. See
|
||||
SOCKSPort for an explanation of isolation flags. +
|
||||
+
|
||||
TransPort requires OS support for transparent proxies, such as BSDs' pf or
|
||||
Linux's IPTables. If you're planning to use Tor as a transparent proxy for
|
||||
a network, you'll want to examine and change VirtualAddrNetwork from the
|
||||
default setting. You'll also want to set the TransListenAddress option for
|
||||
the network you'd like to proxy. Set it to "auto" to have Tor pick a
|
||||
port for you. (Default: 0).
|
||||
the network you'd like to proxy. (Default: 0).
|
||||
|
||||
**TransListenAddress** __IP__[:__PORT__]::
|
||||
Bind to this address to listen for transparent proxy connections. (Default:
|
||||
127.0.0.1). This is useful for exporting a transparent proxy server to an
|
||||
entire network.
|
||||
entire network. (DEPRECATED: As of 0.2.3.x-alpha, you can
|
||||
now use multiple TransPort entries, and provide addresses for TransPort
|
||||
entries, so TransListenAddress no longer has a purpose. For backward
|
||||
compatibility, TransListenAddress is only allowed when TransPort is just
|
||||
a port number.)
|
||||
|
||||
**NATDPort** __PORT__|**auto**::
|
||||
Allow old versions of ipfw (as included in old versions of FreeBSD, etc.)
|
||||
to send connections through Tor using the NATD protocol. This option is
|
||||
only for people who cannot use TransPort. Set it to "auto" to have Tor
|
||||
pick a port for you. (Default: 0)
|
||||
**NATDPort** \['address':]__port__|**auto** [_isolation flags_]::
|
||||
Open this port to listen for connections from old versions of ipfw (as
|
||||
included in old versions of FreeBSD, etc) using the NATD protocol.
|
||||
Use 0 if you don't want to allow NATD connections. Set the port
|
||||
to "auto" to have Tor pick a port for you. This directive can be
|
||||
specified multiple times to bind to multiple addresses/ports. See
|
||||
SOCKSPort for an explanation of isolation flags. +
|
||||
+
|
||||
This option is only for people who cannot use TransPort. (Default: 0)
|
||||
|
||||
**NATDListenAddress** __IP__[:__PORT__]::
|
||||
Bind to this address to listen for NATD connections. (Default: 127.0.0.1).
|
||||
Bind to this address to listen for NATD connections. (DEPRECATED: As of
|
||||
0.2.3.x-alpha, you can now use multiple NATDPort entries, and provide
|
||||
addresses for NATDPort entries, so NATDListenAddress no longer has a
|
||||
purpose. For backward compatibility, NATDListenAddress is only allowed
|
||||
when NATDPort is just a port number.)
|
||||
|
||||
**AutomapHostsOnResolve** **0**|**1**::
|
||||
When this option is enabled, and we get a request to resolve an address
|
||||
@@ -829,13 +877,19 @@ The following options are useful only for clients (that is, if
|
||||
A comma-separated list of suffixes to use with **AutomapHostsOnResolve**.
|
||||
The "." suffix is equivalent to "all addresses." (Default: .exit,.onion).
|
||||
|
||||
**DNSPort** __PORT__|**auto**::
|
||||
If non-zero, Tor listens for UDP DNS requests on this port and resolves
|
||||
them anonymously. Set it to "auto" to have Tor pick a port for
|
||||
you. (Default: 0).
|
||||
**DNSPort** \['address':]__port__|**auto** [_isolation flags_]::
|
||||
If non-zero, open this port to listen for UDP DNS requests, and resolve
|
||||
them anonymously. Set the port to "auto" to have Tor pick a port for
|
||||
you. This directive can be specified multiple times to bind to multiple
|
||||
addresses/ports. See SOCKSPort for an explanation of isolation
|
||||
flags. (Default: 0).
|
||||
|
||||
**DNSListenAddress** __IP__[:__PORT__]::
|
||||
Bind to this address to listen for DNS connections. (Default: 127.0.0.1).
|
||||
Bind to this address to listen for DNS connections. (DEPRECATED: As of
|
||||
0.2.3.x-alpha, you can now use multiple DNSPort entries, and provide
|
||||
addresses for DNSPort entries, so DNSListenAddress no longer has a
|
||||
purpose. For backward compatibility, DNSListenAddress is only allowed
|
||||
when DNSPort is just a port number.)
|
||||
|
||||
**ClientDNSRejectInternalAddresses** **0**|**1**::
|
||||
If true, Tor does not believe any anonymously retrieved DNS answer that
|
||||
@@ -876,6 +930,16 @@ The following options are useful only for clients (that is, if
|
||||
that have the **AllowSingleHopExits** option turned on to build
|
||||
one-hop Tor connections. (Default: 0)
|
||||
|
||||
**OptimisticData** **0**|**1**|**auto**::
|
||||
When this option is set, and Tor is using an exit node that supports
|
||||
the feature, it will try optimistically to send data to the exit node
|
||||
without waiting for the exit node to report whether the connection
|
||||
succeeded. This can save a round-trip time for protocols like HTTP
|
||||
where the client talks first. If OptimisticData is set to **auto**,
|
||||
Tor will look at the UseOptimisticData parameter in the networkstatus.
|
||||
(Default: auto)
|
||||
|
||||
|
||||
SERVER OPTIONS
|
||||
--------------
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
|
||||
|
||||
EXTRA_DIST = common_sha1.i sha256.c
|
||||
EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
|
||||
|
||||
#CFLAGS = -Wall -Wpointer-arith -O2
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
all: libor.lib libor-crypto.lib libor-event.lib
|
||||
|
||||
CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include
|
||||
|
||||
LIBOR_OBJECTS = address.obj compat.obj container.obj di_ops.obj \
|
||||
log.obj memarea.obj mempool.obj procmon.obj util.obj \
|
||||
util_codedigest.obj
|
||||
|
||||
LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj
|
||||
|
||||
LIBOR_EVENT_OBJECTS = compat_libevent.obj
|
||||
|
||||
libor.lib: $(LIBOR_OBJECTS)
|
||||
lib $(LIBOR_OBJECTS) /out:libor.lib
|
||||
|
||||
libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS)
|
||||
lib $(LIBOR_CRYPTO_OBJECTS) /out:libor-crypto.lib
|
||||
|
||||
libor-event.lib: $(LIBOR_EVENT_OBJECTS)
|
||||
lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib
|
||||
@@ -958,8 +958,10 @@ fmt_addr(const tor_addr_t *addr)
|
||||
{
|
||||
static char buf[TOR_ADDR_BUF_LEN];
|
||||
if (!addr) return "<null>";
|
||||
tor_addr_to_str(buf, addr, sizeof(buf), 0);
|
||||
return buf;
|
||||
if (tor_addr_to_str(buf, addr, sizeof(buf), 0))
|
||||
return buf;
|
||||
else
|
||||
return "???";
|
||||
}
|
||||
|
||||
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
|
||||
|
||||
+1
-1
@@ -401,7 +401,7 @@ typedef int socklen_t;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
#define tor_socket_t intptr_t
|
||||
#define SOCKET_OK(s) ((s) != INVALID_SOCKET)
|
||||
#define SOCKET_OK(s) ((unsigned)(s) != INVALID_SOCKET)
|
||||
#else
|
||||
#define tor_socket_t int
|
||||
#define SOCKET_OK(s) ((s) >= 0)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#include <event2/event.h>
|
||||
#include <event2/thread.h>
|
||||
#else
|
||||
#include <event.h>
|
||||
#endif
|
||||
@@ -183,8 +184,10 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
|
||||
struct event_config *cfg = event_config_new();
|
||||
|
||||
#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
|
||||
if (! torcfg->disable_iocp)
|
||||
if (! torcfg->disable_iocp) {
|
||||
evthread_use_windows_threads();
|
||||
event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
|
||||
|
||||
@@ -43,11 +43,7 @@
|
||||
#define off64_t int64_t
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "..\..\contrib\zlib\zlib.h"
|
||||
#else
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
/** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
|
||||
* set to -1 if we haven't checked yet. */
|
||||
|
||||
@@ -111,6 +111,15 @@ typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#define HAVE_UINT32_T
|
||||
#endif
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX 0xffffu
|
||||
#endif
|
||||
#ifndef INT16_MAX
|
||||
#define INT16_MAX 0x7fff
|
||||
#endif
|
||||
#ifndef INT16_MIN
|
||||
#define INT16_MIN (-INT16_MAX-1)
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX 0xffffffffu
|
||||
#endif
|
||||
|
||||
@@ -273,6 +273,22 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
|
||||
|
||||
addr = tls ? tls->address : NULL;
|
||||
|
||||
/* Some errors are known-benign, meaning they are the fault of the other
|
||||
* side of the connection. The caller doesn't know this, so override the
|
||||
* priority for those cases. */
|
||||
switch (ERR_GET_REASON(err)) {
|
||||
case SSL_R_HTTP_REQUEST:
|
||||
case SSL_R_HTTPS_PROXY_REQUEST:
|
||||
case SSL_R_RECORD_LENGTH_MISMATCH:
|
||||
case SSL_R_RECORD_TOO_LARGE:
|
||||
case SSL_R_UNKNOWN_PROTOCOL:
|
||||
case SSL_R_UNSUPPORTED_PROTOCOL:
|
||||
severity = LOG_INFO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
msg = (const char*)ERR_reason_error_string(err);
|
||||
lib = (const char*)ERR_lib_error_string(err);
|
||||
func = (const char*)ERR_func_error_string(err);
|
||||
|
||||
+72
-3
@@ -14,6 +14,9 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "orconfig.h"
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#define UTIL_PRIVATE
|
||||
#include "util.h"
|
||||
#include "torlog.h"
|
||||
@@ -68,9 +71,6 @@
|
||||
#ifdef HAVE_SYS_FCNTL_H
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
@@ -412,6 +412,32 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
|
||||
return number;
|
||||
}
|
||||
|
||||
/** Return the number of bits set in <b>v</b>. */
|
||||
int
|
||||
n_bits_set_u8(uint8_t v)
|
||||
{
|
||||
static const int nybble_table[] = {
|
||||
0, /* 0000 */
|
||||
1, /* 0001 */
|
||||
1, /* 0010 */
|
||||
2, /* 0011 */
|
||||
1, /* 0100 */
|
||||
2, /* 0101 */
|
||||
2, /* 0110 */
|
||||
3, /* 0111 */
|
||||
1, /* 1000 */
|
||||
2, /* 1001 */
|
||||
2, /* 1010 */
|
||||
3, /* 1011 */
|
||||
2, /* 1100 */
|
||||
3, /* 1101 */
|
||||
3, /* 1110 */
|
||||
4, /* 1111 */
|
||||
};
|
||||
|
||||
return nybble_table[v & 15] + nybble_table[v>>4];
|
||||
}
|
||||
|
||||
/* =====
|
||||
* String manipulation
|
||||
* ===== */
|
||||
@@ -495,6 +521,23 @@ tor_strisnonupper(const char *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** As strcmp, except that either string may be NULL. The NULL string is
|
||||
* considered to be before any non-NULL string. */
|
||||
int
|
||||
strcmp_opt(const char *s1, const char *s2)
|
||||
{
|
||||
if (!s1) {
|
||||
if (!s2)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
} else if (!s2) {
|
||||
return 1;
|
||||
} else {
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
|
||||
* strcmp.
|
||||
*/
|
||||
@@ -1693,6 +1736,8 @@ check_private_dir(const char *dirname, cpd_check_t check,
|
||||
struct passwd *pw = NULL;
|
||||
uid_t running_uid;
|
||||
gid_t running_gid;
|
||||
#else
|
||||
(void)effective_user;
|
||||
#endif
|
||||
|
||||
tor_assert(dirname);
|
||||
@@ -2636,6 +2681,30 @@ tor_sscanf(const char *buf, const char *pattern, ...)
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>)
|
||||
* to <b>sl</b>. */
|
||||
void
|
||||
smartlist_asprintf_add(struct smartlist_t *sl, const char *pattern, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, pattern);
|
||||
smartlist_vasprintf_add(sl, pattern, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/** va_list-based backend of smartlist_asprintf_add. */
|
||||
void
|
||||
smartlist_vasprintf_add(struct smartlist_t *sl, const char *pattern,
|
||||
va_list args)
|
||||
{
|
||||
char *str = NULL;
|
||||
|
||||
tor_vasprintf(&str, pattern, args);
|
||||
tor_assert(str != NULL);
|
||||
|
||||
smartlist_add(sl, str);
|
||||
}
|
||||
|
||||
/** Return a new list containing the filenames in the directory <b>dirname</b>.
|
||||
* Return NULL on error or if <b>dirname</b> is not a directory.
|
||||
*/
|
||||
|
||||
@@ -160,6 +160,7 @@ uint64_t round_to_power_of_2(uint64_t u64);
|
||||
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
|
||||
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
|
||||
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
|
||||
int n_bits_set_u8(uint8_t v);
|
||||
|
||||
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b>
|
||||
* and positive <b>b</b>. Works on integer types only. Not defined if a+b can
|
||||
@@ -174,6 +175,7 @@ void tor_strlower(char *s) ATTR_NONNULL((1));
|
||||
void tor_strupper(char *s) ATTR_NONNULL((1));
|
||||
int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
||||
int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
||||
int strcmp_opt(const char *s1, const char *s2) ATTR_PURE;
|
||||
int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
|
||||
int strcmp_len(const char *s1, const char *s2, size_t len)
|
||||
ATTR_PURE ATTR_NONNULL((1,2));
|
||||
@@ -218,6 +220,11 @@ int tor_sscanf(const char *buf, const char *pattern, ...)
|
||||
#endif
|
||||
;
|
||||
|
||||
void smartlist_asprintf_add(struct smartlist_t *sl, const char *pattern, ...)
|
||||
CHECK_PRINTF(2, 3);
|
||||
void smartlist_vasprintf_add(struct smartlist_t *sl, const char *pattern,
|
||||
va_list args);
|
||||
|
||||
int hex_decode_digit(char c);
|
||||
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);
|
||||
|
||||
+3232
-2959
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -7,7 +7,7 @@ else
|
||||
tor_platform_source=
|
||||
endif
|
||||
|
||||
EXTRA_DIST=ntmain.c or_sha1.i
|
||||
EXTRA_DIST=ntmain.c or_sha1.i Makefile.nmake
|
||||
|
||||
if USE_EXTERNAL_EVDNS
|
||||
evdns_source=
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
all: tor.exe
|
||||
|
||||
CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common
|
||||
|
||||
LIBS = ..\..\..\build-alpha\lib\libevent.a \
|
||||
..\..\..\build-alpha\lib\libcrypto.a \
|
||||
..\..\..\build-alpha\lib\libssl.a \
|
||||
..\..\..\build-alpha\lib\libz.a \
|
||||
ws2_32.lib advapi32.lib shell32.lib
|
||||
|
||||
LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
|
||||
command.obj config.obj connection.obj connection_edge.obj \
|
||||
connection_or.obj control.obj cpuworker.obj directory.obj \
|
||||
dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj \
|
||||
hibernate.obj main.obj microdesc.obj networkstatus.obj \
|
||||
nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
|
||||
rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
|
||||
rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
|
||||
config_codedigest.obj ntmain.obj
|
||||
|
||||
libtor.lib: $(LIBTOR_OBJECTS)
|
||||
lib $(LIBTOR_OBJECTS) /out:libtor.lib
|
||||
|
||||
tor.exe: libtor.lib tor_main.obj
|
||||
$(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj
|
||||
|
||||
clean:
|
||||
del $(LIBTOR_OBJECTS) *.lib tor.exe
|
||||
+88
-22
@@ -557,6 +557,39 @@ buf_free(buf_t *buf)
|
||||
tor_free(buf);
|
||||
}
|
||||
|
||||
/** Return a new copy of <b>in_chunk</b> */
|
||||
static chunk_t *
|
||||
chunk_copy(const chunk_t *in_chunk)
|
||||
{
|
||||
chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen));
|
||||
newch->next = NULL;
|
||||
if (in_chunk->data) {
|
||||
off_t offset = in_chunk->data - in_chunk->mem;
|
||||
newch->data = newch->mem + offset;
|
||||
}
|
||||
return newch;
|
||||
}
|
||||
|
||||
/** Return a new copy of <b>buf</b> */
|
||||
buf_t *
|
||||
buf_copy(const buf_t *buf)
|
||||
{
|
||||
chunk_t *ch;
|
||||
buf_t *out = buf_new();
|
||||
out->default_chunk_size = buf->default_chunk_size;
|
||||
for (ch = buf->head; ch; ch = ch->next) {
|
||||
chunk_t *newch = chunk_copy(ch);
|
||||
if (out->tail) {
|
||||
out->tail->next = newch;
|
||||
out->tail = newch;
|
||||
} else {
|
||||
out->head = out->tail = newch;
|
||||
}
|
||||
}
|
||||
out->datalen = buf->datalen;
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
|
||||
* the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
|
||||
* than MAX_CHUNK_ALLOC. */
|
||||
@@ -1021,13 +1054,13 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
/** Try to read <b>n</b> bytes from <b>buf</b> at <b>pos</b> (which may be
|
||||
* NULL for the start of the buffer), copying the data only if necessary. Set
|
||||
* *<b>data</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
|
||||
* *<b>data_out</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
|
||||
* if we needed to malloc *<b>data</b> because the original bytes were
|
||||
* noncontiguous; 0 otherwise. Return the number of bytes actually available
|
||||
* at <b>data</b>.
|
||||
* at *<b>data_out</b>.
|
||||
*/
|
||||
static ssize_t
|
||||
inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
|
||||
inspect_evbuffer(struct evbuffer *buf, char **data_out, size_t n, int *free_out,
|
||||
struct evbuffer_ptr *pos)
|
||||
{
|
||||
int n_vecs, i;
|
||||
@@ -1042,25 +1075,15 @@ inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
|
||||
struct evbuffer_iovec v;
|
||||
i = evbuffer_peek(buf, n, pos, &v, 1);
|
||||
tor_assert(i == 1);
|
||||
*data = v.iov_base;
|
||||
*data_out = v.iov_base;
|
||||
*free_out = 0;
|
||||
return v.iov_len;
|
||||
} else {
|
||||
struct evbuffer_iovec *vecs =
|
||||
tor_malloc(sizeof(struct evbuffer_iovec)*n_vecs);
|
||||
size_t copied = 0;
|
||||
i = evbuffer_peek(buf, n, NULL, vecs, n_vecs);
|
||||
tor_assert(i == n_vecs);
|
||||
*data = tor_malloc(n);
|
||||
for (i=0; i < n_vecs; ++i) {
|
||||
size_t copy = n - copied;
|
||||
if (copy > vecs[i].iov_len)
|
||||
copy = vecs[i].iov_len;
|
||||
tor_assert(copied+copy <= n);
|
||||
memcpy(data+copied, vecs[i].iov_base, copy);
|
||||
copied += copy;
|
||||
}
|
||||
ev_ssize_t copied;
|
||||
*data_out = tor_malloc(n);
|
||||
*free_out = 1;
|
||||
copied = evbuffer_copyout(buf, *data_out, n);
|
||||
tor_assert(copied >= 0 && (size_t)copied == n);
|
||||
return copied;
|
||||
}
|
||||
}
|
||||
@@ -1499,8 +1522,14 @@ socks_request_free(socks_request_t *req)
|
||||
{
|
||||
if (!req)
|
||||
return;
|
||||
tor_free(req->username);
|
||||
tor_free(req->password);
|
||||
if (req->username) {
|
||||
memset(req->username, 0x10, req->usernamelen);
|
||||
tor_free(req->username);
|
||||
}
|
||||
if (req->password) {
|
||||
memset(req->password, 0x04, req->passwordlen);
|
||||
tor_free(req->password);
|
||||
}
|
||||
memset(req, 0xCC, sizeof(socks_request_t));
|
||||
tor_free(req);
|
||||
}
|
||||
@@ -1581,12 +1610,12 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
|
||||
*/
|
||||
struct evbuffer_iovec v;
|
||||
int i;
|
||||
want_length = evbuffer_get_contiguous_space(buf);
|
||||
n_drain = 0;
|
||||
i = evbuffer_peek(buf, want_length, NULL, &v, 1);
|
||||
i = evbuffer_peek(buf, -1, NULL, &v, 1);
|
||||
tor_assert(i == 1);
|
||||
data = v.iov_base;
|
||||
datalen = v.iov_len;
|
||||
want_length = 0;
|
||||
|
||||
res = parse_socks(data, datalen, req, log_sockstype,
|
||||
safe_socks, &n_drain, &want_length);
|
||||
@@ -2374,6 +2403,43 @@ write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
|
||||
int
|
||||
generic_buffer_set_to_copy(generic_buffer_t **output,
|
||||
const generic_buffer_t *input)
|
||||
{
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
struct evbuffer_ptr ptr;
|
||||
size_t remaining = evbuffer_get_length(input);
|
||||
if (*output) {
|
||||
evbuffer_drain(*output, evbuffer_get_length(*output));
|
||||
} else {
|
||||
if (!(*output = evbuffer_new()))
|
||||
return -1;
|
||||
}
|
||||
evbuffer_ptr_set((struct evbuffer*)input, &ptr, 0, EVBUFFER_PTR_SET);
|
||||
while (remaining) {
|
||||
struct evbuffer_iovec v[4];
|
||||
int n_used, i;
|
||||
n_used = evbuffer_peek((struct evbuffer*)input, -1, &ptr, v, 4);
|
||||
if (n_used < 0)
|
||||
return -1;
|
||||
for (i=0;i<n_used;++i) {
|
||||
evbuffer_add(*output, v[i].iov_base, v[i].iov_len);
|
||||
tor_assert(v[i].iov_len <= remaining);
|
||||
remaining -= v[i].iov_len;
|
||||
evbuffer_ptr_set((struct evbuffer*)input,
|
||||
&ptr, v[i].iov_len, EVBUFFER_PTR_ADD);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (*output)
|
||||
buf_free(*output);
|
||||
*output = buf_copy(input);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Log an error and exit if <b>buf</b> is corrupted.
|
||||
*/
|
||||
void
|
||||
|
||||
@@ -16,6 +16,7 @@ buf_t *buf_new(void);
|
||||
buf_t *buf_new_with_capacity(size_t size);
|
||||
void buf_free(buf_t *buf);
|
||||
void buf_clear(buf_t *buf);
|
||||
buf_t *buf_copy(const buf_t *buf);
|
||||
void buf_shrink(buf_t *buf);
|
||||
void buf_shrink_freelists(int free_all);
|
||||
void buf_dump_freelist_sizes(int severity);
|
||||
@@ -67,6 +68,24 @@ int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
|
||||
int done);
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
#define generic_buffer_new() evbuffer_new()
|
||||
#define generic_buffer_len(b) evbuffer_get_length((b))
|
||||
#define generic_buffer_add(b,dat,len) evbuffer_add((b),(dat),(len))
|
||||
#define generic_buffer_get(b,buf,buflen) evbuffer_remove((b),(buf),(buflen))
|
||||
#define generic_buffer_clear(b) evbuffer_drain((b), evbuffer_get_length((b)))
|
||||
#define generic_buffer_free(b) evbuffer_free((b))
|
||||
#else
|
||||
#define generic_buffer_new() buf_new()
|
||||
#define generic_buffer_len(b) buf_datalen((b))
|
||||
#define generic_buffer_add(b,dat,len) write_to_buf((dat),(len),(b))
|
||||
#define generic_buffer_get(b,buf,buflen) fetch_from_buf((buf),(buflen),(b))
|
||||
#define generic_buffer_clear(b) buf_clear((b))
|
||||
#define generic_buffer_free(b) buf_free((b))
|
||||
#endif
|
||||
int generic_buffer_set_to_copy(generic_buffer_t **output,
|
||||
const generic_buffer_t *input);
|
||||
|
||||
void assert_buf_ok(buf_t *buf);
|
||||
|
||||
#ifdef BUFFERS_PRIVATE
|
||||
|
||||
+12
-1
@@ -550,6 +550,16 @@ circuit_free(circuit_t *circ)
|
||||
|
||||
crypto_free_pk_env(ocirc->intro_key);
|
||||
rend_data_free(ocirc->rend_data);
|
||||
|
||||
tor_free(ocirc->dest_address);
|
||||
if (ocirc->socks_username) {
|
||||
memset(ocirc->socks_username, 0x12, ocirc->socks_username_len);
|
||||
tor_free(ocirc->socks_username);
|
||||
}
|
||||
if (ocirc->socks_password) {
|
||||
memset(ocirc->socks_password, 0x06, ocirc->socks_password_len);
|
||||
tor_free(ocirc->socks_password);
|
||||
}
|
||||
} else {
|
||||
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
|
||||
/* Remember cell statistics for this circuit before deallocating. */
|
||||
@@ -1001,7 +1011,8 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
||||
(!need_capacity || circ->build_state->need_capacity) &&
|
||||
(internal == circ->build_state->is_internal) &&
|
||||
circ->remaining_relay_early_cells &&
|
||||
!circ->build_state->onehop_tunnel) {
|
||||
!circ->build_state->onehop_tunnel &&
|
||||
!circ->isolation_values_set) {
|
||||
if (info) {
|
||||
/* need to make sure we don't duplicate hops */
|
||||
crypt_path_t *hop = circ->cpath;
|
||||
|
||||
+170
-22
@@ -18,6 +18,7 @@
|
||||
#include "connection_edge.h"
|
||||
#include "control.h"
|
||||
#include "nodelist.h"
|
||||
#include "networkstatus.h"
|
||||
#include "policies.h"
|
||||
#include "rendclient.h"
|
||||
#include "rendcommon.h"
|
||||
@@ -39,19 +40,19 @@ static void circuit_increment_failure_count(void);
|
||||
* Else return 0.
|
||||
*/
|
||||
static int
|
||||
circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
|
||||
circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
const edge_connection_t *conn,
|
||||
int must_be_open, uint8_t purpose,
|
||||
int need_uptime, int need_internal,
|
||||
time_t now)
|
||||
{
|
||||
const circuit_t *circ = TO_CIRCUIT(origin_circ);
|
||||
const node_t *exitnode;
|
||||
cpath_build_state_t *build_state;
|
||||
tor_assert(circ);
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->socks_request);
|
||||
|
||||
if (!CIRCUIT_IS_ORIGIN(circ))
|
||||
return 0; /* this circ doesn't start at us */
|
||||
if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
|
||||
return 0; /* ignore non-open circs */
|
||||
if (circ->marked_for_close)
|
||||
@@ -86,7 +87,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
|
||||
* circuit, it's the magical extra bob hop. so just check the nickname
|
||||
* of the one we meant to finish at.
|
||||
*/
|
||||
build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
|
||||
build_state = origin_circ->build_state;
|
||||
exitnode = build_state_get_exit_node(build_state);
|
||||
|
||||
if (need_uptime && !build_state->need_uptime)
|
||||
@@ -134,25 +135,37 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
|
||||
return 0;
|
||||
}
|
||||
} else { /* not general */
|
||||
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||
if ((conn->rend_data && !ocirc->rend_data) ||
|
||||
(!conn->rend_data && ocirc->rend_data) ||
|
||||
(conn->rend_data && ocirc->rend_data &&
|
||||
if ((conn->rend_data && !origin_circ->rend_data) ||
|
||||
(!conn->rend_data && origin_circ->rend_data) ||
|
||||
(conn->rend_data && origin_circ->rend_data &&
|
||||
rend_cmp_service_ids(conn->rend_data->onion_address,
|
||||
ocirc->rend_data->onion_address))) {
|
||||
origin_circ->rend_data->onion_address))) {
|
||||
/* this circ is not for this conn */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connection_edge_compatible_with_circuit(conn, origin_circ)) {
|
||||
/* conn needs to be isolated from other conns that have already used
|
||||
* origin_circ */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Return 1 if circuit <b>a</b> is better than circuit <b>b</b> for
|
||||
* <b>purpose</b>, and return 0 otherwise. Used by circuit_get_best.
|
||||
* <b>conn</b>, and return 0 otherwise. Used by circuit_get_best.
|
||||
*/
|
||||
static int
|
||||
circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
||||
circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
|
||||
const edge_connection_t *conn)
|
||||
{
|
||||
const circuit_t *a = TO_CIRCUIT(oa);
|
||||
const circuit_t *b = TO_CIRCUIT(ob);
|
||||
const uint8_t purpose = conn->_base.purpose;
|
||||
int a_bits, b_bits;
|
||||
|
||||
switch (purpose) {
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
/* if it's used but less dirty it's best;
|
||||
@@ -166,8 +179,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
||||
if (a->timestamp_dirty ||
|
||||
timercmp(&a->timestamp_created, &b->timestamp_created, >))
|
||||
return 1;
|
||||
if (CIRCUIT_IS_ORIGIN(b) &&
|
||||
TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
|
||||
if (ob->build_state->is_internal)
|
||||
/* XXX023 what the heck is this internal thing doing here. I
|
||||
* think we can get rid of it. circuit_is_acceptable() already
|
||||
* makes sure that is_internal is exactly what we need it to
|
||||
@@ -186,6 +198,29 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* XXXX023 Maybe this check should get a higher priority to avoid
|
||||
* using up circuits too rapidly. */
|
||||
|
||||
a_bits = connection_edge_update_circuit_isolation(conn,
|
||||
(origin_circuit_t*)oa, 1);
|
||||
b_bits = connection_edge_update_circuit_isolation(conn,
|
||||
(origin_circuit_t*)ob, 1);
|
||||
/* if x_bits < 0, then we have not used x for anything; better not to dirty
|
||||
* a connection if we can help it. */
|
||||
if (a_bits < 0) {
|
||||
return 0;
|
||||
} else if (b_bits < 0) {
|
||||
return 1;
|
||||
}
|
||||
a_bits &= ~ oa->isolation_flags_mixed;
|
||||
a_bits &= ~ ob->isolation_flags_mixed;
|
||||
if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) {
|
||||
/* The fewer new restrictions we need to make on a circuit for stream
|
||||
* isolation, the better. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -206,10 +241,12 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
|
||||
* closest introduce-purposed circuit that you can find.
|
||||
*/
|
||||
static origin_circuit_t *
|
||||
circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
|
||||
circuit_get_best(const edge_connection_t *conn,
|
||||
int must_be_open, uint8_t purpose,
|
||||
int need_uptime, int need_internal)
|
||||
{
|
||||
circuit_t *circ, *best=NULL;
|
||||
circuit_t *circ;
|
||||
origin_circuit_t *best=NULL;
|
||||
struct timeval now;
|
||||
int intro_going_on_but_too_old = 0;
|
||||
|
||||
@@ -222,7 +259,11 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
|
||||
tor_gettimeofday(&now);
|
||||
|
||||
for (circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
|
||||
origin_circuit_t *origin_circ;
|
||||
if (!CIRCUIT_IS_ORIGIN(circ))
|
||||
continue;
|
||||
origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
|
||||
need_uptime,need_internal,now.tv_sec))
|
||||
continue;
|
||||
|
||||
@@ -236,8 +277,8 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
|
||||
/* now this is an acceptable circ to hand back. but that doesn't
|
||||
* mean it's the *best* circ to hand back. try to decide.
|
||||
*/
|
||||
if (!best || circuit_is_better(circ,best,purpose))
|
||||
best = circ;
|
||||
if (!best || circuit_is_better(origin_circ,best,conn))
|
||||
best = origin_circ;
|
||||
}
|
||||
|
||||
if (!best && intro_going_on_but_too_old)
|
||||
@@ -245,7 +286,28 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
|
||||
"right now, but it has already taken quite a while. Starting "
|
||||
"one in parallel.");
|
||||
|
||||
return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
|
||||
return best;
|
||||
}
|
||||
|
||||
/** Return the number of not-yet-open general-purpose origin circuits. */
|
||||
static int
|
||||
count_pending_general_client_circuits(void)
|
||||
{
|
||||
const circuit_t *circ;
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (circ = global_circuitlist; circ; circ = circ->next) {
|
||||
if (circ->marked_for_close ||
|
||||
circ->state == CIRCUIT_STATE_OPEN ||
|
||||
circ->purpose != CIRCUIT_PURPOSE_C_GENERAL ||
|
||||
!CIRCUIT_IS_ORIGIN(circ))
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -677,6 +739,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
|
||||
tor_assert(conn);
|
||||
|
||||
conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
|
||||
conn->may_use_optimistic_data = 0;
|
||||
conn->on_circuit = NULL;
|
||||
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
@@ -937,6 +1000,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
|
||||
void
|
||||
circuit_has_opened(origin_circuit_t *circ)
|
||||
{
|
||||
int can_try_clearing_isolation = 0, tried_clearing_isolation = 0;
|
||||
control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0);
|
||||
|
||||
/* Remember that this circuit has finished building. Now if we start
|
||||
@@ -944,9 +1008,12 @@ circuit_has_opened(origin_circuit_t *circ)
|
||||
* to consider its build time. */
|
||||
circ->has_opened = 1;
|
||||
|
||||
again:
|
||||
|
||||
switch (TO_CIRCUIT(circ)->purpose) {
|
||||
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
|
||||
rend_client_rendcirc_has_opened(circ);
|
||||
can_try_clearing_isolation = 1;
|
||||
connection_ap_attach_pending();
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
@@ -955,6 +1022,7 @@ circuit_has_opened(origin_circuit_t *circ)
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
/* Tell any AP connections that have been waiting for a new
|
||||
* circuit that one is ready. */
|
||||
can_try_clearing_isolation = 1;
|
||||
connection_ap_attach_pending();
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
@@ -972,6 +1040,24 @@ circuit_has_opened(origin_circuit_t *circ)
|
||||
* This won't happen in normal operation, but might happen if the
|
||||
* controller did it. Just let it slide. */
|
||||
}
|
||||
|
||||
if (/* The circuit may have become non-open if it was cannibalized.*/
|
||||
circ->_base.state == CIRCUIT_STATE_OPEN &&
|
||||
/* Only if the purpose is clearable, and only if we haven't tried
|
||||
* to clear isolation yet, do we try. */
|
||||
can_try_clearing_isolation && !tried_clearing_isolation &&
|
||||
/* If !isolation_values_set, there is nothing to clear. */
|
||||
circ->isolation_values_set &&
|
||||
/* It's not legal to clear a circuit's isolation info if it's ever had
|
||||
* streams attached */
|
||||
!circ->isolation_any_streams_attached) {
|
||||
/* If we have any isolation information set on this circuit, and
|
||||
* we didn't manage to attach any streams to it, then we can
|
||||
* and should clear it and try again. */
|
||||
circuit_clear_isolation(circ);
|
||||
tried_clearing_isolation = 1;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
/** Called whenever a circuit could not be successfully built.
|
||||
@@ -1307,6 +1393,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
|
||||
if (!circ) {
|
||||
extend_info_t *extend_info=NULL;
|
||||
uint8_t new_circ_purpose;
|
||||
const int n_pending = count_pending_general_client_circuits();
|
||||
|
||||
if (n_pending >= options->MaxClientCircuitsPending) {
|
||||
static ratelim_t delay_limit = RATELIM_INIT(10*60);
|
||||
char *m;
|
||||
if ((m = rate_limit_log(&delay_limit, approx_time()))) {
|
||||
log_notice(LD_APP, "We'd like to launch a circuit to handle a "
|
||||
"connection, but we already have %d general-purpose client "
|
||||
"circuits pending. Waiting until some finish.",
|
||||
n_pending);
|
||||
tor_free(m);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
||||
/* need to pick an intro point */
|
||||
@@ -1417,12 +1517,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
|
||||
rend_client_rendcirc_has_opened(circ);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!circ)
|
||||
} /* endif (!circ) */
|
||||
if (circ) {
|
||||
/* Mark the circuit with the isolation fields for this connection.
|
||||
* When the circuit arrives, we'll clear these flags: this is
|
||||
* just some internal bookkeeping to make sure that we have
|
||||
* launched enough circuits.
|
||||
*/
|
||||
connection_edge_update_circuit_isolation(conn, circ, 0);
|
||||
} else {
|
||||
log_info(LD_APP,
|
||||
"No safe circuit (purpose %d) ready for edge "
|
||||
"connection; delaying.",
|
||||
desired_circuit_purpose);
|
||||
}
|
||||
*circp = circ;
|
||||
return 0;
|
||||
}
|
||||
@@ -1441,6 +1549,21 @@ cpath_is_on_circuit(origin_circuit_t *circ, crypt_path_t *crypt_path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return true iff client-side optimistic data is supported. */
|
||||
static int
|
||||
optimistic_data_enabled(void)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
if (options->OptimisticData < 0) {
|
||||
/* XXX023 consider having auto default to 1 rather than 0 before
|
||||
* the 0.2.3 branch goes stable. See bug 3617. -RD */
|
||||
const int32_t enabled =
|
||||
networkstatus_get_param(NULL, "UseOptimisticData", 0, 0, 1);
|
||||
return (int)enabled;
|
||||
}
|
||||
return options->OptimisticData;
|
||||
}
|
||||
|
||||
/** Attach the AP stream <b>apconn</b> to circ's linked list of
|
||||
* p_streams. Also set apconn's cpath_layer to <b>cpath</b>, or to the last
|
||||
* hop in circ's cpath if <b>cpath</b> is NULL.
|
||||
@@ -1449,6 +1572,8 @@ static void
|
||||
link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
|
||||
crypt_path_t *cpath)
|
||||
{
|
||||
const node_t *exitnode;
|
||||
|
||||
/* add it into the linked list of streams on this circuit */
|
||||
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
|
||||
circ->_base.n_circ_id);
|
||||
@@ -1468,6 +1593,28 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
|
||||
tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
|
||||
apconn->cpath_layer = circ->cpath->prev;
|
||||
}
|
||||
|
||||
circ->isolation_any_streams_attached = 1;
|
||||
connection_edge_update_circuit_isolation(apconn, circ, 0);
|
||||
|
||||
/* See if we can use optimistic data on this circuit */
|
||||
if (apconn->cpath_layer->extend_info &&
|
||||
(exitnode = node_get_by_id(
|
||||
apconn->cpath_layer->extend_info->identity_digest)) &&
|
||||
exitnode->rs) {
|
||||
/* Okay; we know what exit node this is. */
|
||||
if (optimistic_data_enabled() &&
|
||||
circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
|
||||
exitnode->rs->version_supports_optimistic_data)
|
||||
apconn->may_use_optimistic_data = 1;
|
||||
else
|
||||
apconn->may_use_optimistic_data = 0;
|
||||
log_info(LD_APP, "Looks like completed circuit to %s %s allow "
|
||||
"optimistic data for connection to %s",
|
||||
safe_str_client(node_describe(exitnode)),
|
||||
apconn->may_use_optimistic_data ? "does" : "doesn't",
|
||||
safe_str_client(apconn->socks_request->address));
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff <b>address</b> is matched by one of the entries in
|
||||
@@ -1495,7 +1642,8 @@ hostname_in_track_host_exits(const or_options_t *options, const char *address)
|
||||
* <b>conn</b>'s destination.
|
||||
*/
|
||||
static void
|
||||
consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
|
||||
consider_recording_trackhost(const edge_connection_t *conn,
|
||||
const origin_circuit_t *circ)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
char *new_address = NULL;
|
||||
|
||||
+438
-66
@@ -40,6 +40,9 @@
|
||||
|
||||
#include "procmon.h"
|
||||
|
||||
/* From main.c */
|
||||
extern int quiet_level;
|
||||
|
||||
/** Enumeration of types which option values can take */
|
||||
typedef enum config_type_t {
|
||||
CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
|
||||
@@ -240,7 +243,7 @@ static config_var_t _option_vars[] = {
|
||||
VAR("DirServer", LINELIST, DirServers, NULL),
|
||||
V(DisableAllSwap, BOOL, "0"),
|
||||
V(DisableIOCP, BOOL, "1"),
|
||||
V(DNSPort, PORT, "0"),
|
||||
V(DNSPort, LINELIST, NULL),
|
||||
V(DNSListenAddress, LINELIST, NULL),
|
||||
V(DownloadExtraInfo, BOOL, "0"),
|
||||
V(EnforceDistinctSubnets, BOOL, "1"),
|
||||
@@ -315,13 +318,14 @@ static config_var_t _option_vars[] = {
|
||||
VAR("MapAddress", LINELIST, AddressMap, NULL),
|
||||
V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"),
|
||||
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
|
||||
V(MaxClientCircuitsPending, UINT, "32"),
|
||||
V(MaxOnionsPending, UINT, "100"),
|
||||
OBSOLETE("MonthlyAccountingStart"),
|
||||
V(MyFamily, STRING, NULL),
|
||||
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
|
||||
VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
|
||||
V(NATDListenAddress, LINELIST, NULL),
|
||||
V(NATDPort, PORT, "0"),
|
||||
V(NATDPort, LINELIST, NULL),
|
||||
V(Nickname, STRING, NULL),
|
||||
V(WarnUnsafeSocks, BOOL, "1"),
|
||||
OBSOLETE("NoPublish"),
|
||||
@@ -336,6 +340,7 @@ static config_var_t _option_vars[] = {
|
||||
V(PerConnBWRate, MEMUNIT, "0"),
|
||||
V(PidFile, STRING, NULL),
|
||||
V(TestingTorNetwork, BOOL, "0"),
|
||||
V(OptimisticData, AUTOBOOL, "auto"),
|
||||
V(PortForwarding, BOOL, "0"),
|
||||
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
|
||||
V(PreferTunneledDirConns, BOOL, "1"),
|
||||
@@ -374,7 +379,7 @@ static config_var_t _option_vars[] = {
|
||||
V(ShutdownWaitLength, INTERVAL, "30 seconds"),
|
||||
V(SocksListenAddress, LINELIST, NULL),
|
||||
V(SocksPolicy, LINELIST, NULL),
|
||||
V(SocksPort, PORT, "9050"),
|
||||
V(SocksPort, LINELIST, NULL),
|
||||
V(SocksTimeout, INTERVAL, "2 minutes"),
|
||||
OBSOLETE("StatusFetchPeriod"),
|
||||
V(StrictNodes, BOOL, "0"),
|
||||
@@ -385,7 +390,7 @@ static config_var_t _option_vars[] = {
|
||||
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
|
||||
OBSOLETE("TrafficShaping"),
|
||||
V(TransListenAddress, LINELIST, NULL),
|
||||
V(TransPort, PORT, "0"),
|
||||
V(TransPort, LINELIST, NULL),
|
||||
V(TunnelDirConns, BOOL, "1"),
|
||||
V(UpdateBridgesFromAuthority, BOOL, "0"),
|
||||
V(UseBridges, BOOL, "0"),
|
||||
@@ -577,6 +582,9 @@ static int parse_client_transport_line(const char *line, int validate_only);
|
||||
static int parse_dir_server_line(const char *line,
|
||||
dirinfo_type_t required_type,
|
||||
int validate_only);
|
||||
static void port_cfg_free(port_cfg_t *port);
|
||||
static int parse_client_ports(const or_options_t *options, int validate_only,
|
||||
char **msg_out, int *n_ports_out);
|
||||
static int validate_data_directory(or_options_t *options);
|
||||
static int write_configuration_file(const char *fname,
|
||||
const or_options_t *options);
|
||||
@@ -646,6 +654,8 @@ static or_state_t *global_state = NULL;
|
||||
static config_line_t *global_cmdline_options = NULL;
|
||||
/** Contents of most recently read DirPortFrontPage file. */
|
||||
static char *global_dirfrontpagecontents = NULL;
|
||||
/** List of port_cfg_t for client-level (SOCKS, DNS, Trans, NATD) ports. */
|
||||
static smartlist_t *configured_client_ports = NULL;
|
||||
|
||||
/** Return the contents of our frontpage string, or NULL if not configured. */
|
||||
const char *
|
||||
@@ -686,6 +696,9 @@ get_options(void)
|
||||
int
|
||||
set_options(or_options_t *new_val, char **msg)
|
||||
{
|
||||
int i;
|
||||
smartlist_t *elements;
|
||||
config_line_t *line;
|
||||
or_options_t *old_options = global_options;
|
||||
global_options = new_val;
|
||||
/* Note that we pass the *old* options below, for comparison. It
|
||||
@@ -700,7 +713,34 @@ set_options(or_options_t *new_val, char **msg)
|
||||
"Acting on config options left us in a broken state. Dying.");
|
||||
exit(1);
|
||||
}
|
||||
/* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
|
||||
* just starting up then the old_options will be undefined. */
|
||||
if (old_options) {
|
||||
elements = smartlist_create();
|
||||
for (i=0; options_format.vars[i].name; ++i) {
|
||||
const config_var_t *var = &options_format.vars[i];
|
||||
const char *var_name = var->name;
|
||||
if (var->type == CONFIG_TYPE_LINELIST_S ||
|
||||
var->type == CONFIG_TYPE_OBSOLETE) {
|
||||
continue;
|
||||
}
|
||||
if (!option_is_same(&options_format, new_val, old_options, var_name)) {
|
||||
line = get_assigned_option(&options_format, new_val, var_name, 1);
|
||||
|
||||
if (line) {
|
||||
for (; line; line = line->next) {
|
||||
smartlist_add(elements, line->key);
|
||||
smartlist_add(elements, line->value);
|
||||
}
|
||||
} else {
|
||||
smartlist_add(elements, (char*)options_format.vars[i].name);
|
||||
smartlist_add(elements, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
control_event_conf_changed(elements);
|
||||
smartlist_free(elements);
|
||||
}
|
||||
config_free(&options_format, old_options);
|
||||
|
||||
return 0;
|
||||
@@ -758,6 +798,13 @@ config_free_all(void)
|
||||
config_free_lines(global_cmdline_options);
|
||||
global_cmdline_options = NULL;
|
||||
|
||||
if (configured_client_ports) {
|
||||
SMARTLIST_FOREACH(configured_client_ports,
|
||||
port_cfg_t *, p, tor_free(p));
|
||||
smartlist_free(configured_client_ports);
|
||||
configured_client_ports = NULL;
|
||||
}
|
||||
|
||||
tor_free(torrc_fname);
|
||||
tor_free(_version);
|
||||
tor_free(global_dirfrontpagecontents);
|
||||
@@ -1004,6 +1051,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
|
||||
#endif
|
||||
|
||||
if (running_tor) {
|
||||
int n_client_ports=0;
|
||||
/* We need to set the connection limit before we can open the listeners. */
|
||||
if (set_max_file_descriptors((unsigned)options->ConnLimit,
|
||||
&options->_ConnLimit) < 0) {
|
||||
@@ -1019,6 +1067,10 @@ options_act_reversible(const or_options_t *old_options, char **msg)
|
||||
libevent_initialized = 1;
|
||||
}
|
||||
|
||||
/* Adjust the client port configuration so we can launch listeners. */
|
||||
if (parse_client_ports(options, 0, msg, &n_client_ports))
|
||||
return -1;
|
||||
|
||||
/* Launch the listeners. (We do this before we setuid, so we can bind to
|
||||
* ports under 1024.) We don't want to rebind if we're hibernating. */
|
||||
if (!we_are_hibernating()) {
|
||||
@@ -1068,6 +1120,9 @@ options_act_reversible(const or_options_t *old_options, char **msg)
|
||||
/* No need to roll back, since you can't change the value. */
|
||||
}
|
||||
|
||||
/* Write control ports to disk as appropriate */
|
||||
control_ports_write_to_file();
|
||||
|
||||
if (directory_caches_v2_dir_info(options)) {
|
||||
size_t len = strlen(options->DataDirectory)+32;
|
||||
char *fn = tor_malloc(len);
|
||||
@@ -3027,6 +3082,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
int i;
|
||||
config_line_t *cl;
|
||||
const char *uname = get_uname();
|
||||
int n_client_ports=0;
|
||||
#define REJECT(arg) \
|
||||
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
|
||||
#define COMPLAIN(arg) STMT_BEGIN log(LOG_WARN, LD_CONFIG, arg); STMT_END
|
||||
@@ -3050,57 +3106,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
if (options->DirPort == 0 && options->DirListenAddress != NULL)
|
||||
REJECT("DirPort must be defined if DirListenAddress is defined.");
|
||||
|
||||
if (options->DNSPort == 0 && options->DNSListenAddress != NULL)
|
||||
REJECT("DNSPort must be defined if DNSListenAddress is defined.");
|
||||
|
||||
if (options->ControlPort == 0 && options->ControlListenAddress != NULL)
|
||||
REJECT("ControlPort must be defined if ControlListenAddress is defined.");
|
||||
|
||||
if (options->TransPort == 0 && options->TransListenAddress != NULL)
|
||||
REJECT("TransPort must be defined if TransListenAddress is defined.");
|
||||
|
||||
if (options->NATDPort == 0 && options->NATDListenAddress != NULL)
|
||||
REJECT("NATDPort must be defined if NATDListenAddress is defined.");
|
||||
|
||||
/* Don't gripe about SocksPort 0 with SocksListenAddress set; a standard
|
||||
* configuration does this. */
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
int is_socks = i==0;
|
||||
int is_trans = i==1;
|
||||
config_line_t *line, *opt, *old;
|
||||
const char *tp;
|
||||
if (is_socks) {
|
||||
opt = options->SocksListenAddress;
|
||||
old = old_options ? old_options->SocksListenAddress : NULL;
|
||||
tp = "SOCKS proxy";
|
||||
} else if (is_trans) {
|
||||
opt = options->TransListenAddress;
|
||||
old = old_options ? old_options->TransListenAddress : NULL;
|
||||
tp = "transparent proxy";
|
||||
} else {
|
||||
opt = options->NATDListenAddress;
|
||||
old = old_options ? old_options->NATDListenAddress : NULL;
|
||||
tp = "natd proxy";
|
||||
}
|
||||
|
||||
for (line = opt; line; line = line->next) {
|
||||
char *address = NULL;
|
||||
uint16_t port;
|
||||
uint32_t addr;
|
||||
if (parse_addr_port(LOG_WARN, line->value, &address, &addr, &port)<0)
|
||||
continue; /* We'll warn about this later. */
|
||||
if (!is_internal_IP(addr, 1) &&
|
||||
(!old_options || !config_lines_eq(old, opt))) {
|
||||
log_warn(LD_CONFIG,
|
||||
"You specified a public address '%s' for a %s. Other "
|
||||
"people on the Internet might find your computer and use it as "
|
||||
"an open %s. Please don't allow this unless you have "
|
||||
"a good reason.", address, tp, tp);
|
||||
}
|
||||
tor_free(address);
|
||||
}
|
||||
}
|
||||
if (parse_client_ports(options, 1, msg, &n_client_ports) < 0)
|
||||
return -1;
|
||||
|
||||
if (validate_data_directory(options)<0)
|
||||
REJECT("Invalid DataDirectory");
|
||||
@@ -3124,8 +3131,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
"misconfigured or something else goes wrong.");
|
||||
|
||||
/* Special case on first boot if no Log options are given. */
|
||||
if (!options->Logs && !options->RunAsDaemon && !from_setconf)
|
||||
config_line_append(&options->Logs, "Log", "notice stdout");
|
||||
if (!options->Logs && !options->RunAsDaemon && !from_setconf) {
|
||||
if (quiet_level == 0)
|
||||
config_line_append(&options->Logs, "Log", "notice stdout");
|
||||
else if (quiet_level == 1)
|
||||
config_line_append(&options->Logs, "Log", "warn stdout");
|
||||
}
|
||||
|
||||
if (options_init_logs(options, 1)<0) /* Validate the log(s) */
|
||||
REJECT("Failed to validate Log options. See logs for details.");
|
||||
@@ -3142,9 +3153,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
|
||||
#endif
|
||||
|
||||
if (options->SocksPort == 0 && options->TransPort == 0 &&
|
||||
options->NATDPort == 0 && options->ORPort == 0 &&
|
||||
options->DNSPort == 0 && !options->RendConfigLines)
|
||||
if (n_client_ports == 0 && options->ORPort == 0 && !options->RendConfigLines)
|
||||
log(LOG_WARN, LD_CONFIG,
|
||||
"SocksPort, TransPort, NATDPort, DNSPort, and ORPort are all "
|
||||
"undefined, and there aren't any hidden services configured. "
|
||||
@@ -3253,6 +3262,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (options->MaxClientCircuitsPending <= 0 ||
|
||||
options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) {
|
||||
tor_asprintf(msg,
|
||||
"MaxClientCircuitsPending must be between 1 and %d, but "
|
||||
"was set to %d", MAX_MAX_CLIENT_CIRCUITS_PENDING,
|
||||
options->MaxClientCircuitsPending);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (validate_ports_csv(options->FirewallPorts, "FirewallPorts", msg) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -3892,12 +3910,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
|
||||
static int
|
||||
opt_streq(const char *s1, const char *s2)
|
||||
{
|
||||
if (!s1 && !s2)
|
||||
return 1;
|
||||
else if (s1 && s2 && !strcmp(s1,s2))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return 0 == strcmp_opt(s1, s2);
|
||||
}
|
||||
|
||||
/** Check if any of the previous options have changed but aren't allowed to. */
|
||||
@@ -4885,6 +4898,365 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Free all storage held in <b>port</b> */
|
||||
static void
|
||||
port_cfg_free(port_cfg_t *port)
|
||||
{
|
||||
tor_free(port);
|
||||
}
|
||||
|
||||
/** Warn for every port in <b>ports</b> that is not on a loopback address. */
|
||||
static void
|
||||
warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname)
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
|
||||
if (!tor_addr_is_loopback(&port->addr)) {
|
||||
log_warn(LD_CONFIG, "You specified a public address for %sPort. "
|
||||
"Other people on the Internet might find your computer and "
|
||||
"use it as an open proxy. Please don't allow this unless you "
|
||||
"have a good reason.", portname);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(port);
|
||||
}
|
||||
|
||||
#define CL_PORT_NO_OPTIONS (1u<<0)
|
||||
#define CL_PORT_WARN_NONLOCAL (1u<<1)
|
||||
#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2)
|
||||
|
||||
/**
|
||||
* Parse port configuration for a single client port type.
|
||||
*
|
||||
* Read entries of the "FooPort" type from the list <b>ports</b>, and
|
||||
* entries of the "FooListenAddress" type from the list
|
||||
* <b>listenaddrs</b>. Two syntaxes are supported: a legacy syntax
|
||||
* where FooPort is at most a single entry containing a port number and
|
||||
* where FooListenAddress has any number of address:port combinations;
|
||||
* and a new syntax where there are no FooListenAddress entries and
|
||||
* where FooPort can have any number of entries of the format
|
||||
* "[Address:][Port] IsolationOptions".
|
||||
*
|
||||
* In log messages, describe the port type as <b>portname</b>.
|
||||
*
|
||||
* If no address is specified, default to <b>defaultaddr</b>. If no
|
||||
* FooPort is given, default to defaultport (if 0, there is no default).
|
||||
*
|
||||
* If CL_PORT_NO_OPTIONS is set in <b>flags</b>, do not allow stream
|
||||
* isolation options in the FooPort entries.
|
||||
*
|
||||
* If CL_PORT_WARN_NONLOCAL is set in <b>flags</b>, warn if any of the
|
||||
* ports are not on a local address.
|
||||
*
|
||||
* Unless CL_PORT_ALLOW_EXTRA_LISTENADDR is set in <b>flags</b>, warn
|
||||
* if FooListenAddress is set but FooPort is 0.
|
||||
*
|
||||
* On success, if <b>out</b> is given, add a new port_cfg_t entry to
|
||||
* <b>out</b> for every port that the client should listen on. Return 0
|
||||
* on success, -1 on failure.
|
||||
*/
|
||||
static int
|
||||
parse_client_port_config(smartlist_t *out,
|
||||
const config_line_t *ports,
|
||||
const config_line_t *listenaddrs,
|
||||
const char *portname,
|
||||
int listener_type,
|
||||
const char *defaultaddr,
|
||||
int defaultport,
|
||||
unsigned flags)
|
||||
{
|
||||
smartlist_t *elts;
|
||||
int retval = -1;
|
||||
const unsigned allow_client_options = !(flags & CL_PORT_NO_OPTIONS);
|
||||
const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL;
|
||||
const unsigned allow_spurious_listenaddr =
|
||||
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
|
||||
|
||||
/* FooListenAddress is deprecated; let's make it work like it used to work,
|
||||
* though. */
|
||||
if (listenaddrs) {
|
||||
int mainport = defaultport;
|
||||
|
||||
if (ports && ports->next) {
|
||||
log_warn(LD_CONFIG, "%sListenAddress can't be used when there are "
|
||||
"multiple %sPort lines", portname, portname);
|
||||
return -1;
|
||||
} else if (ports) {
|
||||
if (!strcmp(ports->value, "auto")) {
|
||||
mainport = CFG_AUTO_PORT;
|
||||
} else {
|
||||
int ok;
|
||||
mainport = (int)tor_parse_long(ports->value, 10, 0, 65535, &ok, NULL);
|
||||
if (!ok) {
|
||||
log_warn(LD_CONFIG, "%sListenAddress can only be used with a single "
|
||||
"%sPort with value \"auto\" or 1-65535.", portname, portname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mainport == 0) {
|
||||
if (allow_spurious_listenaddr)
|
||||
return 1;
|
||||
log_warn(LD_CONFIG, "%sPort must be defined if %sListenAddress is used",
|
||||
portname, portname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (; listenaddrs; listenaddrs = listenaddrs->next) {
|
||||
tor_addr_t addr;
|
||||
uint16_t port = 0;
|
||||
if (tor_addr_port_parse(listenaddrs->value, &addr, &port) < 0) {
|
||||
log_warn(LD_CONFIG, "Unable to parse %sListenAddress '%s'",
|
||||
portname, listenaddrs->value);
|
||||
return -1;
|
||||
}
|
||||
if (out) {
|
||||
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
cfg->type = listener_type;
|
||||
cfg->port = port ? port : defaultport;
|
||||
tor_addr_copy(&cfg->addr, &addr);
|
||||
cfg->session_group = SESSION_GROUP_UNSET;
|
||||
cfg->isolation_flags = ISO_DEFAULT;
|
||||
smartlist_add(out, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
if (warn_nonlocal && out)
|
||||
warn_nonlocal_client_ports(out, portname);
|
||||
return 0;
|
||||
} /* end if (listenaddrs) */
|
||||
|
||||
/* No ListenAddress lines. If there's no FooPort, then maybe make a default
|
||||
* one. */
|
||||
if (! ports) {
|
||||
if (defaultport && out) {
|
||||
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
cfg->type = listener_type;
|
||||
cfg->port = defaultport;
|
||||
tor_addr_from_str(&cfg->addr, defaultaddr);
|
||||
cfg->session_group = SESSION_GROUP_UNSET;
|
||||
cfg->isolation_flags = ISO_DEFAULT;
|
||||
smartlist_add(out, cfg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* At last we can actually parse the FooPort lines. The syntax is:
|
||||
* [Addr:](Port|auto) [Options].*/
|
||||
elts = smartlist_create();
|
||||
|
||||
for (; ports; ports = ports->next) {
|
||||
tor_addr_t addr;
|
||||
int port;
|
||||
int sessiongroup = SESSION_GROUP_UNSET;
|
||||
unsigned isolation = ISO_DEFAULT;
|
||||
|
||||
char *addrport;
|
||||
uint16_t ptmp=0;
|
||||
int ok;
|
||||
|
||||
smartlist_split_string(elts, ports->value, NULL,
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
if (smartlist_len(elts) == 0) {
|
||||
log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!allow_client_options && smartlist_len(elts) > 1) {
|
||||
log_warn(LD_CONFIG, "Too many options on %sPort line", portname);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Now parse the addr/port value */
|
||||
addrport = smartlist_get(elts, 0);
|
||||
if (!strcmp(addrport, "auto")) {
|
||||
port = CFG_AUTO_PORT;
|
||||
tor_addr_from_str(&addr, defaultaddr);
|
||||
} else if (!strcasecmpend(addrport, ":auto")) {
|
||||
char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
|
||||
port = CFG_AUTO_PORT;
|
||||
if (tor_addr_port_parse(addrtmp, &addr, &ptmp)<0 || ptmp) {
|
||||
log_warn(LD_CONFIG, "Invalid address '%s' for %sPort",
|
||||
escaped(addrport), portname);
|
||||
tor_free(addrtmp);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
/* Try parsing integer port before address, because, who knows?
|
||||
"9050" might be a valid address. */
|
||||
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
|
||||
if (ok) {
|
||||
tor_addr_from_str(&addr, defaultaddr);
|
||||
} else if (tor_addr_port_parse(addrport, &addr, &ptmp) == 0) {
|
||||
if (ptmp == 0) {
|
||||
log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
|
||||
goto err;
|
||||
}
|
||||
port = ptmp;
|
||||
} else {
|
||||
log_warn(LD_CONFIG, "Couldn't parse address '%s' for %sPort",
|
||||
escaped(addrport), portname);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now parse the rest of the options, if any. */
|
||||
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
|
||||
int no = 0, isoflag = 0;
|
||||
const char *elt_orig = elt;
|
||||
if (elt_sl_idx == 0)
|
||||
continue; /* Skip addr:port */
|
||||
if (!strcasecmpstart(elt, "SessionGroup=")) {
|
||||
int group = (int)tor_parse_long(elt+strlen("SessionGroup="),
|
||||
10, 0, INT_MAX, &ok, NULL);
|
||||
if (!ok) {
|
||||
log_warn(LD_CONFIG, "Invalid %sPort option '%s'",
|
||||
portname, escaped(elt));
|
||||
goto err;
|
||||
}
|
||||
if (sessiongroup >= 0) {
|
||||
log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort",
|
||||
portname);
|
||||
goto err;
|
||||
}
|
||||
sessiongroup = group;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcasecmpstart(elt, "No")) {
|
||||
no = 1;
|
||||
elt += 2;
|
||||
}
|
||||
if (!strcasecmpend(elt, "s"))
|
||||
elt[strlen(elt)-1] = '\0'; /* kill plurals. */
|
||||
|
||||
if (!strcasecmp(elt, "IsolateDestPort")) {
|
||||
isoflag = ISO_DESTPORT;
|
||||
} else if (!strcasecmp(elt, "IsolateDestAddr")) {
|
||||
isoflag = ISO_DESTADDR;
|
||||
} else if (!strcasecmp(elt, "IsolateSOCKSAuth")) {
|
||||
isoflag = ISO_SOCKSAUTH;
|
||||
} else if (!strcasecmp(elt, "IsolateClientProtocol")) {
|
||||
isoflag = ISO_CLIENTPROTO;
|
||||
} else if (!strcasecmp(elt, "IsolateClientAddr")) {
|
||||
isoflag = ISO_CLIENTADDR;
|
||||
} else {
|
||||
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
|
||||
portname, escaped(elt_orig));
|
||||
}
|
||||
|
||||
if (no) {
|
||||
isolation &= ~isoflag;
|
||||
} else {
|
||||
isolation |= isoflag;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(elt);
|
||||
|
||||
if (out && port) {
|
||||
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
cfg->type = listener_type;
|
||||
cfg->port = port;
|
||||
tor_addr_copy(&cfg->addr, &addr);
|
||||
cfg->session_group = sessiongroup;
|
||||
cfg->isolation_flags = isolation;
|
||||
smartlist_add(out, cfg);
|
||||
}
|
||||
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
|
||||
smartlist_clear(elts);
|
||||
}
|
||||
|
||||
if (warn_nonlocal && out)
|
||||
warn_nonlocal_client_ports(out, portname);
|
||||
|
||||
retval = 0;
|
||||
err:
|
||||
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
|
||||
smartlist_free(elts);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Parse all client port types (Socks, DNS, Trans, NATD) from
|
||||
* <b>options</b>. On success, set *<b>n_ports_out</b> to the number of
|
||||
* ports that are listed and return 0. On failure, set *<b>msg</b> to a
|
||||
* description of the problem and return -1.
|
||||
*
|
||||
* If <b>validate_only</b> is false, set configured_client_ports to the
|
||||
* new list of ports parsed from <b>options</b>.
|
||||
**/
|
||||
static int
|
||||
parse_client_ports(const or_options_t *options, int validate_only,
|
||||
char **msg, int *n_ports_out)
|
||||
{
|
||||
smartlist_t *ports;
|
||||
int retval = -1;
|
||||
|
||||
ports = smartlist_create();
|
||||
|
||||
*n_ports_out = 0;
|
||||
|
||||
if (parse_client_port_config(ports,
|
||||
options->SocksPort, options->SocksListenAddress,
|
||||
"Socks", CONN_TYPE_AP_LISTENER,
|
||||
"127.0.0.1", 9050,
|
||||
CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR) < 0) {
|
||||
*msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration");
|
||||
goto err;
|
||||
}
|
||||
if (parse_client_port_config(ports,
|
||||
options->DNSPort, options->DNSListenAddress,
|
||||
"DNS", CONN_TYPE_AP_DNS_LISTENER,
|
||||
"127.0.0.1", 0,
|
||||
CL_PORT_WARN_NONLOCAL) < 0) {
|
||||
*msg = tor_strdup("Invalid DNSPort/DNSListenAddress configuration");
|
||||
goto err;
|
||||
}
|
||||
if (parse_client_port_config(ports,
|
||||
options->TransPort, options->TransListenAddress,
|
||||
"Trans", CONN_TYPE_AP_TRANS_LISTENER,
|
||||
"127.0.0.1", 0,
|
||||
CL_PORT_WARN_NONLOCAL) < 0) {
|
||||
*msg = tor_strdup("Invalid TransPort/TransListenAddress configuration");
|
||||
goto err;
|
||||
}
|
||||
if (parse_client_port_config(ports,
|
||||
options->NATDPort, options->NATDListenAddress,
|
||||
"NATD", CONN_TYPE_AP_NATD_LISTENER,
|
||||
"127.0.0.1", 0,
|
||||
CL_PORT_WARN_NONLOCAL) < 0) {
|
||||
*msg = tor_strdup("Invalid NatdPort/NatdListenAddress configuration");
|
||||
goto err;
|
||||
}
|
||||
|
||||
*n_ports_out = smartlist_len(ports);
|
||||
|
||||
if (!validate_only) {
|
||||
if (configured_client_ports) {
|
||||
SMARTLIST_FOREACH(configured_client_ports,
|
||||
port_cfg_t *, p, port_cfg_free(p));
|
||||
smartlist_free(configured_client_ports);
|
||||
}
|
||||
configured_client_ports = ports;
|
||||
ports = NULL; /* prevent free below. */
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
err:
|
||||
if (ports) {
|
||||
SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
|
||||
smartlist_free(ports);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Return a list of port_cfg_t for client ports parsed from the
|
||||
* options. */
|
||||
const smartlist_t *
|
||||
get_configured_client_ports(void)
|
||||
{
|
||||
if (!configured_client_ports)
|
||||
configured_client_ports = smartlist_create();
|
||||
return configured_client_ports;
|
||||
}
|
||||
|
||||
/** Adjust the value of options->DataDirectory, or fill it in if it's
|
||||
* absent. Return 0 on success, -1 on failure. */
|
||||
static int
|
||||
|
||||
@@ -64,6 +64,8 @@ or_state_t *get_or_state(void);
|
||||
int did_last_state_file_write_fail(void);
|
||||
int or_state_save(time_t now);
|
||||
|
||||
const smartlist_t *get_configured_client_ports(void);
|
||||
|
||||
int options_need_geoip_info(const or_options_t *options,
|
||||
const char **reason_out);
|
||||
int getinfo_helper_config(control_connection_t *conn,
|
||||
|
||||
+315
-285
@@ -43,11 +43,12 @@
|
||||
static connection_t *connection_create_listener(
|
||||
const struct sockaddr *listensockaddr,
|
||||
socklen_t listensocklen, int type,
|
||||
char* address);
|
||||
const char *address,
|
||||
const port_cfg_t *portcfg);
|
||||
static void connection_init(time_t now, connection_t *conn, int type,
|
||||
int socket_family);
|
||||
static int connection_init_accepted_conn(connection_t *conn,
|
||||
uint8_t listener_type);
|
||||
const listener_connection_t *listener);
|
||||
static int connection_handle_listener_read(connection_t *conn, int new_type);
|
||||
#ifndef USE_BUFFEREVENTS
|
||||
static int connection_bucket_should_increase(int bucket,
|
||||
@@ -76,6 +77,15 @@ static uint32_t last_interface_ip = 0;
|
||||
* Used to detect IP address changes. */
|
||||
static smartlist_t *outgoing_addrs = NULL;
|
||||
|
||||
#define CASE_ANY_LISTENER_TYPE \
|
||||
case CONN_TYPE_OR_LISTENER: \
|
||||
case CONN_TYPE_AP_LISTENER: \
|
||||
case CONN_TYPE_DIR_LISTENER: \
|
||||
case CONN_TYPE_CONTROL_LISTENER: \
|
||||
case CONN_TYPE_AP_TRANS_LISTENER: \
|
||||
case CONN_TYPE_AP_NATD_LISTENER: \
|
||||
case CONN_TYPE_AP_DNS_LISTENER
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/**
|
||||
@@ -116,13 +126,7 @@ conn_state_to_string(int type, int state)
|
||||
{
|
||||
static char buf[96];
|
||||
switch (type) {
|
||||
case CONN_TYPE_OR_LISTENER:
|
||||
case CONN_TYPE_AP_LISTENER:
|
||||
case CONN_TYPE_AP_TRANS_LISTENER:
|
||||
case CONN_TYPE_AP_NATD_LISTENER:
|
||||
case CONN_TYPE_AP_DNS_LISTENER:
|
||||
case CONN_TYPE_DIR_LISTENER:
|
||||
case CONN_TYPE_CONTROL_LISTENER:
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
if (state == LISTENER_STATE_READY)
|
||||
return "ready";
|
||||
break;
|
||||
@@ -265,6 +269,17 @@ control_connection_new(int socket_family)
|
||||
return control_conn;
|
||||
}
|
||||
|
||||
/** Allocate and return a new listener_connection_t, initialized as by
|
||||
* connection_init(). */
|
||||
listener_connection_t *
|
||||
listener_connection_new(int type, int socket_family)
|
||||
{
|
||||
listener_connection_t *listener_conn =
|
||||
tor_malloc_zero(sizeof(listener_connection_t));
|
||||
connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family);
|
||||
return listener_conn;
|
||||
}
|
||||
|
||||
/** Allocate, initialize, and return a new connection_t subtype of <b>type</b>
|
||||
* to make or receive connections of address family <b>socket_family</b>. The
|
||||
* type should be one of the CONN_TYPE_* constants. */
|
||||
@@ -285,6 +300,9 @@ connection_new(int type, int socket_family)
|
||||
case CONN_TYPE_CONTROL:
|
||||
return TO_CONN(control_connection_new(socket_family));
|
||||
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
return TO_CONN(listener_connection_new(type, socket_family));
|
||||
|
||||
default: {
|
||||
connection_t *conn = tor_malloc_zero(sizeof(connection_t));
|
||||
connection_init(time(NULL), conn, type, socket_family);
|
||||
@@ -325,6 +343,9 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
|
||||
case CONN_TYPE_CONTROL:
|
||||
conn->magic = CONTROL_CONNECTION_MAGIC;
|
||||
break;
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
conn->magic = LISTENER_CONNECTION_MAGIC;
|
||||
break;
|
||||
default:
|
||||
conn->magic = BASE_CONNECTION_MAGIC;
|
||||
break;
|
||||
@@ -396,6 +417,11 @@ _connection_free(connection_t *conn)
|
||||
mem = TO_CONTROL_CONN(conn);
|
||||
memlen = sizeof(control_connection_t);
|
||||
break;
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC);
|
||||
mem = TO_LISTENER_CONN(conn);
|
||||
memlen = sizeof(listener_connection_t);
|
||||
break;
|
||||
default:
|
||||
tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
|
||||
mem = conn;
|
||||
@@ -442,9 +468,15 @@ _connection_free(connection_t *conn)
|
||||
if (CONN_IS_EDGE(conn)) {
|
||||
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
|
||||
tor_free(edge_conn->chosen_exit_name);
|
||||
tor_free(edge_conn->original_dest_address);
|
||||
if (edge_conn->socks_request)
|
||||
socks_request_free(edge_conn->socks_request);
|
||||
|
||||
if (edge_conn->pending_optimistic_data) {
|
||||
generic_buffer_free(edge_conn->pending_optimistic_data);
|
||||
}
|
||||
if (edge_conn->sending_optimistic_data) {
|
||||
generic_buffer_free(edge_conn->sending_optimistic_data);
|
||||
}
|
||||
rend_data_free(edge_conn->rend_data);
|
||||
}
|
||||
if (conn->type == CONN_TYPE_CONTROL) {
|
||||
@@ -529,41 +561,6 @@ connection_free(connection_t *conn)
|
||||
_connection_free(conn);
|
||||
}
|
||||
|
||||
/** Call _connection_free() on every connection in our array, and release all
|
||||
* storage held by connection.c. This is used by cpuworkers and dnsworkers
|
||||
* when they fork, so they don't keep resources held open (especially
|
||||
* sockets).
|
||||
*
|
||||
* Don't do the checks in connection_free(), because they will
|
||||
* fail.
|
||||
*/
|
||||
void
|
||||
connection_free_all(void)
|
||||
{
|
||||
smartlist_t *conns = get_connection_array();
|
||||
|
||||
/* We don't want to log any messages to controllers. */
|
||||
SMARTLIST_FOREACH(conns, connection_t *, conn,
|
||||
if (conn->type == CONN_TYPE_CONTROL)
|
||||
TO_CONTROL_CONN(conn)->event_mask = 0);
|
||||
|
||||
control_update_global_event_mask();
|
||||
|
||||
/* Unlink everything from the identity map. */
|
||||
connection_or_clear_identity_map();
|
||||
|
||||
/* Clear out our list of broken connections */
|
||||
clear_broken_connection_map(0);
|
||||
|
||||
SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
|
||||
|
||||
if (outgoing_addrs) {
|
||||
SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
|
||||
smartlist_free(outgoing_addrs);
|
||||
outgoing_addrs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we're about to finally unlink and free a connection:
|
||||
* perform necessary accounting and cleanup
|
||||
@@ -701,48 +698,6 @@ connection_expire_held_open(void)
|
||||
});
|
||||
}
|
||||
|
||||
/** Create an AF_INET listenaddr struct.
|
||||
* <b>listenaddress</b> provides the host and optionally the port information
|
||||
* for the new structure. If no port is provided in <b>listenaddress</b> then
|
||||
* <b>listenport</b> is used.
|
||||
*
|
||||
* If not NULL <b>readable_address</b> will contain a copy of the host part of
|
||||
* <b>listenaddress</b>.
|
||||
*
|
||||
* The listenaddr struct has to be freed by the caller.
|
||||
*/
|
||||
static struct sockaddr_in *
|
||||
create_inet_sockaddr(const char *listenaddress, int listenport,
|
||||
char **readable_address, socklen_t *socklen_out) {
|
||||
struct sockaddr_in *listenaddr = NULL;
|
||||
uint32_t addr;
|
||||
uint16_t usePort = 0;
|
||||
|
||||
if (parse_addr_port(LOG_WARN,
|
||||
listenaddress, readable_address, &addr, &usePort)<0) {
|
||||
log_warn(LD_CONFIG,
|
||||
"Error parsing/resolving ListenAddress %s", listenaddress);
|
||||
goto err;
|
||||
}
|
||||
if (usePort==0) {
|
||||
if (listenport != CFG_AUTO_PORT)
|
||||
usePort = listenport;
|
||||
}
|
||||
|
||||
listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
|
||||
listenaddr->sin_addr.s_addr = htonl(addr);
|
||||
listenaddr->sin_family = AF_INET;
|
||||
listenaddr->sin_port = htons((uint16_t) usePort);
|
||||
|
||||
*socklen_out = sizeof(struct sockaddr_in);
|
||||
|
||||
return listenaddr;
|
||||
|
||||
err:
|
||||
tor_free(listenaddr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
/** Create an AF_UNIX listenaddr struct.
|
||||
* <b>listenaddress</b> provides the path to the Unix socket.
|
||||
@@ -877,12 +832,16 @@ make_socket_reuseable(tor_socket_t sock)
|
||||
static connection_t *
|
||||
connection_create_listener(const struct sockaddr *listensockaddr,
|
||||
socklen_t socklen,
|
||||
int type, char* address)
|
||||
int type, const char *address,
|
||||
const port_cfg_t *port_cfg)
|
||||
{
|
||||
listener_connection_t *lis_conn;
|
||||
connection_t *conn;
|
||||
tor_socket_t s; /* the socket we're going to make */
|
||||
uint16_t usePort = 0, gotPort = 0;
|
||||
int start_reading = 0;
|
||||
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
|
||||
tor_addr_t addr;
|
||||
|
||||
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
|
||||
warn_too_many_conns();
|
||||
@@ -890,7 +849,6 @@ connection_create_listener(const struct sockaddr *listensockaddr,
|
||||
}
|
||||
|
||||
if (listensockaddr->sa_family == AF_INET) {
|
||||
tor_addr_t addr;
|
||||
int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
|
||||
if (is_tcp)
|
||||
start_reading = 1;
|
||||
@@ -958,6 +916,8 @@ connection_create_listener(const struct sockaddr *listensockaddr,
|
||||
log_notice(LD_NET, "Opening %s on %s",
|
||||
conn_type_to_string(type), address);
|
||||
|
||||
tor_addr_make_unspec(&addr);
|
||||
|
||||
if (unlink(address) < 0 && errno != ENOENT) {
|
||||
log_warn(LD_NET, "Could not unlink %s: %s", address,
|
||||
strerror(errno));
|
||||
@@ -999,11 +959,23 @@ connection_create_listener(const struct sockaddr *listensockaddr,
|
||||
|
||||
set_socket_nonblocking(s);
|
||||
|
||||
conn = connection_new(type, listensockaddr->sa_family);
|
||||
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
|
||||
conn = TO_CONN(lis_conn);
|
||||
conn->socket_family = listensockaddr->sa_family;
|
||||
conn->s = s;
|
||||
conn->address = tor_strdup(address);
|
||||
conn->port = gotPort;
|
||||
tor_addr_copy(&conn->addr, &addr);
|
||||
|
||||
if (port_cfg->isolation_flags) {
|
||||
lis_conn->isolation_flags = port_cfg->isolation_flags;
|
||||
if (port_cfg->session_group >= 0) {
|
||||
lis_conn->session_group = port_cfg->session_group;
|
||||
} else {
|
||||
/* XXXX023 This can wrap after ~INT_MAX ports are opened. */
|
||||
lis_conn->session_group = global_next_session_group--;
|
||||
}
|
||||
}
|
||||
|
||||
if (connection_add(conn) < 0) { /* no space, forget it */
|
||||
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
|
||||
@@ -1015,9 +987,6 @@ connection_create_listener(const struct sockaddr *listensockaddr,
|
||||
"%s listening on port %u.",
|
||||
conn_type_to_string(type), gotPort);
|
||||
|
||||
if (type == CONN_TYPE_CONTROL_LISTENER)
|
||||
control_ports_write_to_file();
|
||||
|
||||
conn->state = LISTENER_STATE_READY;
|
||||
if (start_reading) {
|
||||
connection_start_reading(conn);
|
||||
@@ -1217,7 +1186,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
||||
return 0; /* no need to tear down the parent */
|
||||
}
|
||||
|
||||
if (connection_init_accepted_conn(newconn, conn->type) < 0) {
|
||||
if (connection_init_accepted_conn(newconn, TO_LISTENER_CONN(conn)) < 0) {
|
||||
if (! newconn->marked_for_close)
|
||||
connection_mark_for_close(newconn);
|
||||
return 0;
|
||||
@@ -1231,7 +1200,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
|
||||
* and place it in circuit_wait.
|
||||
*/
|
||||
static int
|
||||
connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
|
||||
connection_init_accepted_conn(connection_t *conn,
|
||||
const listener_connection_t *listener)
|
||||
{
|
||||
connection_start_reading(conn);
|
||||
|
||||
@@ -1240,7 +1210,11 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
|
||||
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
|
||||
return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
|
||||
case CONN_TYPE_AP:
|
||||
switch (listener_type) {
|
||||
TO_EDGE_CONN(conn)->isolation_flags = listener->isolation_flags;
|
||||
TO_EDGE_CONN(conn)->session_group = listener->session_group;
|
||||
TO_EDGE_CONN(conn)->nym_epoch = get_signewnym_epoch();
|
||||
TO_EDGE_CONN(conn)->socks_request->listener_type = listener->_base.type;
|
||||
switch (TO_CONN(listener)->type) {
|
||||
case CONN_TYPE_AP_LISTENER:
|
||||
conn->state = AP_CONN_STATE_SOCKS_WAIT;
|
||||
break;
|
||||
@@ -1741,6 +1715,113 @@ connection_read_proxy_handshake(connection_t *conn)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Given a list of listener connections in <b>old_conns</b>, and list of
|
||||
* port_cfg_t entries in <b>ports</b>, open a new listener for every port in
|
||||
* <b>ports</b> that does not already have a listener in <b>old_conns</b>.
|
||||
*
|
||||
* Remove from <b>old_conns</b> every connection that has a corresponding
|
||||
* entry in <b>ports</b>. Add to <b>new_conns</b> new every connection we
|
||||
* launch.
|
||||
*
|
||||
* Return 0 on success, -1 on failure.
|
||||
**/
|
||||
static int
|
||||
retry_listener_ports(smartlist_t *old_conns,
|
||||
const smartlist_t *ports,
|
||||
smartlist_t *new_conns)
|
||||
{
|
||||
smartlist_t *launch = smartlist_create();
|
||||
int r = 0;
|
||||
|
||||
smartlist_add_all(launch, ports);
|
||||
|
||||
/* Iterate through old_conns, comparing it to launch: remove from both lists
|
||||
* each pair of elements that corresponds to the same port. */
|
||||
SMARTLIST_FOREACH_BEGIN(old_conns, connection_t *, conn) {
|
||||
const port_cfg_t *found_port = NULL;
|
||||
|
||||
/* Okay, so this is a listener. Is it configured? */
|
||||
SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, wanted) {
|
||||
if (conn->type != wanted->type)
|
||||
continue;
|
||||
if ((conn->socket_family != AF_UNIX && wanted->is_unix_addr) ||
|
||||
(conn->socket_family == AF_UNIX && ! wanted->is_unix_addr))
|
||||
continue;
|
||||
|
||||
if (wanted->is_unix_addr) {
|
||||
if (conn->socket_family == AF_UNIX &&
|
||||
!strcmp(wanted->unix_addr, conn->address)) {
|
||||
found_port = wanted;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int port_matches;
|
||||
if (wanted->port == CFG_AUTO_PORT) {
|
||||
port_matches = 1;
|
||||
} else {
|
||||
port_matches = (wanted->port == conn->port);
|
||||
}
|
||||
if (port_matches && tor_addr_eq(&wanted->addr, &conn->addr)) {
|
||||
found_port = wanted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(wanted);
|
||||
|
||||
if (found_port) {
|
||||
/* This listener is already running; we don't need to launch it. */
|
||||
//log_debug(LD_NET, "Already have %s on %s:%d",
|
||||
// conn_type_to_string(found_port->type), conn->address, conn->port);
|
||||
smartlist_remove(launch, found_port);
|
||||
/* And we can remove the connection from old_conns too. */
|
||||
SMARTLIST_DEL_CURRENT(old_conns, conn);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(conn);
|
||||
|
||||
/* Now open all the listeners that are configured but not opened. */
|
||||
SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, port) {
|
||||
struct sockaddr *listensockaddr;
|
||||
socklen_t listensocklen = 0;
|
||||
char *address=NULL;
|
||||
connection_t *conn;
|
||||
int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port;
|
||||
tor_assert(real_port <= UINT16_MAX);
|
||||
|
||||
if (port->is_unix_addr) {
|
||||
listensockaddr = (struct sockaddr *)
|
||||
create_unix_sockaddr(port->unix_addr,
|
||||
&address, &listensocklen);
|
||||
} else {
|
||||
listensockaddr = tor_malloc(sizeof(struct sockaddr_storage));
|
||||
listensocklen = tor_addr_to_sockaddr(&port->addr,
|
||||
real_port,
|
||||
listensockaddr,
|
||||
sizeof(struct sockaddr_storage));
|
||||
address = tor_dup_addr(&port->addr);
|
||||
}
|
||||
|
||||
if (listensockaddr) {
|
||||
conn = connection_create_listener(listensockaddr, listensocklen,
|
||||
port->type, address, port);
|
||||
tor_free(listensockaddr);
|
||||
tor_free(address);
|
||||
} else {
|
||||
conn = NULL;
|
||||
}
|
||||
|
||||
if (!conn) {
|
||||
r = -1;
|
||||
} else {
|
||||
if (new_conns)
|
||||
smartlist_add(new_conns, conn);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(port);
|
||||
|
||||
smartlist_free(launch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch any configured listener connections of type <b>type</b>. (A
|
||||
* listener is configured if <b>port_option</b> is non-zero. If any
|
||||
@@ -1748,168 +1829,73 @@ connection_read_proxy_handshake(connection_t *conn)
|
||||
* connection binding to each one. Otherwise, create a single
|
||||
* connection binding to the address <b>default_addr</b>.)
|
||||
*
|
||||
* Only launch the listeners of this type that are not already open, and
|
||||
* only close listeners that are no longer wanted. Existing listeners
|
||||
* that are still configured are not touched.
|
||||
* We assume that we're starting with a list of existing listener connection_t
|
||||
* pointers in <b>old_conns</b>: we do not launch listeners that are already
|
||||
* in that list. Instead, we just remove them from the list.
|
||||
*
|
||||
* If <b>disable_all_conns</b> is set, then never open new conns, and
|
||||
* close the existing ones.
|
||||
*
|
||||
* Add all old conns that should be closed to <b>replaced_conns</b>.
|
||||
* Add all new connections to <b>new_conns</b>.
|
||||
* All new connections we launch are added to <b>new_conns</b>.
|
||||
*/
|
||||
static int
|
||||
retry_listeners(int type, config_line_t *cfg,
|
||||
retry_listeners(smartlist_t *old_conns,
|
||||
int type, const config_line_t *cfg,
|
||||
int port_option, const char *default_addr,
|
||||
smartlist_t *replaced_conns,
|
||||
smartlist_t *new_conns,
|
||||
int disable_all_conns,
|
||||
int socket_family)
|
||||
int is_sockaddr_un)
|
||||
{
|
||||
smartlist_t *launch = smartlist_create(), *conns;
|
||||
int free_launch_elts = 1;
|
||||
int r;
|
||||
config_line_t *c;
|
||||
connection_t *conn;
|
||||
config_line_t *line;
|
||||
smartlist_t *ports = smartlist_create();
|
||||
tor_addr_t dflt_addr;
|
||||
int retval = 0;
|
||||
|
||||
tor_assert(socket_family == AF_INET || socket_family == AF_UNIX);
|
||||
|
||||
if (cfg && port_option) {
|
||||
for (c = cfg; c; c = c->next) {
|
||||
smartlist_add(launch, c);
|
||||
}
|
||||
free_launch_elts = 0;
|
||||
} else if (port_option) {
|
||||
line = tor_malloc_zero(sizeof(config_line_t));
|
||||
line->key = tor_strdup("");
|
||||
line->value = tor_strdup(default_addr);
|
||||
smartlist_add(launch, line);
|
||||
if (default_addr) {
|
||||
tor_addr_from_str(&dflt_addr, default_addr);
|
||||
} else {
|
||||
tor_addr_make_unspec(&dflt_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
SMARTLIST_FOREACH(launch, config_line_t *, l,
|
||||
log_fn(LOG_NOTICE, "#%s#%s", l->key, l->value));
|
||||
*/
|
||||
|
||||
conns = get_connection_array();
|
||||
SMARTLIST_FOREACH(conns, connection_t *, conn,
|
||||
{
|
||||
if (conn->type != type ||
|
||||
conn->socket_family != socket_family ||
|
||||
conn->marked_for_close)
|
||||
continue;
|
||||
/* Okay, so this is a listener. Is it configured? */
|
||||
line = NULL;
|
||||
SMARTLIST_FOREACH(launch, config_line_t *, wanted,
|
||||
{
|
||||
char *address=NULL;
|
||||
uint16_t port;
|
||||
switch (socket_family) {
|
||||
case AF_INET:
|
||||
if (!parse_addr_port(LOG_WARN,
|
||||
wanted->value, &address, NULL, &port)) {
|
||||
int addr_matches = !strcasecmp(address, conn->address);
|
||||
int port_matches;
|
||||
tor_free(address);
|
||||
if (port) {
|
||||
/* The Listener line has a port */
|
||||
port_matches = (port == conn->port);
|
||||
} else if (port_option == CFG_AUTO_PORT) {
|
||||
/* The Listener line has no port, and the Port line is "auto".
|
||||
* "auto" matches anything; transitions from any port to
|
||||
* "auto" succeed. */
|
||||
port_matches = 1;
|
||||
} else {
|
||||
/* The Listener line has no port, and the Port line is "auto".
|
||||
* "auto" matches anything; transitions from any port to
|
||||
* "auto" succeed. */
|
||||
port_matches = (port_option == conn->port);
|
||||
}
|
||||
if (port_matches && addr_matches) {
|
||||
line = wanted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AF_UNIX:
|
||||
if (!strcasecmp(wanted->value, conn->address)) {
|
||||
line = wanted;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tor_assert(0);
|
||||
}
|
||||
});
|
||||
if (!line || disable_all_conns) {
|
||||
/* This one isn't configured. Close it. */
|
||||
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
|
||||
conn_type_to_string(type), conn->address, conn->port);
|
||||
if (replaced_conns) {
|
||||
smartlist_add(replaced_conns, conn);
|
||||
} else {
|
||||
connection_close_immediate(conn);
|
||||
connection_mark_for_close(conn);
|
||||
}
|
||||
if (port_option) {
|
||||
if (!cfg) {
|
||||
port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
tor_addr_copy(&port->addr, &dflt_addr);
|
||||
port->port = port_option;
|
||||
port->type = type;
|
||||
smartlist_add(ports, port);
|
||||
} else {
|
||||
/* It's configured; we don't need to launch it. */
|
||||
// log_debug(LD_NET, "Already have %s on %s:%d",
|
||||
// conn_type_to_string(type), conn->address, conn->port);
|
||||
smartlist_remove(launch, line);
|
||||
if (free_launch_elts)
|
||||
config_free_lines(line);
|
||||
}
|
||||
});
|
||||
|
||||
/* Now open all the listeners that are configured but not opened. */
|
||||
r = 0;
|
||||
if (!disable_all_conns) {
|
||||
SMARTLIST_FOREACH_BEGIN(launch, config_line_t *, cfg_line) {
|
||||
char *address = NULL;
|
||||
struct sockaddr *listensockaddr;
|
||||
socklen_t listensocklen = 0;
|
||||
|
||||
switch (socket_family) {
|
||||
case AF_INET:
|
||||
listensockaddr = (struct sockaddr *)
|
||||
create_inet_sockaddr(cfg_line->value,
|
||||
port_option,
|
||||
&address, &listensocklen);
|
||||
break;
|
||||
case AF_UNIX:
|
||||
listensockaddr = (struct sockaddr *)
|
||||
create_unix_sockaddr(cfg_line->value,
|
||||
&address, &listensocklen);
|
||||
break;
|
||||
default:
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
if (listensockaddr) {
|
||||
conn = connection_create_listener(listensockaddr, listensocklen,
|
||||
type, address);
|
||||
tor_free(listensockaddr);
|
||||
tor_free(address);
|
||||
} else
|
||||
conn = NULL;
|
||||
|
||||
if (!conn) {
|
||||
r = -1;
|
||||
const config_line_t *c;
|
||||
for (c = cfg; c; c = c->next) {
|
||||
port_cfg_t *port;
|
||||
tor_addr_t addr;
|
||||
uint16_t portval = 0;
|
||||
if (is_sockaddr_un) {
|
||||
size_t len = strlen(c->value);
|
||||
port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
|
||||
port->is_unix_addr = 1;
|
||||
memcpy(port->unix_addr, c->value, len+1);
|
||||
} else {
|
||||
if (new_conns)
|
||||
smartlist_add(new_conns, conn);
|
||||
if (tor_addr_port_parse(c->value, &addr, &portval) < 0) {
|
||||
log_warn(LD_CONFIG, "Can't parse/resolve %s %s",
|
||||
c->key, c->value);
|
||||
retval = -1;
|
||||
continue;
|
||||
}
|
||||
port = tor_malloc_zero(sizeof(port_cfg_t));
|
||||
tor_addr_copy(&port->addr, &addr);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(cfg_line);
|
||||
port->type = type;
|
||||
port->port = portval ? portval : port_option;
|
||||
smartlist_add(ports, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (free_launch_elts) {
|
||||
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
|
||||
config_free_lines(cfg_line));
|
||||
}
|
||||
smartlist_free(launch);
|
||||
if (retval == -1)
|
||||
goto cleanup;
|
||||
|
||||
return r;
|
||||
retval = retry_listener_ports(old_conns, ports, new_conns);
|
||||
|
||||
cleanup:
|
||||
SMARTLIST_FOREACH(ports, port_cfg_t *, p, tor_free(p));
|
||||
smartlist_free(ports);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/** Launch listeners for each port you should have open. Only launch
|
||||
@@ -1923,54 +1909,62 @@ int
|
||||
retry_all_listeners(smartlist_t *replaced_conns,
|
||||
smartlist_t *new_conns)
|
||||
{
|
||||
smartlist_t *listeners = smartlist_create();
|
||||
const or_options_t *options = get_options();
|
||||
int retval = 0;
|
||||
const uint16_t old_or_port = router_get_advertised_or_port(options);
|
||||
const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
|
||||
|
||||
if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
|
||||
options->ORPort, "0.0.0.0",
|
||||
replaced_conns, new_conns, options->ClientOnly,
|
||||
AF_INET)<0)
|
||||
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
|
||||
if (connection_is_listener(conn) && !conn->marked_for_close)
|
||||
smartlist_add(listeners, conn);
|
||||
} SMARTLIST_FOREACH_END(conn);
|
||||
|
||||
if (! options->ClientOnly) {
|
||||
if (retry_listeners(listeners,
|
||||
CONN_TYPE_OR_LISTENER, options->ORListenAddress,
|
||||
options->ORPort, "0.0.0.0",
|
||||
new_conns, 0) < 0)
|
||||
retval = -1;
|
||||
if (retry_listeners(listeners,
|
||||
CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
|
||||
options->DirPort, "0.0.0.0",
|
||||
new_conns, 0) < 0)
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
if (retry_listener_ports(listeners,
|
||||
get_configured_client_ports(),
|
||||
new_conns) < 0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
|
||||
options->DirPort, "0.0.0.0",
|
||||
replaced_conns, new_conns, options->ClientOnly,
|
||||
AF_INET)<0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
|
||||
options->SocksPort, "127.0.0.1",
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_INET)<0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
|
||||
options->TransPort, "127.0.0.1",
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_INET)<0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NATDListenAddress,
|
||||
options->NATDPort, "127.0.0.1",
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_INET)<0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
|
||||
options->DNSPort, "127.0.0.1",
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_INET)<0)
|
||||
retval = -1;
|
||||
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
|
||||
if (retry_listeners(listeners,
|
||||
CONN_TYPE_CONTROL_LISTENER,
|
||||
options->ControlListenAddress,
|
||||
options->ControlPort, "127.0.0.1",
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_INET)<0)
|
||||
new_conns, 0) < 0)
|
||||
return -1;
|
||||
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
|
||||
if (retry_listeners(listeners,
|
||||
CONN_TYPE_CONTROL_LISTENER,
|
||||
options->ControlSocket,
|
||||
options->ControlSocket ? 1 : 0, NULL,
|
||||
replaced_conns, new_conns, 0,
|
||||
AF_UNIX)<0)
|
||||
new_conns, 1) < 0)
|
||||
return -1;
|
||||
|
||||
/* Any members that were still in 'listeners' don't correspond to
|
||||
* any configured port. Kill 'em. */
|
||||
SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) {
|
||||
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
|
||||
conn_type_to_string(conn->type), conn->address, conn->port);
|
||||
if (replaced_conns) {
|
||||
smartlist_add(replaced_conns, conn);
|
||||
} else {
|
||||
connection_close_immediate(conn);
|
||||
connection_mark_for_close(conn);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(conn);
|
||||
|
||||
smartlist_free(listeners);
|
||||
|
||||
if (old_or_port != router_get_advertised_or_port(options) ||
|
||||
old_dir_port != router_get_advertised_dir_port(options, 0)) {
|
||||
/* Our chosen ORPort or DirPort is not what it used to be: the
|
||||
@@ -3910,6 +3904,9 @@ assert_connection_ok(connection_t *conn, time_t now)
|
||||
case CONN_TYPE_CONTROL:
|
||||
tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
|
||||
break;
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC);
|
||||
break;
|
||||
default:
|
||||
tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
|
||||
break;
|
||||
@@ -3994,13 +3991,7 @@ assert_connection_ok(connection_t *conn, time_t now)
|
||||
|
||||
switch (conn->type)
|
||||
{
|
||||
case CONN_TYPE_OR_LISTENER:
|
||||
case CONN_TYPE_AP_LISTENER:
|
||||
case CONN_TYPE_AP_TRANS_LISTENER:
|
||||
case CONN_TYPE_AP_NATD_LISTENER:
|
||||
case CONN_TYPE_DIR_LISTENER:
|
||||
case CONN_TYPE_CONTROL_LISTENER:
|
||||
case CONN_TYPE_AP_DNS_LISTENER:
|
||||
CASE_ANY_LISTENER_TYPE:
|
||||
tor_assert(conn->state == LISTENER_STATE_READY);
|
||||
break;
|
||||
case CONN_TYPE_OR:
|
||||
@@ -4136,3 +4127,42 @@ proxy_type_to_string(int proxy_type)
|
||||
return NULL; /*Unreached*/
|
||||
}
|
||||
|
||||
/** Call _connection_free() on every connection in our array, and release all
|
||||
* storage held by connection.c. This is used by cpuworkers and dnsworkers
|
||||
* when they fork, so they don't keep resources held open (especially
|
||||
* sockets).
|
||||
*
|
||||
* Don't do the checks in connection_free(), because they will
|
||||
* fail.
|
||||
*/
|
||||
void
|
||||
connection_free_all(void)
|
||||
{
|
||||
smartlist_t *conns = get_connection_array();
|
||||
|
||||
/* We don't want to log any messages to controllers. */
|
||||
SMARTLIST_FOREACH(conns, connection_t *, conn,
|
||||
if (conn->type == CONN_TYPE_CONTROL)
|
||||
TO_CONTROL_CONN(conn)->event_mask = 0);
|
||||
|
||||
control_update_global_event_mask();
|
||||
|
||||
/* Unlink everything from the identity map. */
|
||||
connection_or_clear_identity_map();
|
||||
|
||||
/* Clear out our list of broken connections */
|
||||
clear_broken_connection_map(0);
|
||||
|
||||
SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
|
||||
|
||||
if (outgoing_addrs) {
|
||||
SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
|
||||
smartlist_free(outgoing_addrs);
|
||||
outgoing_addrs = NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
if (global_rate_limit)
|
||||
bufferevent_rate_limit_group_free(global_rate_limit);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ dir_connection_t *dir_connection_new(int socket_family);
|
||||
or_connection_t *or_connection_new(int socket_family);
|
||||
edge_connection_t *edge_connection_new(int type, int socket_family);
|
||||
control_connection_t *control_connection_new(int socket_family);
|
||||
listener_connection_t *listener_connection_new(int type, int socket_family);
|
||||
connection_t *connection_new(int type, int socket_family);
|
||||
|
||||
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
|
||||
|
||||
+270
-3
@@ -57,6 +57,7 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn);
|
||||
static int address_is_in_virtual_range(const char *addr);
|
||||
static int consider_plaintext_ports(edge_connection_t *conn, uint16_t port);
|
||||
static void clear_trackexithost_mappings(const char *exitname);
|
||||
static int connection_ap_supports_optimistic_data(const edge_connection_t *);
|
||||
|
||||
/** An AP stream has failed/finished. If it hasn't already sent back
|
||||
* a socks reply, send one now (based on endreason). Also set
|
||||
@@ -154,10 +155,26 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case AP_CONN_STATE_CONNECT_WAIT:
|
||||
if (connection_ap_supports_optimistic_data(conn)) {
|
||||
log_info(LD_EDGE,
|
||||
"data from edge while in '%s' state. Sending it anyway. "
|
||||
"package_partial=%d, buflen=%ld",
|
||||
conn_state_to_string(conn->_base.type, conn->_base.state),
|
||||
package_partial,
|
||||
(long)connection_get_inbuf_len(TO_CONN(conn)));
|
||||
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
|
||||
/* (We already sent an end cell if possible) */
|
||||
connection_mark_for_close(TO_CONN(conn));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* Fall through if the connection is on a circuit without optimistic
|
||||
* data support. */
|
||||
case EXIT_CONN_STATE_CONNECTING:
|
||||
case AP_CONN_STATE_RENDDESC_WAIT:
|
||||
case AP_CONN_STATE_CIRCUIT_WAIT:
|
||||
case AP_CONN_STATE_CONNECT_WAIT:
|
||||
case AP_CONN_STATE_RESOLVE_WAIT:
|
||||
case AP_CONN_STATE_CONTROLLER_WAIT:
|
||||
log_info(LD_EDGE,
|
||||
@@ -722,6 +739,12 @@ connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ,
|
||||
{
|
||||
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
|
||||
conn->_base.timestamp_lastread = time(NULL);
|
||||
|
||||
if (conn->pending_optimistic_data) {
|
||||
generic_buffer_set_to_copy(&conn->sending_optimistic_data,
|
||||
conn->pending_optimistic_data);
|
||||
}
|
||||
|
||||
if (!get_options()->LeaveStreamsUnattached || conn->use_begindir) {
|
||||
/* If we're attaching streams ourself, or if this connection is
|
||||
* a tunneled directory connection, then just attach it. */
|
||||
@@ -1671,6 +1694,9 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
|
||||
safe_str_client(socks->address),
|
||||
socks->port);
|
||||
|
||||
if (! conn->original_dest_address)
|
||||
conn->original_dest_address = tor_strdup(conn->socks_request->address);
|
||||
|
||||
if (socks->command == SOCKS_COMMAND_RESOLVE &&
|
||||
!tor_inet_aton(socks->address, &addr_tmp) &&
|
||||
options->AutomapHostsOnResolve && options->AutomapHostsSuffixes) {
|
||||
@@ -2334,6 +2360,22 @@ get_unique_stream_id_by_circ(origin_circuit_t *circ)
|
||||
return test_stream_id;
|
||||
}
|
||||
|
||||
/** Return true iff <b>conn</b> is linked to a circuit and configured to use
|
||||
* an exit that supports optimistic data. */
|
||||
static int
|
||||
connection_ap_supports_optimistic_data(const edge_connection_t *conn)
|
||||
{
|
||||
tor_assert(conn->_base.type == CONN_TYPE_AP);
|
||||
/* We can only send optimistic data if we're connected to an open
|
||||
general circuit. */
|
||||
if (conn->on_circuit == NULL ||
|
||||
conn->on_circuit->state != CIRCUIT_STATE_OPEN ||
|
||||
conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
|
||||
return 0;
|
||||
|
||||
return conn->may_use_optimistic_data;
|
||||
}
|
||||
|
||||
/** Write a relay begin cell, using destaddr and destport from ap_conn's
|
||||
* socks_request field, and send it down circ.
|
||||
*
|
||||
@@ -2395,6 +2437,21 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn)
|
||||
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
|
||||
ap_conn->_base.s, circ->_base.n_circ_id);
|
||||
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
|
||||
|
||||
/* If there's queued-up data, send it now */
|
||||
if ((connection_get_inbuf_len(TO_CONN(ap_conn)) ||
|
||||
ap_conn->sending_optimistic_data) &&
|
||||
connection_ap_supports_optimistic_data(ap_conn)) {
|
||||
log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data",
|
||||
(long)connection_get_inbuf_len(TO_CONN(ap_conn)),
|
||||
ap_conn->sending_optimistic_data ?
|
||||
(long)generic_buffer_len(ap_conn->sending_optimistic_data) :
|
||||
0);
|
||||
if (connection_edge_package_raw_inbuf(ap_conn, 1, NULL) < 0) {
|
||||
connection_mark_for_close(TO_CONN(ap_conn));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2494,7 +2551,9 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
|
||||
edge_connection_t *
|
||||
connection_ap_make_link(connection_t *partner,
|
||||
char *address, uint16_t port,
|
||||
const char *digest, int use_begindir, int want_onehop)
|
||||
const char *digest,
|
||||
int session_group, int isolation_flags,
|
||||
int use_begindir, int want_onehop)
|
||||
{
|
||||
edge_connection_t *conn;
|
||||
|
||||
@@ -2524,6 +2583,12 @@ connection_ap_make_link(connection_t *partner,
|
||||
digest, DIGEST_LEN);
|
||||
}
|
||||
|
||||
/* Populate isolation fields. */
|
||||
conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
|
||||
conn->original_dest_address = tor_strdup(address);
|
||||
conn->session_group = session_group;
|
||||
conn->isolation_flags = isolation_flags;
|
||||
|
||||
conn->_base.address = tor_strdup("(Tor_internal)");
|
||||
tor_addr_make_unspec(&conn->_base.addr);
|
||||
conn->_base.port = 0;
|
||||
@@ -3166,7 +3231,7 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn)
|
||||
* resolved.)
|
||||
*/
|
||||
int
|
||||
connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit)
|
||||
connection_ap_can_use_exit(const edge_connection_t *conn, const node_t *exit)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
@@ -3266,3 +3331,205 @@ parse_extended_hostname(char *address, int allowdotexit)
|
||||
return BAD_HOSTNAME;
|
||||
}
|
||||
|
||||
/** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at
|
||||
* <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory
|
||||
* at <b>b</b>. */
|
||||
static int
|
||||
memeq_opt(const char *a, size_t alen, const char *b, size_t blen)
|
||||
{
|
||||
if (a == NULL) {
|
||||
return (b == NULL);
|
||||
} else if (b == NULL) {
|
||||
return 0;
|
||||
} else if (alen != blen) {
|
||||
return 0;
|
||||
} else {
|
||||
return tor_memeq(a, b, alen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff none of the isolation flags and fields in <b>conn</b>
|
||||
* should prevent it from being attached to <b>circ</b>.
|
||||
*/
|
||||
int
|
||||
connection_edge_compatible_with_circuit(const edge_connection_t *conn,
|
||||
const origin_circuit_t *circ)
|
||||
{
|
||||
const uint8_t iso = conn->isolation_flags;
|
||||
const socks_request_t *sr = conn->socks_request;
|
||||
|
||||
/* If circ has never been used for an isolated connection, we can
|
||||
* totally use it for this one. */
|
||||
if (!circ->isolation_values_set)
|
||||
return 1;
|
||||
|
||||
/* If circ has been used for connections having more than one value
|
||||
* for some field f, it will have the corresponding bit set in
|
||||
* isolation_flags_mixed. If isolation_flags_mixed has any bits
|
||||
* in common with iso, then conn must be isolated from at least
|
||||
* one stream that has been attached to circ. */
|
||||
if ((iso & circ->isolation_flags_mixed) != 0) {
|
||||
/* For at least one field where conn is isolated, the circuit
|
||||
* already has mixed streams. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! conn->original_dest_address) {
|
||||
log_warn(LD_BUG, "Reached connection_edge_compatible_with_circuit without "
|
||||
"having set conn->original_dest_address");
|
||||
((edge_connection_t*)conn)->original_dest_address =
|
||||
tor_strdup(conn->socks_request->address);
|
||||
}
|
||||
|
||||
if ((iso & ISO_STREAM) &&
|
||||
(circ->associated_isolated_stream_global_id !=
|
||||
TO_CONN(conn)->global_identifier))
|
||||
return 0;
|
||||
|
||||
if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port)
|
||||
return 0;
|
||||
if ((iso & ISO_DESTADDR) &&
|
||||
strcasecmp(conn->original_dest_address, circ->dest_address))
|
||||
return 0;
|
||||
if ((iso & ISO_SOCKSAUTH) &&
|
||||
(! memeq_opt(sr->username, sr->usernamelen,
|
||||
circ->socks_username, circ->socks_username_len) ||
|
||||
! memeq_opt(sr->password, sr->passwordlen,
|
||||
circ->socks_password, circ->socks_password_len)))
|
||||
return 0;
|
||||
if ((iso & ISO_CLIENTPROTO) &&
|
||||
(conn->socks_request->listener_type != circ->client_proto_type ||
|
||||
conn->socks_request->socks_version != circ->client_proto_socksver))
|
||||
return 0;
|
||||
if ((iso & ISO_CLIENTADDR) &&
|
||||
!tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
|
||||
return 0;
|
||||
if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
|
||||
return 0;
|
||||
if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* If <b>dry_run</b> is false, update <b>circ</b>'s isolation flags and fields
|
||||
* to reflect having had <b>conn</b> attached to it, and return 0. Otherwise,
|
||||
* if <b>dry_run</b> is true, then make no changes to <b>circ</b>, and return
|
||||
* a bitfield of isolation flags that we would have to set in
|
||||
* isolation_flags_mixed to add <b>conn</b> to <b>circ</b>, or -1 if
|
||||
* <b>circ</b> has had no streams attached to it.
|
||||
*/
|
||||
int
|
||||
connection_edge_update_circuit_isolation(const edge_connection_t *conn,
|
||||
origin_circuit_t *circ,
|
||||
int dry_run)
|
||||
{
|
||||
const socks_request_t *sr = conn->socks_request;
|
||||
if (! conn->original_dest_address) {
|
||||
log_warn(LD_BUG, "Reached connection_update_circuit_isolation without "
|
||||
"having set conn->original_dest_address");
|
||||
((edge_connection_t*)conn)->original_dest_address =
|
||||
tor_strdup(conn->socks_request->address);
|
||||
}
|
||||
|
||||
if (!circ->isolation_values_set) {
|
||||
if (dry_run)
|
||||
return -1;
|
||||
circ->associated_isolated_stream_global_id =
|
||||
TO_CONN(conn)->global_identifier;
|
||||
circ->dest_port = conn->socks_request->port;
|
||||
circ->dest_address = tor_strdup(conn->original_dest_address);
|
||||
circ->client_proto_type = conn->socks_request->listener_type;
|
||||
circ->client_proto_socksver = conn->socks_request->socks_version;
|
||||
tor_addr_copy(&circ->client_addr, &TO_CONN(conn)->addr);
|
||||
circ->session_group = conn->session_group;
|
||||
circ->nym_epoch = conn->nym_epoch;
|
||||
circ->socks_username = sr->username ?
|
||||
tor_memdup(sr->username, sr->usernamelen) : NULL;
|
||||
circ->socks_password = sr->password ?
|
||||
tor_memdup(sr->password, sr->passwordlen) : NULL;
|
||||
circ->socks_username_len = sr->usernamelen;
|
||||
circ->socks_password_len = sr->passwordlen;
|
||||
|
||||
circ->isolation_values_set = 1;
|
||||
return 0;
|
||||
} else {
|
||||
uint8_t mixed = 0;
|
||||
if (conn->socks_request->port != circ->dest_port)
|
||||
mixed |= ISO_DESTPORT;
|
||||
if (strcasecmp(conn->original_dest_address, circ->dest_address))
|
||||
mixed |= ISO_DESTADDR;
|
||||
if (!memeq_opt(sr->username, sr->usernamelen,
|
||||
circ->socks_username, circ->socks_username_len) ||
|
||||
!memeq_opt(sr->password, sr->passwordlen,
|
||||
circ->socks_password, circ->socks_password_len))
|
||||
mixed |= ISO_SOCKSAUTH;
|
||||
if ((conn->socks_request->listener_type != circ->client_proto_type ||
|
||||
conn->socks_request->socks_version != circ->client_proto_socksver))
|
||||
mixed |= ISO_CLIENTPROTO;
|
||||
if (!tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
|
||||
mixed |= ISO_CLIENTADDR;
|
||||
if (conn->session_group != circ->session_group)
|
||||
mixed |= ISO_SESSIONGRP;
|
||||
if (conn->nym_epoch != circ->nym_epoch)
|
||||
mixed |= ISO_NYM_EPOCH;
|
||||
|
||||
if (dry_run)
|
||||
return mixed;
|
||||
|
||||
if ((mixed & conn->isolation_flags) != 0) {
|
||||
log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
|
||||
"isolation flags.");
|
||||
}
|
||||
circ->isolation_flags_mixed |= mixed;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the isolation settings on <b>circ</b>.
|
||||
*
|
||||
* This only works on an open circuit that has never had a stream attached to
|
||||
* it, and whose isolation settings are hypothetical. (We set hypothetical
|
||||
* isolation settings on circuits as we're launching them, so that we
|
||||
* know whether they can handle more streams or whether we need to launch
|
||||
* even more circuits. Once the circuit is open, if it turns out that
|
||||
* we no longer have any streams to attach to it, we clear the isolation flags
|
||||
* and data so that other streams can have a chance.)
|
||||
*/
|
||||
void
|
||||
circuit_clear_isolation(origin_circuit_t *circ)
|
||||
{
|
||||
if (circ->isolation_any_streams_attached) {
|
||||
log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit");
|
||||
return;
|
||||
}
|
||||
if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) {
|
||||
log_warn(LD_BUG, "Tried to clear the isolation status of a non-open "
|
||||
"circuit");
|
||||
return;
|
||||
}
|
||||
|
||||
circ->isolation_values_set = 0;
|
||||
circ->isolation_flags_mixed = 0;
|
||||
circ->associated_isolated_stream_global_id = 0;
|
||||
circ->client_proto_type = 0;
|
||||
circ->client_proto_socksver = 0;
|
||||
circ->dest_port = 0;
|
||||
tor_addr_make_unspec(&circ->client_addr);
|
||||
tor_free(circ->dest_address);
|
||||
circ->session_group = -1;
|
||||
circ->nym_epoch = 0;
|
||||
if (circ->socks_username) {
|
||||
memset(circ->socks_username, 0x11, circ->socks_username_len);
|
||||
tor_free(circ->socks_username);
|
||||
}
|
||||
if (circ->socks_password) {
|
||||
memset(circ->socks_password, 0x05, circ->socks_password_len);
|
||||
tor_free(circ->socks_password);
|
||||
}
|
||||
circ->socks_username_len = circ->socks_password_len = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn);
|
||||
edge_connection_t *connection_ap_make_link(connection_t *partner,
|
||||
char *address, uint16_t port,
|
||||
const char *digest,
|
||||
int session_group,
|
||||
int isolation_flags,
|
||||
int use_begindir, int want_onehop);
|
||||
void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
|
||||
size_t replylen,
|
||||
@@ -51,7 +53,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
|
||||
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
|
||||
void connection_exit_connect(edge_connection_t *conn);
|
||||
int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
|
||||
int connection_ap_can_use_exit(edge_connection_t *conn,
|
||||
int connection_ap_can_use_exit(const edge_connection_t *conn,
|
||||
const node_t *exit);
|
||||
void connection_ap_expire_beginning(void);
|
||||
void connection_ap_attach_pending(void);
|
||||
@@ -103,5 +105,12 @@ hostname_type_t parse_extended_hostname(char *address, int allowdotexit);
|
||||
int get_pf_socket(void);
|
||||
#endif
|
||||
|
||||
int connection_edge_compatible_with_circuit(const edge_connection_t *conn,
|
||||
const origin_circuit_t *circ);
|
||||
int connection_edge_update_circuit_isolation(const edge_connection_t *conn,
|
||||
origin_circuit_t *circ,
|
||||
int dry_run);
|
||||
void circuit_clear_isolation(origin_circuit_t *circ);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+37
-2
@@ -74,7 +74,8 @@
|
||||
#define EVENT_NEWCONSENSUS 0x0016
|
||||
#define EVENT_BUILDTIMEOUT_SET 0x0017
|
||||
#define EVENT_SIGNAL 0x0018
|
||||
#define _EVENT_MAX 0x0018
|
||||
#define EVENT_CONF_CHANGED 0x0019
|
||||
#define _EVENT_MAX 0x0019
|
||||
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
|
||||
|
||||
/** Bitfield: The bit 1<<e is set if <b>any</b> open control
|
||||
@@ -946,6 +947,7 @@ static const struct control_event_t control_event_table[] = {
|
||||
{ EVENT_NEWCONSENSUS, "NEWCONSENSUS" },
|
||||
{ EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" },
|
||||
{ EVENT_SIGNAL, "SIGNAL" },
|
||||
{ EVENT_CONF_CHANGED, "CONF_CHANGED"},
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
@@ -3567,7 +3569,7 @@ control_event_logmsg(int severity, uint32_t domain, const char *msg)
|
||||
severity <= LOG_NOTICE) {
|
||||
char *esc = esc_for_log(msg);
|
||||
++disable_log_messages;
|
||||
control_event_general_status(severity, "BUG REASON=\"%s\"", esc);
|
||||
control_event_general_status(severity, "BUG REASON=%s", esc);
|
||||
--disable_log_messages;
|
||||
tor_free(esc);
|
||||
}
|
||||
@@ -3996,6 +3998,39 @@ control_event_guard(const char *nickname, const char *digest,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Called when a configuration option changes. This is generally triggered
|
||||
* by SETCONF requests and RELOAD/SIGHUP signals. The <b>elements</b> is
|
||||
* a smartlist_t containing (key, value, ...) pairs in sequence.
|
||||
* <b>value</b> can be NULL. */
|
||||
int
|
||||
control_event_conf_changed(smartlist_t *elements)
|
||||
{
|
||||
int i;
|
||||
char *result;
|
||||
smartlist_t *lines;
|
||||
if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) ||
|
||||
smartlist_len(elements) == 0) {
|
||||
return 0;
|
||||
}
|
||||
lines = smartlist_create();
|
||||
for (i = 0; i < smartlist_len(elements); i += 2) {
|
||||
char *k = smartlist_get(elements, i);
|
||||
char *v = smartlist_get(elements, i+1);
|
||||
if (v == NULL) {
|
||||
smartlist_asprintf_add(lines, "650-%s", k);
|
||||
} else {
|
||||
smartlist_asprintf_add(lines, "650-%s=%s", k, v);
|
||||
}
|
||||
}
|
||||
result = smartlist_join_strings(lines, "\r\n", 0, NULL);
|
||||
send_control_event(EVENT_CONF_CHANGED, 0,
|
||||
"650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result);
|
||||
tor_free(result);
|
||||
SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
|
||||
smartlist_free(lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Helper: Return a newly allocated string containing a path to the
|
||||
* file where we store our authentication cookie. */
|
||||
static char *
|
||||
|
||||
@@ -66,6 +66,7 @@ int control_event_server_status(int severity, const char *format, ...)
|
||||
CHECK_PRINTF(2,3);
|
||||
int control_event_guard(const char *nickname, const char *digest,
|
||||
const char *status);
|
||||
int control_event_conf_changed(smartlist_t *elements);
|
||||
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
|
||||
buildtimeout_set_event_t type);
|
||||
int control_event_signal(uintptr_t signal);
|
||||
|
||||
+7
-1
@@ -973,6 +973,10 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
|
||||
}
|
||||
} else { /* we want to connect via a tor connection */
|
||||
edge_connection_t *linked_conn;
|
||||
/* Anonymized tunneled connections can never share a circuit.
|
||||
* One-hop directory connections can share circuits with each other
|
||||
* but nothing else. */
|
||||
int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP;
|
||||
|
||||
/* If it's an anonymized connection, remember the fact that we
|
||||
* wanted it for later: maybe we'll want it again soon. */
|
||||
@@ -988,7 +992,9 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
|
||||
linked_conn =
|
||||
connection_ap_make_link(TO_CONN(conn),
|
||||
conn->_base.address, conn->_base.port,
|
||||
digest, use_begindir, conn->dirconn_direct);
|
||||
digest,
|
||||
SESSION_GROUP_DIRCONN, iso_flags,
|
||||
use_begindir, conn->dirconn_direct);
|
||||
if (!linked_conn) {
|
||||
log_warn(LD_NET,"Making tunnel to dirserver failed.");
|
||||
connection_mark_for_close(TO_CONN(conn));
|
||||
|
||||
+24
-7
@@ -29,8 +29,9 @@
|
||||
* DNSPort. We need to eventually answer the request <b>req</b>.
|
||||
*/
|
||||
static void
|
||||
evdns_server_callback(struct evdns_server_request *req, void *_data)
|
||||
evdns_server_callback(struct evdns_server_request *req, void *data_)
|
||||
{
|
||||
const listener_connection_t *listener = data_;
|
||||
edge_connection_t *conn;
|
||||
int i = 0;
|
||||
struct evdns_server_question *q = NULL;
|
||||
@@ -43,7 +44,7 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
|
||||
char *q_name;
|
||||
|
||||
tor_assert(req);
|
||||
tor_assert(_data == NULL);
|
||||
|
||||
log_info(LD_APP, "Got a new DNS request!");
|
||||
|
||||
req->flags |= 0x80; /* set RA */
|
||||
@@ -130,7 +131,11 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
|
||||
strlcpy(conn->socks_request->address, q->name,
|
||||
sizeof(conn->socks_request->address));
|
||||
|
||||
conn->socks_request->listener_type = listener->_base.type;
|
||||
conn->dns_server_request = req;
|
||||
conn->isolation_flags = listener->isolation_flags;
|
||||
conn->session_group = listener->session_group;
|
||||
conn->nym_epoch = get_signewnym_epoch();
|
||||
|
||||
if (connection_add(TO_CONN(conn)) < 0) {
|
||||
log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
|
||||
@@ -181,6 +186,12 @@ dnsserv_launch_request(const char *name, int reverse)
|
||||
strlcpy(conn->socks_request->address, name,
|
||||
sizeof(conn->socks_request->address));
|
||||
|
||||
conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER;
|
||||
conn->original_dest_address = tor_strdup(name);
|
||||
conn->session_group = SESSION_GROUP_CONTROL_RESOLVE;
|
||||
conn->nym_epoch = get_signewnym_epoch();
|
||||
conn->isolation_flags = ISO_DEFAULT;
|
||||
|
||||
if (connection_add(TO_CONN(conn))<0) {
|
||||
log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
|
||||
connection_free(TO_CONN(conn));
|
||||
@@ -305,12 +316,15 @@ dnsserv_resolved(edge_connection_t *conn,
|
||||
void
|
||||
dnsserv_configure_listener(connection_t *conn)
|
||||
{
|
||||
listener_connection_t *listener_conn;
|
||||
tor_assert(conn);
|
||||
tor_assert(SOCKET_OK(conn->s));
|
||||
tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER);
|
||||
|
||||
conn->dns_server_port =
|
||||
tor_evdns_add_server_port(conn->s, 0, evdns_server_callback, NULL);
|
||||
listener_conn = TO_LISTENER_CONN(conn);
|
||||
listener_conn->dns_server_port =
|
||||
tor_evdns_add_server_port(conn->s, 0, evdns_server_callback,
|
||||
listener_conn);
|
||||
}
|
||||
|
||||
/** Free the evdns server port for <b>conn</b>, which must be an
|
||||
@@ -318,12 +332,15 @@ dnsserv_configure_listener(connection_t *conn)
|
||||
void
|
||||
dnsserv_close_listener(connection_t *conn)
|
||||
{
|
||||
listener_connection_t *listener_conn;
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER);
|
||||
|
||||
if (conn->dns_server_port) {
|
||||
evdns_close_server_port(conn->dns_server_port);
|
||||
conn->dns_server_port = NULL;
|
||||
listener_conn = TO_LISTENER_CONN(conn);
|
||||
|
||||
if (listener_conn->dns_server_port) {
|
||||
evdns_close_server_port(listener_conn->dns_server_port);
|
||||
listener_conn->dns_server_port = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+188
-128
@@ -930,10 +930,9 @@ geoip_dirreq_stats_init(time_t now)
|
||||
start_of_dirreq_stats_interval = now;
|
||||
}
|
||||
|
||||
/** Stop collecting directory request stats in a way that we can re-start
|
||||
* doing so in geoip_dirreq_stats_init(). */
|
||||
/** Reset counters for dirreq stats. */
|
||||
void
|
||||
geoip_dirreq_stats_term(void)
|
||||
geoip_reset_dirreq_stats(time_t now)
|
||||
{
|
||||
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
|
||||
c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
|
||||
@@ -965,21 +964,131 @@ geoip_dirreq_stats_term(void)
|
||||
tor_free(this);
|
||||
}
|
||||
}
|
||||
start_of_dirreq_stats_interval = 0;
|
||||
start_of_dirreq_stats_interval = now;
|
||||
}
|
||||
|
||||
/** Write dirreq statistics to $DATADIR/stats/dirreq-stats and return when
|
||||
* we would next want to write. */
|
||||
/** Stop collecting directory request stats in a way that we can re-start
|
||||
* doing so in geoip_dirreq_stats_init(). */
|
||||
void
|
||||
geoip_dirreq_stats_term(void)
|
||||
{
|
||||
geoip_reset_dirreq_stats(0);
|
||||
}
|
||||
|
||||
/** Return a newly allocated string containing the dirreq statistics
|
||||
* until <b>now</b>, or NULL if we're not collecting dirreq stats. */
|
||||
char *
|
||||
geoip_format_dirreq_stats(time_t now)
|
||||
{
|
||||
char t[ISO_TIME_LEN+1];
|
||||
double v2_share = 0.0, v3_share = 0.0;
|
||||
int i;
|
||||
char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string,
|
||||
*v2_share_string = NULL, *v3_share_string = NULL,
|
||||
*v3_direct_dl_string, *v2_direct_dl_string,
|
||||
*v3_tunneled_dl_string, *v2_tunneled_dl_string;
|
||||
char *result;
|
||||
|
||||
if (!start_of_dirreq_stats_interval)
|
||||
return NULL; /* Not initialized. */
|
||||
|
||||
format_iso_time(t, now);
|
||||
v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
|
||||
v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
|
||||
v2_reqs_string = geoip_get_request_history(
|
||||
GEOIP_CLIENT_NETWORKSTATUS_V2);
|
||||
v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
|
||||
|
||||
#define RESPONSE_GRANULARITY 8
|
||||
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
|
||||
ns_v2_responses[i] = round_uint32_to_next_multiple_of(
|
||||
ns_v2_responses[i], RESPONSE_GRANULARITY);
|
||||
ns_v3_responses[i] = round_uint32_to_next_multiple_of(
|
||||
ns_v3_responses[i], RESPONSE_GRANULARITY);
|
||||
}
|
||||
#undef RESPONSE_GRANULARITY
|
||||
|
||||
if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
|
||||
tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2lf%%\n",
|
||||
v2_share*100);
|
||||
tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2lf%%\n",
|
||||
v3_share*100);
|
||||
}
|
||||
|
||||
v2_direct_dl_string = geoip_get_dirreq_history(
|
||||
GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT);
|
||||
v3_direct_dl_string = geoip_get_dirreq_history(
|
||||
GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT);
|
||||
|
||||
v2_tunneled_dl_string = geoip_get_dirreq_history(
|
||||
GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED);
|
||||
v3_tunneled_dl_string = geoip_get_dirreq_history(
|
||||
GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED);
|
||||
|
||||
/* Put everything together into a single string. */
|
||||
tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n"
|
||||
"dirreq-v3-ips %s\n"
|
||||
"dirreq-v2-ips %s\n"
|
||||
"dirreq-v3-reqs %s\n"
|
||||
"dirreq-v2-reqs %s\n"
|
||||
"dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
|
||||
"not-found=%u,not-modified=%u,busy=%u\n"
|
||||
"dirreq-v2-resp ok=%u,unavailable=%u,"
|
||||
"not-found=%u,not-modified=%u,busy=%u\n"
|
||||
"%s"
|
||||
"%s"
|
||||
"dirreq-v3-direct-dl %s\n"
|
||||
"dirreq-v2-direct-dl %s\n"
|
||||
"dirreq-v3-tunneled-dl %s\n"
|
||||
"dirreq-v2-tunneled-dl %s\n",
|
||||
t,
|
||||
(unsigned) (now - start_of_dirreq_stats_interval),
|
||||
v3_ips_string ? v3_ips_string : "",
|
||||
v2_ips_string ? v2_ips_string : "",
|
||||
v3_reqs_string ? v3_reqs_string : "",
|
||||
v2_reqs_string ? v2_reqs_string : "",
|
||||
ns_v3_responses[GEOIP_SUCCESS],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
|
||||
ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
|
||||
ns_v3_responses[GEOIP_REJECT_BUSY],
|
||||
ns_v2_responses[GEOIP_SUCCESS],
|
||||
ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
|
||||
ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
|
||||
ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
|
||||
ns_v2_responses[GEOIP_REJECT_BUSY],
|
||||
v2_share_string ? v2_share_string : "",
|
||||
v3_share_string ? v3_share_string : "",
|
||||
v3_direct_dl_string ? v3_direct_dl_string : "",
|
||||
v2_direct_dl_string ? v2_direct_dl_string : "",
|
||||
v3_tunneled_dl_string ? v3_tunneled_dl_string : "",
|
||||
v2_tunneled_dl_string ? v2_tunneled_dl_string : "");
|
||||
|
||||
/* Free partial strings. */
|
||||
tor_free(v3_ips_string);
|
||||
tor_free(v2_ips_string);
|
||||
tor_free(v3_reqs_string);
|
||||
tor_free(v2_reqs_string);
|
||||
tor_free(v2_share_string);
|
||||
tor_free(v3_share_string);
|
||||
tor_free(v3_direct_dl_string);
|
||||
tor_free(v2_direct_dl_string);
|
||||
tor_free(v3_tunneled_dl_string);
|
||||
tor_free(v2_tunneled_dl_string);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If 24 hours have passed since the beginning of the current dirreq
|
||||
* stats period, write dirreq stats to $DATADIR/stats/dirreq-stats
|
||||
* (possibly overwriting an existing file) and reset counters. Return
|
||||
* when we would next want to write dirreq stats or 0 if we never want to
|
||||
* write. */
|
||||
time_t
|
||||
geoip_dirreq_stats_write(time_t now)
|
||||
{
|
||||
char *statsdir = NULL, *filename = NULL;
|
||||
char *data_v2 = NULL, *data_v3 = NULL;
|
||||
char written[ISO_TIME_LEN+1];
|
||||
open_file_t *open_file = NULL;
|
||||
double v2_share = 0.0, v3_share = 0.0;
|
||||
FILE *out;
|
||||
int i;
|
||||
char *statsdir = NULL, *filename = NULL, *str = NULL;
|
||||
|
||||
if (!start_of_dirreq_stats_interval)
|
||||
return 0; /* Not initialized. */
|
||||
@@ -989,98 +1098,26 @@ geoip_dirreq_stats_write(time_t now)
|
||||
/* Discard all items in the client history that are too old. */
|
||||
geoip_remove_old_clients(start_of_dirreq_stats_interval);
|
||||
|
||||
/* Generate history string .*/
|
||||
str = geoip_format_dirreq_stats(now);
|
||||
|
||||
/* Write dirreq-stats string to disk. */
|
||||
statsdir = get_datadir_fname("stats");
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
|
||||
log_warn(LD_HIST, "Unable to create stats/ directory!");
|
||||
goto done;
|
||||
}
|
||||
filename = get_datadir_fname2("stats", "dirreq-stats");
|
||||
data_v2 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
|
||||
data_v3 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
|
||||
format_iso_time(written, now);
|
||||
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
|
||||
0600, &open_file);
|
||||
if (!out)
|
||||
goto done;
|
||||
if (fprintf(out, "dirreq-stats-end %s (%d s)\ndirreq-v3-ips %s\n"
|
||||
"dirreq-v2-ips %s\n", written,
|
||||
(unsigned) (now - start_of_dirreq_stats_interval),
|
||||
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
|
||||
goto done;
|
||||
tor_free(data_v2);
|
||||
tor_free(data_v3);
|
||||
if (write_str_to_file(filename, str, 0) < 0)
|
||||
log_warn(LD_HIST, "Unable to write dirreq statistics to disk!");
|
||||
|
||||
data_v2 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
|
||||
data_v3 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
|
||||
if (fprintf(out, "dirreq-v3-reqs %s\ndirreq-v2-reqs %s\n",
|
||||
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
|
||||
goto done;
|
||||
tor_free(data_v2);
|
||||
tor_free(data_v3);
|
||||
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
|
||||
c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
|
||||
});
|
||||
#define RESPONSE_GRANULARITY 8
|
||||
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
|
||||
ns_v2_responses[i] = round_uint32_to_next_multiple_of(
|
||||
ns_v2_responses[i], RESPONSE_GRANULARITY);
|
||||
ns_v3_responses[i] = round_uint32_to_next_multiple_of(
|
||||
ns_v3_responses[i], RESPONSE_GRANULARITY);
|
||||
}
|
||||
#undef RESPONSE_GRANULARITY
|
||||
if (fprintf(out, "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
|
||||
"not-found=%u,not-modified=%u,busy=%u\n",
|
||||
ns_v3_responses[GEOIP_SUCCESS],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
|
||||
ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
|
||||
ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
|
||||
ns_v3_responses[GEOIP_REJECT_BUSY]) < 0)
|
||||
goto done;
|
||||
if (fprintf(out, "dirreq-v2-resp ok=%u,unavailable=%u,"
|
||||
"not-found=%u,not-modified=%u,busy=%u\n",
|
||||
ns_v2_responses[GEOIP_SUCCESS],
|
||||
ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
|
||||
ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
|
||||
ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
|
||||
ns_v2_responses[GEOIP_REJECT_BUSY]) < 0)
|
||||
goto done;
|
||||
memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
|
||||
memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
|
||||
if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
|
||||
if (fprintf(out, "dirreq-v2-share %0.2lf%%\n", v2_share*100) < 0)
|
||||
goto done;
|
||||
if (fprintf(out, "dirreq-v3-share %0.2lf%%\n", v3_share*100) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
|
||||
DIRREQ_DIRECT);
|
||||
data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
|
||||
DIRREQ_DIRECT);
|
||||
if (fprintf(out, "dirreq-v3-direct-dl %s\ndirreq-v2-direct-dl %s\n",
|
||||
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
|
||||
goto done;
|
||||
tor_free(data_v2);
|
||||
tor_free(data_v3);
|
||||
data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
|
||||
DIRREQ_TUNNELED);
|
||||
data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
|
||||
DIRREQ_TUNNELED);
|
||||
if (fprintf(out, "dirreq-v3-tunneled-dl %s\ndirreq-v2-tunneled-dl %s\n",
|
||||
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
|
||||
goto done;
|
||||
|
||||
finish_writing_to_file(open_file);
|
||||
open_file = NULL;
|
||||
|
||||
start_of_dirreq_stats_interval = now;
|
||||
/* Reset measurement interval start. */
|
||||
geoip_reset_dirreq_stats(now);
|
||||
|
||||
done:
|
||||
if (open_file)
|
||||
abort_writing_to_file(open_file);
|
||||
tor_free(filename);
|
||||
tor_free(statsdir);
|
||||
tor_free(data_v2);
|
||||
tor_free(data_v3);
|
||||
tor_free(filename);
|
||||
tor_free(str);
|
||||
return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
|
||||
}
|
||||
|
||||
@@ -1160,8 +1197,8 @@ static char *bridge_stats_extrainfo = NULL;
|
||||
/** Return a newly allocated string holding our bridge usage stats by country
|
||||
* in a format suitable for inclusion in an extrainfo document. Return NULL on
|
||||
* failure. */
|
||||
static char *
|
||||
format_bridge_stats_extrainfo(time_t now)
|
||||
char *
|
||||
geoip_format_bridge_stats(time_t now)
|
||||
{
|
||||
char *out = NULL, *data = NULL;
|
||||
long duration = now - start_of_bridge_stats_interval;
|
||||
@@ -1169,6 +1206,8 @@ format_bridge_stats_extrainfo(time_t now)
|
||||
|
||||
if (duration < 0)
|
||||
return NULL;
|
||||
if (!start_of_bridge_stats_interval)
|
||||
return NULL; /* Not initialized. */
|
||||
|
||||
format_iso_time(written, now);
|
||||
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
|
||||
@@ -1218,7 +1257,7 @@ geoip_bridge_stats_write(time_t now)
|
||||
geoip_remove_old_clients(start_of_bridge_stats_interval);
|
||||
|
||||
/* Generate formatted string */
|
||||
val = format_bridge_stats_extrainfo(now);
|
||||
val = geoip_format_bridge_stats(now);
|
||||
if (val == NULL)
|
||||
goto done;
|
||||
|
||||
@@ -1295,25 +1334,51 @@ geoip_entry_stats_init(time_t now)
|
||||
start_of_entry_stats_interval = now;
|
||||
}
|
||||
|
||||
/** Reset counters for entry stats. */
|
||||
void
|
||||
geoip_reset_entry_stats(time_t now)
|
||||
{
|
||||
client_history_clear();
|
||||
start_of_entry_stats_interval = now;
|
||||
}
|
||||
|
||||
/** Stop collecting entry stats in a way that we can re-start doing so in
|
||||
* geoip_entry_stats_init(). */
|
||||
void
|
||||
geoip_entry_stats_term(void)
|
||||
{
|
||||
client_history_clear();
|
||||
start_of_entry_stats_interval = 0;
|
||||
geoip_reset_entry_stats(0);
|
||||
}
|
||||
|
||||
/** Write entry statistics to $DATADIR/stats/entry-stats and return time
|
||||
* when we would next want to write. */
|
||||
/** Return a newly allocated string containing the entry statistics
|
||||
* until <b>now</b>, or NULL if we're not collecting entry stats. */
|
||||
char *
|
||||
geoip_format_entry_stats(time_t now)
|
||||
{
|
||||
char t[ISO_TIME_LEN+1];
|
||||
char *data = NULL;
|
||||
char *result;
|
||||
|
||||
if (!start_of_entry_stats_interval)
|
||||
return NULL; /* Not initialized. */
|
||||
|
||||
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
|
||||
format_iso_time(t, now);
|
||||
tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
|
||||
t, (unsigned) (now - start_of_entry_stats_interval),
|
||||
data ? data : "");
|
||||
tor_free(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If 24 hours have passed since the beginning of the current entry stats
|
||||
* period, write entry stats to $DATADIR/stats/entry-stats (possibly
|
||||
* overwriting an existing file) and reset counters. Return when we would
|
||||
* next want to write entry stats or 0 if we never want to write. */
|
||||
time_t
|
||||
geoip_entry_stats_write(time_t now)
|
||||
{
|
||||
char *statsdir = NULL, *filename = NULL;
|
||||
char *data = NULL;
|
||||
char written[ISO_TIME_LEN+1];
|
||||
open_file_t *open_file = NULL;
|
||||
FILE *out;
|
||||
char *statsdir = NULL, *filename = NULL, *str = NULL;
|
||||
|
||||
if (!start_of_entry_stats_interval)
|
||||
return 0; /* Not initialized. */
|
||||
@@ -1323,31 +1388,26 @@ geoip_entry_stats_write(time_t now)
|
||||
/* Discard all items in the client history that are too old. */
|
||||
geoip_remove_old_clients(start_of_entry_stats_interval);
|
||||
|
||||
/* Generate history string .*/
|
||||
str = geoip_format_entry_stats(now);
|
||||
|
||||
/* Write entry-stats string to disk. */
|
||||
statsdir = get_datadir_fname("stats");
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
|
||||
log_warn(LD_HIST, "Unable to create stats/ directory!");
|
||||
goto done;
|
||||
}
|
||||
filename = get_datadir_fname2("stats", "entry-stats");
|
||||
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
|
||||
format_iso_time(written, now);
|
||||
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
|
||||
0600, &open_file);
|
||||
if (!out)
|
||||
goto done;
|
||||
if (fprintf(out, "entry-stats-end %s (%u s)\nentry-ips %s\n",
|
||||
written, (unsigned) (now - start_of_entry_stats_interval),
|
||||
data ? data : "") < 0)
|
||||
goto done;
|
||||
if (write_str_to_file(filename, str, 0) < 0)
|
||||
log_warn(LD_HIST, "Unable to write entry statistics to disk!");
|
||||
|
||||
start_of_entry_stats_interval = now;
|
||||
/* Reset measurement interval start. */
|
||||
geoip_reset_entry_stats(now);
|
||||
|
||||
finish_writing_to_file(open_file);
|
||||
open_file = NULL;
|
||||
done:
|
||||
if (open_file)
|
||||
abort_writing_to_file(open_file);
|
||||
tor_free(filename);
|
||||
tor_free(statsdir);
|
||||
tor_free(data);
|
||||
tor_free(filename);
|
||||
tor_free(str);
|
||||
return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,17 @@ void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
|
||||
dirreq_state_t new_state);
|
||||
|
||||
void geoip_dirreq_stats_init(time_t now);
|
||||
void geoip_reset_dirreq_stats(time_t now);
|
||||
char *geoip_format_dirreq_stats(time_t now);
|
||||
time_t geoip_dirreq_stats_write(time_t now);
|
||||
void geoip_dirreq_stats_term(void);
|
||||
void geoip_entry_stats_init(time_t now);
|
||||
time_t geoip_entry_stats_write(time_t now);
|
||||
void geoip_entry_stats_term(void);
|
||||
void geoip_reset_entry_stats(time_t now);
|
||||
char *geoip_format_entry_stats(time_t now);
|
||||
void geoip_bridge_stats_init(time_t now);
|
||||
char *geoip_format_bridge_stats(time_t now);
|
||||
time_t geoip_bridge_stats_write(time_t now);
|
||||
void geoip_bridge_stats_term(void);
|
||||
const char *geoip_get_bridge_stats_extrainfo(time_t);
|
||||
|
||||
+19
-1
@@ -114,6 +114,8 @@ static time_t time_to_check_for_correct_dns = 0;
|
||||
static time_t time_of_last_signewnym = 0;
|
||||
/** Is there a signewnym request we're currently waiting to handle? */
|
||||
static int signewnym_is_pending = 0;
|
||||
/** How many times have we called newnym? */
|
||||
static unsigned newnym_epoch = 0;
|
||||
|
||||
/** Smartlist of all open connections. */
|
||||
static smartlist_t *connection_array = NULL;
|
||||
@@ -152,6 +154,12 @@ int can_complete_circuit=0;
|
||||
* 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.
|
||||
*/
|
||||
int quiet_level = 0;
|
||||
|
||||
/********* END VARIABLES ************/
|
||||
|
||||
/****************************************************************************
|
||||
@@ -290,7 +298,7 @@ connection_unregister_events(connection_t *conn)
|
||||
conn->bufev = NULL;
|
||||
}
|
||||
#endif
|
||||
if (conn->dns_server_port) {
|
||||
if (conn->type == CONN_TYPE_AP_DNS_LISTENER) {
|
||||
dnsserv_close_listener(conn);
|
||||
}
|
||||
}
|
||||
@@ -1038,9 +1046,18 @@ signewnym_impl(time_t now)
|
||||
time_of_last_signewnym = now;
|
||||
signewnym_is_pending = 0;
|
||||
|
||||
++newnym_epoch;
|
||||
|
||||
control_event_signal(SIGNEWNYM);
|
||||
}
|
||||
|
||||
/** Return the number of times that signewnym has been called. */
|
||||
unsigned
|
||||
get_signewnym_epoch(void)
|
||||
{
|
||||
return newnym_epoch;
|
||||
}
|
||||
|
||||
/** Perform regular maintenance tasks. This function gets run once per
|
||||
* second by second_elapsed_callback().
|
||||
*/
|
||||
@@ -2137,6 +2154,7 @@ tor_init(int argc, char *argv[])
|
||||
default:
|
||||
add_temp_log(LOG_NOTICE);
|
||||
}
|
||||
quiet_level = quiet;
|
||||
|
||||
log(LOG_NOTICE, LD_GENERAL, "Tor v%s. This is experimental software. "
|
||||
"Do not rely on it for strong anonymity. (Running on %s)",get_version(),
|
||||
|
||||
@@ -52,6 +52,7 @@ void ip_address_changed(int at_interface);
|
||||
void dns_servers_relaunch_checks(void);
|
||||
|
||||
long get_uptime(void);
|
||||
unsigned get_signewnym_epoch(void);
|
||||
|
||||
void handle_signals(int is_parent);
|
||||
void process_signal(uintptr_t sig);
|
||||
|
||||
@@ -698,14 +698,8 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
|
||||
int ret = options->UseMicrodescriptors;
|
||||
if (ret == -1) {
|
||||
/* UseMicrodescriptors is "auto"; we need to decide: */
|
||||
#if 0
|
||||
/* So we decide that we'll use microdescriptors iff we are not a server */
|
||||
ret = ! server_mode(options);
|
||||
#else
|
||||
/* We don't use microdescs for now: not enough caches are running
|
||||
* 0.2.3.1-alpha */
|
||||
ret = 0;
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2006,13 +2006,6 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
|
||||
tor_memcmp(rs->identity_digest,
|
||||
router->cache_info.identity_digest, DIGEST_LEN),
|
||||
{
|
||||
#if 0
|
||||
/* We have no routerstatus for this router. Clear flags and skip it. */
|
||||
if (!authdir) {
|
||||
if (router->purpose == ROUTER_PURPOSE_GENERAL)
|
||||
router_clear_status_flags(router);
|
||||
}
|
||||
#endif
|
||||
}) {
|
||||
/* We have a routerstatus for this router. */
|
||||
const char *digest = router->cache_info.identity_digest;
|
||||
|
||||
+188
-11
@@ -930,6 +930,11 @@ typedef struct {
|
||||
|
||||
typedef struct buf_t buf_t;
|
||||
typedef struct socks_request_t socks_request_t;
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
#define generic_buffer_t struct evbuffer
|
||||
#else
|
||||
#define generic_buffer_t buf_t
|
||||
#endif
|
||||
|
||||
/* Values for connection_t.magic: used to make sure that downcasts (casts from
|
||||
* connection_t to foo_connection_t) are safe. */
|
||||
@@ -938,6 +943,7 @@ typedef struct socks_request_t socks_request_t;
|
||||
#define EDGE_CONNECTION_MAGIC 0xF0374013u
|
||||
#define DIR_CONNECTION_MAGIC 0x9988ffeeu
|
||||
#define CONTROL_CONNECTION_MAGIC 0x8abc765du
|
||||
#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u
|
||||
|
||||
/** Description of a connection to another host or process, and associated
|
||||
* data.
|
||||
@@ -1043,15 +1049,31 @@ typedef struct connection_t {
|
||||
/** Unique identifier for this connection on this Tor instance. */
|
||||
uint64_t global_identifier;
|
||||
|
||||
/* XXXX023 move this field, and all the listener-only fields (just
|
||||
socket_family, I think), into a new listener_connection_t subtype. */
|
||||
/** Unique ID for measuring tunneled network status requests. */
|
||||
uint64_t dirreq_id;
|
||||
} connection_t;
|
||||
|
||||
typedef struct listener_connection_t {
|
||||
connection_t _base;
|
||||
|
||||
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
|
||||
* to the evdns_server_port it uses to listen to and answer connections. */
|
||||
struct evdns_server_port *dns_server_port;
|
||||
|
||||
/** Unique ID for measuring tunneled network status requests. */
|
||||
uint64_t dirreq_id;
|
||||
} connection_t;
|
||||
/** @name Isolation parameters
|
||||
*
|
||||
* For an AP listener, these fields describe how to isolate streams that
|
||||
* arrive on the listener.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/** The session group for this listener. */
|
||||
int session_group;
|
||||
/** One or more ISO_ flags to describe how to isolate streams. */
|
||||
uint8_t isolation_flags;
|
||||
/**@}*/
|
||||
|
||||
} listener_connection_t;
|
||||
|
||||
/** Stores flags and information related to the portion of a v2 Tor OR
|
||||
* connection handshake that happens after the TLS handshake is finished.
|
||||
@@ -1190,6 +1212,20 @@ typedef struct edge_connection_t {
|
||||
/** What rendezvous service are we querying for? (AP only) */
|
||||
rend_data_t *rend_data;
|
||||
|
||||
/* === Isolation related, AP only. === */
|
||||
/** AP only: based on which factors do we isolate this stream? */
|
||||
uint8_t isolation_flags;
|
||||
/** AP only: what session group is this stream in? */
|
||||
int session_group;
|
||||
/** AP only: The newnym epoch in which we created this connection. */
|
||||
unsigned nym_epoch;
|
||||
/** AP only: The original requested address before we rewrote it. */
|
||||
char *original_dest_address;
|
||||
/* Other fields to isolate on already exist. The ClientAddr is addr. The
|
||||
ClientProtocol is a combination of type and socks_request->
|
||||
socks_version. SocksAuth is socks_request->username/password.
|
||||
DestAddr is in socks_request->address. */
|
||||
|
||||
/** Number of times we've reassigned this application connection to
|
||||
* a new circuit. We keep track because the timeout is longer if we've
|
||||
* already retried several times. */
|
||||
@@ -1232,6 +1268,21 @@ typedef struct edge_connection_t {
|
||||
* NATd connection */
|
||||
unsigned int is_transparent_ap:1;
|
||||
|
||||
/** For AP connections only: Set if this connection's target exit node
|
||||
* allows optimistic data (that is, data sent on this stream before
|
||||
* the exit has sent a CONNECTED cell) and we have chosen to use it.
|
||||
*/
|
||||
unsigned int may_use_optimistic_data : 1;
|
||||
|
||||
/** For AP connections only: buffer for data that we have sent
|
||||
* optimistically, which we might need to re-send if we have to
|
||||
* retry this connection. */
|
||||
generic_buffer_t *pending_optimistic_data;
|
||||
/* For AP connections only: buffer for data that we previously sent
|
||||
* optimistically which we are currently re-sending as we retry this
|
||||
* connection. */
|
||||
generic_buffer_t *sending_optimistic_data;
|
||||
|
||||
/** If this is a DNSPort connection, this field holds the pending DNS
|
||||
* request that we're going to try to answer. */
|
||||
struct evdns_server_request *dns_server_request;
|
||||
@@ -1321,6 +1372,9 @@ static edge_connection_t *TO_EDGE_CONN(connection_t *);
|
||||
/** Convert a connection_t* to an control_connection_t*; assert if the cast is
|
||||
* invalid. */
|
||||
static control_connection_t *TO_CONTROL_CONN(connection_t *);
|
||||
/** Convert a connection_t* to an listener_connection_t*; assert if the cast is
|
||||
* invalid. */
|
||||
static listener_connection_t *TO_LISTENER_CONN(connection_t *);
|
||||
|
||||
static INLINE or_connection_t *TO_OR_CONN(connection_t *c)
|
||||
{
|
||||
@@ -1342,6 +1396,11 @@ static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
|
||||
tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
|
||||
return DOWNCAST(control_connection_t, c);
|
||||
}
|
||||
static INLINE listener_connection_t *TO_LISTENER_CONN(connection_t *c)
|
||||
{
|
||||
tor_assert(c->magic == LISTENER_CONNECTION_MAGIC);
|
||||
return DOWNCAST(listener_connection_t, c);
|
||||
}
|
||||
|
||||
/* Conditional macros to help write code that works whether bufferevents are
|
||||
disabled or not.
|
||||
@@ -1667,6 +1726,9 @@ typedef struct routerstatus_t {
|
||||
/** True iff this router is a version that, if it caches directory info,
|
||||
* we can get microdescriptors from. */
|
||||
unsigned int version_supports_microdesc_cache:1;
|
||||
/** True iff this router is a version that allows DATA cells to arrive on
|
||||
* a stream before it has sent a CONNECTED cell. */
|
||||
unsigned int version_supports_optimistic_data:1;
|
||||
|
||||
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
|
||||
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
|
||||
@@ -2424,6 +2486,55 @@ typedef struct origin_circuit_t {
|
||||
/* XXXX NM This can get re-used after 2**32 circuits. */
|
||||
uint32_t global_identifier;
|
||||
|
||||
/** True if we have associated one stream to this circuit, thereby setting
|
||||
* the isolation paramaters for this circuit. Note that this doesn't
|
||||
* necessarily mean that we've <em>attached</em> any streams to the circuit:
|
||||
* we may only have marked up this circuit during the launch process.
|
||||
*/
|
||||
unsigned int isolation_values_set : 1;
|
||||
/** True iff any stream has <em>ever</em> been attached to this circuit.
|
||||
*
|
||||
* In a better world we could use timestamp_dirty for this, but
|
||||
* timestamp_dirty is far too overloaded at the moment.
|
||||
*/
|
||||
unsigned int isolation_any_streams_attached : 1;
|
||||
|
||||
/** A bitfield of ISO_* flags for every isolation field such that this
|
||||
* circuit has had streams with more than one value for that field
|
||||
* attached to it. */
|
||||
uint8_t isolation_flags_mixed;
|
||||
|
||||
/** @name Isolation parameters
|
||||
*
|
||||
* If any streams have been associated with this circ (isolation_values_set
|
||||
* == 1), and all streams associated with the circuit have had the same
|
||||
* value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these
|
||||
* elements hold the value for that field.
|
||||
*
|
||||
* Note again that "associated" is not the same as "attached": we
|
||||
* preliminarily associate streams with a circuit while the circuit is being
|
||||
* launched, so that we can tell whether we need to launch more circuits.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
uint8_t client_proto_type;
|
||||
uint8_t client_proto_socksver;
|
||||
uint16_t dest_port;
|
||||
tor_addr_t client_addr;
|
||||
char *dest_address;
|
||||
int session_group;
|
||||
unsigned nym_epoch;
|
||||
size_t socks_username_len;
|
||||
uint8_t socks_password_len;
|
||||
/* Note that the next two values are NOT NUL-terminated; see
|
||||
socks_username_len and socks_password_len for their lengths. */
|
||||
char *socks_username;
|
||||
char *socks_password;
|
||||
/** Global identifier for the first stream attached here; used by
|
||||
* ISO_STREAM. */
|
||||
uint64_t associated_isolated_stream_global_id;
|
||||
/**@}*/
|
||||
|
||||
} origin_circuit_t;
|
||||
|
||||
/** An or_circuit_t holds information needed to implement a circuit at an
|
||||
@@ -2542,6 +2653,60 @@ typedef enum invalid_router_usage_t {
|
||||
#define MIN_CONSTRAINED_TCP_BUFFER 2048
|
||||
#define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */
|
||||
|
||||
/** @name Isolation flags
|
||||
|
||||
Ways to isolate client streams
|
||||
|
||||
@{
|
||||
*/
|
||||
/** Isolate based on destination port */
|
||||
#define ISO_DESTPORT (1u<<0)
|
||||
/** Isolate based on destination address */
|
||||
#define ISO_DESTADDR (1u<<1)
|
||||
/** Isolate based on SOCKS authentication */
|
||||
#define ISO_SOCKSAUTH (1u<<2)
|
||||
/** Isolate based on client protocol choice */
|
||||
#define ISO_CLIENTPROTO (1u<<3)
|
||||
/** Isolate based on client address */
|
||||
#define ISO_CLIENTADDR (1u<<4)
|
||||
/** Isolate based on session group (always on). */
|
||||
#define ISO_SESSIONGRP (1u<<5)
|
||||
/** Isolate based on newnym epoch (always on). */
|
||||
#define ISO_NYM_EPOCH (1u<<6)
|
||||
/** Isolate all streams (Internal only). */
|
||||
#define ISO_STREAM (1u<<7)
|
||||
/**@}*/
|
||||
|
||||
/** Default isolation level for ports. */
|
||||
#define ISO_DEFAULT (ISO_CLIENTADDR|ISO_SOCKSAUTH|ISO_SESSIONGRP|ISO_NYM_EPOCH)
|
||||
|
||||
/** Indicates that we haven't yet set a session group on a port_cfg_t. */
|
||||
#define SESSION_GROUP_UNSET -1
|
||||
/** Session group reserved for directory connections */
|
||||
#define SESSION_GROUP_DIRCONN -2
|
||||
/** Session group reserved for resolve requests launched by a controller */
|
||||
#define SESSION_GROUP_CONTROL_RESOLVE -3
|
||||
/** First automatically allocated session group number */
|
||||
#define SESSION_GROUP_FIRST_AUTO -4
|
||||
|
||||
/** Configuration for a single port that we're listening on. */
|
||||
typedef struct port_cfg_t {
|
||||
tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */
|
||||
int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its
|
||||
* own port. */
|
||||
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
|
||||
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
|
||||
|
||||
/* Client port types (socks, dns, trans, natd) only: */
|
||||
uint8_t isolation_flags; /**< Zero or more isolation flags */
|
||||
int session_group; /**< A session group, or -1 if this port is not in a
|
||||
* session group. */
|
||||
|
||||
/* Unix sockets only: */
|
||||
/** Path for an AF_UNIX address */
|
||||
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
|
||||
} port_cfg_t;
|
||||
|
||||
/** A linked list of lines in a config file. */
|
||||
typedef struct config_line_t {
|
||||
char *key;
|
||||
@@ -2637,16 +2802,17 @@ typedef struct {
|
||||
char *User; /**< Name of user to run Tor as. */
|
||||
char *Group; /**< Name of group to run Tor as. */
|
||||
int ORPort; /**< Port to listen on for OR connections. */
|
||||
int SocksPort; /**< Port to listen on for SOCKS connections. */
|
||||
/** Port to listen on for transparent pf/netfilter connections. */
|
||||
int TransPort;
|
||||
int NATDPort; /**< Port to listen on for transparent natd connections. */
|
||||
config_line_t *SocksPort; /**< Ports to listen on for SOCKS connections. */
|
||||
/** Ports to listen on for transparent pf/netfilter connections. */
|
||||
config_line_t *TransPort;
|
||||
config_line_t *NATDPort; /**< Ports to listen on for transparent natd
|
||||
* connections. */
|
||||
int ControlPort; /**< Port to listen on for control connections. */
|
||||
config_line_t *ControlSocket; /**< List of Unix Domain Sockets to listen on
|
||||
* for control connections. */
|
||||
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
|
||||
int DirPort; /**< Port to listen on for directory connections. */
|
||||
int DNSPort; /**< Port to listen on for DNS requests. */
|
||||
config_line_t *DNSPort; /**< Port to listen on for DNS requests. */
|
||||
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
|
||||
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
|
||||
int V1AuthoritativeDir; /**< Boolean: is this an authoritative directory
|
||||
@@ -3108,6 +3274,15 @@ typedef struct {
|
||||
/** Should that file be group-readable? */
|
||||
int ControlPortFileGroupReadable;
|
||||
|
||||
#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024
|
||||
/** Maximum number of non-open general-purpose origin circuits to allow at
|
||||
* once. */
|
||||
int MaxClientCircuitsPending;
|
||||
|
||||
/** If 1, we always send optimistic data when it's supported. If 0, we
|
||||
* never use it. If -1, we do what the consensus says. */
|
||||
int OptimisticData;
|
||||
|
||||
} or_options_t;
|
||||
|
||||
/** Persistent state for an onion router, as saved to disk. */
|
||||
@@ -3214,6 +3389,8 @@ struct socks_request_t {
|
||||
uint8_t auth_type;
|
||||
/** What is this stream's goal? One of the SOCKS_COMMAND_* values */
|
||||
uint8_t command;
|
||||
/** Which kind of listener created this stream? */
|
||||
uint8_t listener_type;
|
||||
size_t replylen; /**< Length of <b>reply</b>. */
|
||||
uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if
|
||||
* we want to specify our own socks reply,
|
||||
@@ -3230,7 +3407,7 @@ struct socks_request_t {
|
||||
unsigned int got_auth : 1; /**< Have we received any authentication data? */
|
||||
|
||||
/** Number of bytes in username; 0 if username is NULL */
|
||||
uint8_t usernamelen;
|
||||
size_t usernamelen;
|
||||
/** Number of bytes in password; 0 if password is NULL */
|
||||
uint8_t passwordlen;
|
||||
/** The negotiated username value if any (for socks5), or the entire
|
||||
|
||||
+42
-2
@@ -944,6 +944,12 @@ connection_edge_process_relay_cell_not_open(
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* This is definitely a success, so forget about any pending data we
|
||||
* had sent. */
|
||||
if (conn->pending_optimistic_data) {
|
||||
generic_buffer_free(conn->pending_optimistic_data);
|
||||
conn->pending_optimistic_data = NULL;
|
||||
}
|
||||
|
||||
/* handle anything that might have queued */
|
||||
if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) {
|
||||
@@ -1343,6 +1349,10 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
|
||||
char payload[CELL_PAYLOAD_SIZE];
|
||||
circuit_t *circ;
|
||||
unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT;
|
||||
int sending_from_optimistic = 0;
|
||||
const int sending_optimistically =
|
||||
conn->_base.type == CONN_TYPE_AP &&
|
||||
conn->_base.state != AP_CONN_STATE_OPEN;
|
||||
|
||||
tor_assert(conn);
|
||||
|
||||
@@ -1375,7 +1385,18 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
|
||||
sending_from_optimistic = conn->sending_optimistic_data != NULL;
|
||||
|
||||
if (PREDICT_UNLIKELY(sending_from_optimistic)) {
|
||||
amount_to_process = generic_buffer_len(conn->sending_optimistic_data);
|
||||
if (PREDICT_UNLIKELY(!amount_to_process)) {
|
||||
log_warn(LD_BUG, "sending_optimistic_data was non-NULL but empty");
|
||||
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
|
||||
sending_from_optimistic = 0;
|
||||
}
|
||||
} else {
|
||||
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
|
||||
}
|
||||
|
||||
if (!amount_to_process)
|
||||
return 0;
|
||||
@@ -1391,11 +1412,30 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
|
||||
stats_n_data_bytes_packaged += length;
|
||||
stats_n_data_cells_packaged += 1;
|
||||
|
||||
connection_fetch_from_buf(payload, length, TO_CONN(conn));
|
||||
if (PREDICT_UNLIKELY(sending_from_optimistic)) {
|
||||
/* XXX023 We could be more efficient here by sometimes packing
|
||||
* previously-sent optimistic data in the same cell with data
|
||||
* from the inbuf. */
|
||||
generic_buffer_get(conn->sending_optimistic_data, payload, length);
|
||||
if (!generic_buffer_len(conn->sending_optimistic_data)) {
|
||||
generic_buffer_free(conn->sending_optimistic_data);
|
||||
conn->sending_optimistic_data = NULL;
|
||||
}
|
||||
} else {
|
||||
connection_fetch_from_buf(payload, length, TO_CONN(conn));
|
||||
}
|
||||
|
||||
log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
|
||||
(int)length, (int)connection_get_inbuf_len(TO_CONN(conn)));
|
||||
|
||||
if (sending_optimistically && !sending_from_optimistic) {
|
||||
/* This is new optimistic data; remember it in case we need to detach and
|
||||
retry */
|
||||
if (!conn->pending_optimistic_data)
|
||||
conn->pending_optimistic_data = generic_buffer_new();
|
||||
generic_buffer_add(conn->pending_optimistic_data, payload, length);
|
||||
}
|
||||
|
||||
if (connection_edge_send_command(conn, RELAY_COMMAND_DATA,
|
||||
payload, length) < 0 )
|
||||
/* circuit got marked for close, don't continue, don't need to mark conn */
|
||||
|
||||
+142
-98
@@ -2364,23 +2364,41 @@ typedef struct circ_buffer_stats_t {
|
||||
/** List of circ_buffer_stats_t. */
|
||||
static smartlist_t *circuits_for_buffer_stats = NULL;
|
||||
|
||||
/** Remember cell statistics <b>mean_num_cells_in_queue</b>,
|
||||
* <b>mean_time_cells_in_queue</b>, and <b>processed_cells</b> of a
|
||||
* circuit. */
|
||||
void
|
||||
rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
|
||||
double mean_time_cells_in_queue, uint32_t processed_cells)
|
||||
{
|
||||
circ_buffer_stats_t *stat;
|
||||
if (!start_of_buffer_stats_interval)
|
||||
return; /* Not initialized. */
|
||||
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
|
||||
stat->mean_num_cells_in_queue = mean_num_cells_in_queue;
|
||||
stat->mean_time_cells_in_queue = mean_time_cells_in_queue;
|
||||
stat->processed_cells = processed_cells;
|
||||
if (!circuits_for_buffer_stats)
|
||||
circuits_for_buffer_stats = smartlist_create();
|
||||
smartlist_add(circuits_for_buffer_stats, stat);
|
||||
}
|
||||
|
||||
/** Remember cell statistics for circuit <b>circ</b> at time
|
||||
* <b>end_of_interval</b> and reset cell counters in case the circuit
|
||||
* remains open in the next measurement interval. */
|
||||
void
|
||||
rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
|
||||
{
|
||||
circ_buffer_stats_t *stat;
|
||||
time_t start_of_interval;
|
||||
int interval_length;
|
||||
or_circuit_t *orcirc;
|
||||
double mean_num_cells_in_queue, mean_time_cells_in_queue;
|
||||
uint32_t processed_cells;
|
||||
if (CIRCUIT_IS_ORIGIN(circ))
|
||||
return;
|
||||
orcirc = TO_OR_CIRCUIT(circ);
|
||||
if (!orcirc->processed_cells)
|
||||
return;
|
||||
if (!circuits_for_buffer_stats)
|
||||
circuits_for_buffer_stats = smartlist_create();
|
||||
start_of_interval = (circ->timestamp_created.tv_sec >
|
||||
start_of_buffer_stats_interval) ?
|
||||
circ->timestamp_created.tv_sec :
|
||||
@@ -2388,17 +2406,18 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
|
||||
interval_length = (int) (end_of_interval - start_of_interval);
|
||||
if (interval_length <= 0)
|
||||
return;
|
||||
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
|
||||
stat->processed_cells = orcirc->processed_cells;
|
||||
processed_cells = orcirc->processed_cells;
|
||||
/* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
|
||||
stat->mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
|
||||
mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
|
||||
(double) interval_length / 1000.0 / 2.0;
|
||||
stat->mean_time_cells_in_queue =
|
||||
mean_time_cells_in_queue =
|
||||
(double) orcirc->total_cell_waiting_time /
|
||||
(double) orcirc->processed_cells;
|
||||
smartlist_add(circuits_for_buffer_stats, stat);
|
||||
orcirc->total_cell_waiting_time = 0;
|
||||
orcirc->processed_cells = 0;
|
||||
rep_hist_add_buffer_stats(mean_num_cells_in_queue,
|
||||
mean_time_cells_in_queue,
|
||||
processed_cells);
|
||||
}
|
||||
|
||||
/** Sorting helper: return -1, 1, or 0 based on comparison of two
|
||||
@@ -2420,135 +2439,160 @@ _buffer_stats_compare_entries(const void **_a, const void **_b)
|
||||
void
|
||||
rep_hist_buffer_stats_term(void)
|
||||
{
|
||||
start_of_buffer_stats_interval = 0;
|
||||
rep_hist_reset_buffer_stats(0);
|
||||
}
|
||||
|
||||
/** Clear history of circuit statistics and set the measurement interval
|
||||
* start to <b>now</b>. */
|
||||
void
|
||||
rep_hist_reset_buffer_stats(time_t now)
|
||||
{
|
||||
if (!circuits_for_buffer_stats)
|
||||
circuits_for_buffer_stats = smartlist_create();
|
||||
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
|
||||
stat, tor_free(stat));
|
||||
smartlist_clear(circuits_for_buffer_stats);
|
||||
start_of_buffer_stats_interval = now;
|
||||
}
|
||||
|
||||
/** Write buffer statistics to $DATADIR/stats/buffer-stats and return when
|
||||
* we would next want to write exit stats. */
|
||||
time_t
|
||||
rep_hist_buffer_stats_write(time_t now)
|
||||
/** Return a newly allocated string containing the buffer statistics until
|
||||
* <b>now</b>, or NULL if we're not collecting buffer stats. */
|
||||
char *
|
||||
rep_hist_format_buffer_stats(time_t now)
|
||||
{
|
||||
char *statsdir = NULL, *filename = NULL;
|
||||
char written[ISO_TIME_LEN+1];
|
||||
open_file_t *open_file = NULL;
|
||||
FILE *out;
|
||||
#define SHARES 10
|
||||
int processed_cells[SHARES], circs_in_share[SHARES],
|
||||
number_of_circuits, i;
|
||||
double queued_cells[SHARES], time_in_queue[SHARES];
|
||||
smartlist_t *str_build = NULL;
|
||||
char *str = NULL, *buf = NULL;
|
||||
circuit_t *circ;
|
||||
char *buf = NULL;
|
||||
smartlist_t *processed_cells_strings, *queued_cells_strings,
|
||||
*time_in_queue_strings;
|
||||
char *processed_cells_string, *queued_cells_string,
|
||||
*time_in_queue_string;
|
||||
char t[ISO_TIME_LEN+1];
|
||||
char *result;
|
||||
|
||||
if (!start_of_buffer_stats_interval)
|
||||
return 0; /* Not initialized. */
|
||||
if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
|
||||
goto done; /* Not ready to write */
|
||||
return NULL; /* Not initialized. */
|
||||
|
||||
str_build = smartlist_create();
|
||||
|
||||
/* add current circuits to stats */
|
||||
for (circ = _circuit_get_global_list(); circ; circ = circ->next)
|
||||
rep_hist_buffer_stats_add_circ(circ, now);
|
||||
/* calculate deciles */
|
||||
/* Calculate deciles if we saw at least one circuit. */
|
||||
memset(processed_cells, 0, SHARES * sizeof(int));
|
||||
memset(circs_in_share, 0, SHARES * sizeof(int));
|
||||
memset(queued_cells, 0, SHARES * sizeof(double));
|
||||
memset(time_in_queue, 0, SHARES * sizeof(double));
|
||||
if (!circuits_for_buffer_stats)
|
||||
circuits_for_buffer_stats = smartlist_create();
|
||||
smartlist_sort(circuits_for_buffer_stats,
|
||||
_buffer_stats_compare_entries);
|
||||
number_of_circuits = smartlist_len(circuits_for_buffer_stats);
|
||||
if (number_of_circuits < 1) {
|
||||
log_info(LD_HIST, "Attempt to write cell statistics to disk failed. "
|
||||
"We haven't seen a single circuit to report about.");
|
||||
goto done;
|
||||
if (number_of_circuits > 0) {
|
||||
smartlist_sort(circuits_for_buffer_stats,
|
||||
_buffer_stats_compare_entries);
|
||||
i = 0;
|
||||
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
|
||||
circ_buffer_stats_t *, stat)
|
||||
{
|
||||
int share = i++ * SHARES / number_of_circuits;
|
||||
processed_cells[share] += stat->processed_cells;
|
||||
queued_cells[share] += stat->mean_num_cells_in_queue;
|
||||
time_in_queue[share] += stat->mean_time_cells_in_queue;
|
||||
circs_in_share[share]++;
|
||||
}
|
||||
SMARTLIST_FOREACH_END(stat);
|
||||
}
|
||||
i = 0;
|
||||
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
|
||||
circ_buffer_stats_t *, stat)
|
||||
{
|
||||
int share = i++ * SHARES / number_of_circuits;
|
||||
processed_cells[share] += stat->processed_cells;
|
||||
queued_cells[share] += stat->mean_num_cells_in_queue;
|
||||
time_in_queue[share] += stat->mean_time_cells_in_queue;
|
||||
circs_in_share[share]++;
|
||||
}
|
||||
SMARTLIST_FOREACH_END(stat);
|
||||
/* clear buffer stats history */
|
||||
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
|
||||
stat, tor_free(stat));
|
||||
smartlist_clear(circuits_for_buffer_stats);
|
||||
/* write to file */
|
||||
statsdir = get_datadir_fname("stats");
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
|
||||
goto done;
|
||||
filename = get_datadir_fname2("stats", "buffer-stats");
|
||||
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
|
||||
0600, &open_file);
|
||||
if (!out)
|
||||
goto done;
|
||||
format_iso_time(written, now);
|
||||
if (fprintf(out, "cell-stats-end %s (%d s)\n", written,
|
||||
(unsigned) (now - start_of_buffer_stats_interval)) < 0)
|
||||
goto done;
|
||||
|
||||
/* Write deciles to strings. */
|
||||
processed_cells_strings = smartlist_create();
|
||||
queued_cells_strings = smartlist_create();
|
||||
time_in_queue_strings = smartlist_create();
|
||||
for (i = 0; i < SHARES; i++) {
|
||||
tor_asprintf(&buf,"%d", !circs_in_share[i] ? 0 :
|
||||
processed_cells[i] / circs_in_share[i]);
|
||||
smartlist_add(str_build, buf);
|
||||
smartlist_add(processed_cells_strings, buf);
|
||||
}
|
||||
str = smartlist_join_strings(str_build, ",", 0, NULL);
|
||||
if (fprintf(out, "cell-processed-cells %s\n", str) < 0)
|
||||
goto done;
|
||||
tor_free(str);
|
||||
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
||||
smartlist_clear(str_build);
|
||||
for (i = 0; i < SHARES; i++) {
|
||||
tor_asprintf(&buf, "%.2f", circs_in_share[i] == 0 ? 0.0 :
|
||||
queued_cells[i] / (double) circs_in_share[i]);
|
||||
smartlist_add(str_build, buf);
|
||||
smartlist_add(queued_cells_strings, buf);
|
||||
}
|
||||
str = smartlist_join_strings(str_build, ",", 0, NULL);
|
||||
if (fprintf(out, "cell-queued-cells %s\n", str) < 0)
|
||||
goto done;
|
||||
tor_free(str);
|
||||
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
||||
smartlist_clear(str_build);
|
||||
for (i = 0; i < SHARES; i++) {
|
||||
tor_asprintf(&buf, "%.0f", circs_in_share[i] == 0 ? 0.0 :
|
||||
time_in_queue[i] / (double) circs_in_share[i]);
|
||||
smartlist_add(str_build, buf);
|
||||
smartlist_add(time_in_queue_strings, buf);
|
||||
}
|
||||
str = smartlist_join_strings(str_build, ",", 0, NULL);
|
||||
if (fprintf(out, "cell-time-in-queue %s\n", str) < 0)
|
||||
|
||||
/* Join all observations in single strings. */
|
||||
processed_cells_string = smartlist_join_strings(processed_cells_strings,
|
||||
",", 0, NULL);
|
||||
queued_cells_string = smartlist_join_strings(queued_cells_strings,
|
||||
",", 0, NULL);
|
||||
time_in_queue_string = smartlist_join_strings(time_in_queue_strings,
|
||||
",", 0, NULL);
|
||||
SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp));
|
||||
SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp));
|
||||
SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp));
|
||||
smartlist_free(processed_cells_strings);
|
||||
smartlist_free(queued_cells_strings);
|
||||
smartlist_free(time_in_queue_strings);
|
||||
|
||||
/* Put everything together. */
|
||||
format_iso_time(t, now);
|
||||
tor_asprintf(&result, "cell-stats-end %s (%d s)\n"
|
||||
"cell-processed-cells %s\n"
|
||||
"cell-queued-cells %s\n"
|
||||
"cell-time-in-queue %s\n"
|
||||
"cell-circuits-per-decile %d\n",
|
||||
t, (unsigned) (now - start_of_buffer_stats_interval),
|
||||
processed_cells_string,
|
||||
queued_cells_string,
|
||||
time_in_queue_string,
|
||||
(number_of_circuits + SHARES - 1) / SHARES);
|
||||
tor_free(processed_cells_string);
|
||||
tor_free(queued_cells_string);
|
||||
tor_free(time_in_queue_string);
|
||||
return result;
|
||||
#undef SHARES
|
||||
}
|
||||
|
||||
/** If 24 hours have passed since the beginning of the current buffer
|
||||
* stats period, write buffer stats to $DATADIR/stats/buffer-stats
|
||||
* (possibly overwriting an existing file) and reset counters. Return
|
||||
* when we would next want to write buffer stats or 0 if we never want to
|
||||
* write. */
|
||||
time_t
|
||||
rep_hist_buffer_stats_write(time_t now)
|
||||
{
|
||||
circuit_t *circ;
|
||||
char *statsdir = NULL, *filename = NULL, *str = NULL;
|
||||
|
||||
if (!start_of_buffer_stats_interval)
|
||||
return 0; /* Not initialized. */
|
||||
if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
|
||||
goto done; /* Not ready to write */
|
||||
|
||||
/* Add open circuits to the history. */
|
||||
for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
|
||||
rep_hist_buffer_stats_add_circ(circ, now);
|
||||
}
|
||||
|
||||
/* Generate history string. */
|
||||
str = rep_hist_format_buffer_stats(now);
|
||||
|
||||
/* Reset both buffer history and counters of open circuits. */
|
||||
rep_hist_reset_buffer_stats(now);
|
||||
|
||||
/* Try to write to disk. */
|
||||
statsdir = get_datadir_fname("stats");
|
||||
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
|
||||
log_warn(LD_HIST, "Unable to create stats/ directory!");
|
||||
goto done;
|
||||
tor_free(str);
|
||||
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
||||
smartlist_free(str_build);
|
||||
str_build = NULL;
|
||||
if (fprintf(out, "cell-circuits-per-decile %d\n",
|
||||
(number_of_circuits + SHARES - 1) / SHARES) < 0)
|
||||
goto done;
|
||||
finish_writing_to_file(open_file);
|
||||
open_file = NULL;
|
||||
start_of_buffer_stats_interval = now;
|
||||
}
|
||||
filename = get_datadir_fname2("stats", "buffer-stats");
|
||||
if (write_str_to_file(filename, str, 0) < 0)
|
||||
log_warn(LD_HIST, "Unable to write buffer stats to disk!");
|
||||
|
||||
done:
|
||||
if (open_file)
|
||||
abort_writing_to_file(open_file);
|
||||
tor_free(str);
|
||||
tor_free(filename);
|
||||
tor_free(statsdir);
|
||||
if (str_build) {
|
||||
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
|
||||
smartlist_free(str_build);
|
||||
}
|
||||
tor_free(str);
|
||||
#undef SHARES
|
||||
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ void rep_hist_buffer_stats_add_circ(circuit_t *circ,
|
||||
time_t end_of_interval);
|
||||
time_t rep_hist_buffer_stats_write(time_t now);
|
||||
void rep_hist_buffer_stats_term(void);
|
||||
void rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
|
||||
double mean_time_cells_in_queue, uint32_t processed_cells);
|
||||
char *rep_hist_format_buffer_stats(time_t now);
|
||||
void rep_hist_reset_buffer_stats(time_t now);
|
||||
|
||||
void rep_hist_conn_stats_init(time_t now);
|
||||
void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
|
||||
|
||||
+3
-5
@@ -1116,14 +1116,12 @@ set_server_advertised(int s)
|
||||
server_is_advertised = s;
|
||||
}
|
||||
|
||||
/** Return true iff we are trying to be a socks proxy. */
|
||||
/** Return true iff we are trying to proxy client connections. */
|
||||
int
|
||||
proxy_mode(const or_options_t *options)
|
||||
{
|
||||
return (options->SocksPort != 0 ||
|
||||
options->TransPort != 0 ||
|
||||
options->NATDPort != 0 ||
|
||||
options->DNSPort != 0);
|
||||
(void)options;
|
||||
return smartlist_len(get_configured_client_ports()) > 0;
|
||||
}
|
||||
|
||||
/** Decide if we're a publishable server. We are a publishable server if:
|
||||
|
||||
@@ -2092,6 +2092,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
rs->version_supports_extrainfo_upload = 1;
|
||||
rs->version_supports_conditional_consensus = 1;
|
||||
rs->version_supports_microdesc_cache = 1;
|
||||
rs->version_supports_optimistic_data = 1;
|
||||
} else {
|
||||
rs->version_supports_begindir =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
|
||||
@@ -2109,6 +2110,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
*/
|
||||
rs->version_supports_microdesc_cache =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha");
|
||||
rs->version_supports_optimistic_data =
|
||||
tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
|
||||
}
|
||||
if (vote_rs) {
|
||||
vote_rs->version = tor_strdup(tok->args[0]);
|
||||
|
||||
+295
-1
@@ -569,6 +569,71 @@ test_socks_5_auth_before_negotiation(void *ptr)
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_buffer_copy(void *arg)
|
||||
{
|
||||
generic_buffer_t *buf=NULL, *buf2=NULL;
|
||||
const char *s;
|
||||
size_t len;
|
||||
char b[256];
|
||||
int i;
|
||||
(void)arg;
|
||||
|
||||
buf = generic_buffer_new();
|
||||
tt_assert(buf);
|
||||
|
||||
/* Copy an empty buffer. */
|
||||
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
|
||||
tt_assert(buf2);
|
||||
tt_int_op(0, ==, generic_buffer_len(buf2));
|
||||
|
||||
/* Now try with a short buffer. */
|
||||
s = "And now comes an act of enormous enormance!";
|
||||
len = strlen(s);
|
||||
generic_buffer_add(buf, s, len);
|
||||
tt_int_op(len, ==, generic_buffer_len(buf));
|
||||
/* Add junk to buf2 so we can test replacing.*/
|
||||
generic_buffer_add(buf2, "BLARG", 5);
|
||||
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
|
||||
tt_int_op(len, ==, generic_buffer_len(buf2));
|
||||
generic_buffer_get(buf2, b, len);
|
||||
test_mem_op(b, ==, s, len);
|
||||
/* Now free buf2 and retry so we can test allocating */
|
||||
generic_buffer_free(buf2);
|
||||
buf2 = NULL;
|
||||
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
|
||||
tt_int_op(len, ==, generic_buffer_len(buf2));
|
||||
generic_buffer_get(buf2, b, len);
|
||||
test_mem_op(b, ==, s, len);
|
||||
/* Clear buf for next test */
|
||||
generic_buffer_get(buf, b, len);
|
||||
tt_int_op(generic_buffer_len(buf),==,0);
|
||||
|
||||
/* Okay, now let's try a bigger buffer. */
|
||||
s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
|
||||
"esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
|
||||
"fugiat quo voluptas nulla pariatur?";
|
||||
len = strlen(s);
|
||||
for (i = 0; i < 256; ++i) {
|
||||
b[0]=i;
|
||||
generic_buffer_add(buf, b, 1);
|
||||
generic_buffer_add(buf, s, len);
|
||||
}
|
||||
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
|
||||
tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
|
||||
for (i = 0; i < 256; ++i) {
|
||||
generic_buffer_get(buf2, b, len+1);
|
||||
tt_int_op((unsigned char)b[0],==,i);
|
||||
test_mem_op(b+1, ==, s, len);
|
||||
}
|
||||
|
||||
done:
|
||||
if (buf)
|
||||
generic_buffer_free(buf);
|
||||
if (buf2)
|
||||
generic_buffer_free(buf2);
|
||||
}
|
||||
|
||||
/** Run unit tests for buffers.c */
|
||||
static void
|
||||
test_buffers(void)
|
||||
@@ -1416,8 +1481,73 @@ static void
|
||||
test_geoip(void)
|
||||
{
|
||||
int i, j;
|
||||
time_t now = time(NULL);
|
||||
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
|
||||
char *s = NULL;
|
||||
const char *bridge_stats_1 =
|
||||
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"bridge-ips zz=24,xy=8\n",
|
||||
*dirreq_stats_1 =
|
||||
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"dirreq-v3-ips ab=8\n"
|
||||
"dirreq-v2-ips \n"
|
||||
"dirreq-v3-reqs ab=8\n"
|
||||
"dirreq-v2-reqs \n"
|
||||
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
|
||||
"not-modified=0,busy=0\n"
|
||||
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
|
||||
"busy=0\n"
|
||||
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
|
||||
*dirreq_stats_2 =
|
||||
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"dirreq-v3-ips \n"
|
||||
"dirreq-v2-ips \n"
|
||||
"dirreq-v3-reqs \n"
|
||||
"dirreq-v2-reqs \n"
|
||||
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
|
||||
"not-modified=0,busy=0\n"
|
||||
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
|
||||
"busy=0\n"
|
||||
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
|
||||
*dirreq_stats_3 =
|
||||
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"dirreq-v3-ips \n"
|
||||
"dirreq-v2-ips \n"
|
||||
"dirreq-v3-reqs \n"
|
||||
"dirreq-v2-reqs \n"
|
||||
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
|
||||
"not-modified=0,busy=0\n"
|
||||
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
|
||||
"busy=0\n"
|
||||
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
|
||||
*dirreq_stats_4 =
|
||||
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"dirreq-v3-ips \n"
|
||||
"dirreq-v2-ips \n"
|
||||
"dirreq-v3-reqs \n"
|
||||
"dirreq-v2-reqs \n"
|
||||
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
|
||||
"not-modified=0,busy=0\n"
|
||||
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
|
||||
"busy=0\n"
|
||||
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
|
||||
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n"
|
||||
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
|
||||
*entry_stats_1 =
|
||||
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"entry-ips ab=8\n",
|
||||
*entry_stats_2 =
|
||||
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"entry-ips \n";
|
||||
|
||||
/* Populate the DB a bit. Add these in order, since we can't do the final
|
||||
* 'sort' step. These aren't very good IP addresses, but they're perfectly
|
||||
@@ -1467,6 +1597,114 @@ test_geoip(void)
|
||||
test_assert(s);
|
||||
test_streq("zz=24,xy=8", s);
|
||||
|
||||
/* Start testing bridge statistics by making sure that we don't output
|
||||
* bridge stats without initializing them. */
|
||||
s = geoip_format_bridge_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Initialize stats and generate the bridge-stats history string out of
|
||||
* the connecting clients added above. */
|
||||
geoip_bridge_stats_init(now);
|
||||
s = geoip_format_bridge_stats(now + 86400);
|
||||
test_streq(bridge_stats_1, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Stop collecting bridge stats and make sure we don't write a history
|
||||
* string anymore. */
|
||||
geoip_bridge_stats_term();
|
||||
s = geoip_format_bridge_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Stop being a bridge and start being a directory mirror that gathers
|
||||
* directory request statistics. */
|
||||
geoip_bridge_stats_term();
|
||||
get_options_mutable()->BridgeRelay = 0;
|
||||
get_options_mutable()->BridgeRecordUsageByCountry = 0;
|
||||
get_options_mutable()->DirReqStatistics = 1;
|
||||
|
||||
/* Start testing dirreq statistics by making sure that we don't collect
|
||||
* dirreq stats without initializing them. */
|
||||
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Initialize stats, note one connecting client, and generate the
|
||||
* dirreq-stats history string. */
|
||||
geoip_dirreq_stats_init(now);
|
||||
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_streq(dirreq_stats_1, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Stop collecting stats, add another connecting client, and ensure we
|
||||
* don't generate a history string. */
|
||||
geoip_dirreq_stats_term();
|
||||
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 101, now);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Re-start stats, add a connecting client, reset stats, and make sure
|
||||
* that we get an all empty history string. */
|
||||
geoip_dirreq_stats_init(now);
|
||||
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
|
||||
geoip_reset_dirreq_stats(now);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_streq(dirreq_stats_2, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Note a successful network status response and make sure that it
|
||||
* appears in the history string. */
|
||||
geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_streq(dirreq_stats_3, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Start a tunneled directory request. */
|
||||
geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS,
|
||||
DIRREQ_TUNNELED);
|
||||
s = geoip_format_dirreq_stats(now + 86400);
|
||||
test_streq(dirreq_stats_4, s);
|
||||
|
||||
/* Stop collecting directory request statistics and start gathering
|
||||
* entry stats. */
|
||||
geoip_dirreq_stats_term();
|
||||
get_options_mutable()->DirReqStatistics = 0;
|
||||
get_options_mutable()->EntryStatistics = 1;
|
||||
|
||||
/* Start testing entry statistics by making sure that we don't collect
|
||||
* anything without initializing entry stats. */
|
||||
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
|
||||
s = geoip_format_entry_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Initialize stats, note one connecting client, and generate the
|
||||
* entry-stats history string. */
|
||||
geoip_entry_stats_init(now);
|
||||
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
|
||||
s = geoip_format_entry_stats(now + 86400);
|
||||
test_streq(entry_stats_1, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Stop collecting stats, add another connecting client, and ensure we
|
||||
* don't generate a history string. */
|
||||
geoip_entry_stats_term();
|
||||
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 101, now);
|
||||
s = geoip_format_entry_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Re-start stats, add a connecting client, reset stats, and make sure
|
||||
* that we get an all empty history string. */
|
||||
geoip_entry_stats_init(now);
|
||||
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
|
||||
geoip_reset_entry_stats(now);
|
||||
s = geoip_format_entry_stats(now + 86400);
|
||||
test_streq(entry_stats_2, s);
|
||||
tor_free(s);
|
||||
|
||||
/* Stop collecting entry statistics. */
|
||||
geoip_entry_stats_term();
|
||||
get_options_mutable()->EntryStatistics = 0;
|
||||
|
||||
done:
|
||||
tor_free(s);
|
||||
}
|
||||
@@ -1570,6 +1808,61 @@ test_stats(void)
|
||||
rep_hist_reset_conn_stats(now);
|
||||
s = rep_hist_format_conn_stats(now + 86400);
|
||||
test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n", s);
|
||||
tor_free(s);
|
||||
|
||||
/* Continue with testing buffer statistics; we shouldn't collect buffer
|
||||
* stats without initializing them. */
|
||||
rep_hist_add_buffer_stats(2.0, 2.0, 20);
|
||||
s = rep_hist_format_buffer_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Initialize stats, add statistics for a single circuit, and generate
|
||||
* the history string. */
|
||||
rep_hist_buffer_stats_init(now);
|
||||
rep_hist_add_buffer_stats(2.0, 2.0, 20);
|
||||
s = rep_hist_format_buffer_stats(now + 86400);
|
||||
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
|
||||
"cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
|
||||
"0.00,0.00\n"
|
||||
"cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
|
||||
"cell-circuits-per-decile 1\n", s);
|
||||
tor_free(s);
|
||||
|
||||
/* Add nineteen more circuit statistics to the one that's already in the
|
||||
* history to see that the math works correctly. */
|
||||
for (i = 21; i < 30; i++)
|
||||
rep_hist_add_buffer_stats(2.0, 2.0, i);
|
||||
for (i = 20; i < 30; i++)
|
||||
rep_hist_add_buffer_stats(3.5, 3.5, i);
|
||||
s = rep_hist_format_buffer_stats(now + 86400);
|
||||
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
|
||||
"cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
|
||||
"2.75,2.75\n"
|
||||
"cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
|
||||
"cell-circuits-per-decile 2\n", s);
|
||||
tor_free(s);
|
||||
|
||||
/* Stop collecting stats, add statistics for one circuit, and ensure we
|
||||
* don't generate a history string. */
|
||||
rep_hist_buffer_stats_term();
|
||||
rep_hist_add_buffer_stats(2.0, 2.0, 20);
|
||||
s = rep_hist_format_buffer_stats(now + 86400);
|
||||
test_assert(!s);
|
||||
|
||||
/* Re-start stats, add statistics for one circuit, reset stats, and make
|
||||
* sure that the history has all zeros. */
|
||||
rep_hist_buffer_stats_init(now);
|
||||
rep_hist_add_buffer_stats(2.0, 2.0, 20);
|
||||
rep_hist_reset_buffer_stats(now);
|
||||
s = rep_hist_format_buffer_stats(now + 86400);
|
||||
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
|
||||
"cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
|
||||
"cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
|
||||
"0.00,0.00\n"
|
||||
"cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
|
||||
"cell-circuits-per-decile 0\n", s);
|
||||
|
||||
done:
|
||||
tor_free(s);
|
||||
@@ -1612,6 +1905,7 @@ const struct testcase_setup_t legacy_setup = {
|
||||
|
||||
static struct testcase_t test_array[] = {
|
||||
ENT(buffers),
|
||||
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
|
||||
ENT(onion_handshake),
|
||||
ENT(circuit_timeout),
|
||||
ENT(policies),
|
||||
|
||||
@@ -34,5 +34,5 @@ miniupnpc_cppflags =
|
||||
endif
|
||||
|
||||
tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
|
||||
tor_fw_helper_LDADD = $(nat_pmp_ldadd) $(miniupnpc_ldadd) ../../common/libor.a @TOR_LIB_WS32@
|
||||
tor_fw_helper_LDADD = ../../common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) @TOR_LIB_WS32@
|
||||
tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H
|
||||
|
||||
@@ -234,3 +235,12 @@
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "0.2.3.2-alpha-dev"
|
||||
|
||||
|
||||
|
||||
#define HAVE_STRUCT_SOCKADDR_IN6
|
||||
#define HAVE_STRUCT_IN6_ADDR
|
||||
#define RSHIFT_DOES_SIGN_EXTEND
|
||||
#define FLEXIBLE_ARRAY_MEMBER 0
|
||||
#define HAVE_EVENT2_EVENT_H
|
||||
#define SHARE_DATADIR ""
|
||||
|
||||
Reference in New Issue
Block a user