diff options
210 files changed, 5273 insertions, 1434 deletions
diff --git a/.gitignore b/.gitignore index e48918d32c..201d04da66 100644 --- a/.gitignore +++ b/.gitignore @@ -128,10 +128,13 @@ /src/common/Makefile.in /src/common/common_sha1.i /src/common/libor.a +/src/common/libor-testing.a /src/common/libor.lib /src/common/libor-crypto.a +/src/common/libor-crypto-testing.a /src/common/libor-crypto.lib /src/common/libor-event.a +/src/common/libor-event-testing.a /src/common/libor-event.lib /src/common/libcurve25519_donna.a /src/common/libcurve25519_donna.lib @@ -149,7 +152,10 @@ /src/or/or_sha1.i /src/or/tor /src/or/tor.exe +/src/or/tor-cov +/src/or/tor-cov.exe /src/or/libtor.a +/src/or/libtor-testing.a /src/or/libtor.lib # /src/test @@ -1,3 +1,495 @@ +Changes in version 0.2.4.14-alpha - 2013-06-18 + Tor 0.2.4.14-alpha fixes a pair of client guard enumeration problems + present in 0.2.4.13-alpha. + + o Major bugfixes: + - When we have too much memory queued in circuits (according to a new + MaxMemInCellQueues option), close the circuits consuming the most + memory. This prevents us from running out of memory as a relay if + circuits fill up faster than they can be drained. Fixes bug 9063; + bugfix on the 54th commit of Tor. This bug is a further fix beyond + bug 6252, whose fix was merged into 0.2.3.21-rc. + + This change also fixes an earlier approach taken in 0.2.4.13-alpha, + where we tried to solve this issue simply by imposing an upper limit + on the number of queued cells for a single circuit. That approach + proved to be problematic, since there are ways to provoke clients to + send a number of cells in excess of any such reasonable limit. Fixes + bug 9072; bugfix on 0.2.4.13-alpha. + + - Limit hidden service descriptors to at most ten introduction + points, to slow one kind of guard enumeration. Fixes bug 9002; + bugfix on 0.1.1.11-alpha. + + +Changes in version 0.2.4.13-alpha - 2013-06-14 + Tor 0.2.4.13-alpha fixes a variety of potential remote crash + vulnerabilities, makes socks5 username/password circuit isolation + actually actually work (this time for sure!), and cleans up a bunch + of other issues in preparation for a release candidate. + + o Major bugfixes (robustness): + - Close any circuit that has too many cells queued on it. Fixes + bug 9063; bugfix on the 54th commit of Tor. This bug is a further + fix beyond bug 6252, whose fix was merged into 0.2.3.21-rc. + - Prevent the get_freelists() function from running off the end of + the list of freelists if it somehow gets an unrecognized + allocation. Fixes bug 8844; bugfix on 0.2.0.16-alpha. Reported by + eugenis. + - Avoid an assertion failure on OpenBSD (and perhaps other BSDs) + when an exit connection with optimistic data succeeds immediately + rather than returning EINPROGRESS. Fixes bug 9017; bugfix on + 0.2.3.1-alpha. + - Fix a directory authority crash bug when building a consensus + using an older consensus as its basis. Fixes bug 8833. Bugfix + on 0.2.4.12-alpha. + + o Major bugfixes: + - Avoid a memory leak where we would leak a consensus body when we + find that a consensus which we couldn't previously verify due to + missing certificates is now verifiable. Fixes bug 8719; bugfix + on 0.2.0.10-alpha. + - We used to always request authority certificates by identity digest, + meaning we'd get the newest one even when we wanted one with a + different signing key. Then we would complain about being given + a certificate we already had, and never get the one we really + wanted. Now we use the "fp-sk/" resource as well as the "fp/" + resource to request the one we want. Fixes bug 5595; bugfix on + 0.2.0.8-alpha. + - Follow the socks5 protocol when offering username/password + authentication. The fix for bug 8117 exposed this bug, and it + turns out real-world applications like Pidgin do care. Bugfix on + 0.2.3.2-alpha; fixes bug 8879. + - Prevent failures on Windows Vista and later when rebuilding the + microdescriptor cache. Diagnosed by Robert Ransom. Fixes bug 8822; + bugfix on 0.2.4.12-alpha. + + o Minor bugfixes: + - Fix an impossible buffer overrun in the AES unit tests. Fixes + bug 8845; bugfix on 0.2.0.7-alpha. Found by eugenis. + - If for some reason we fail to write a microdescriptor while + rebuilding the cache, do not let the annotations from that + microdescriptor linger in the cache file, and do not let the + microdescriptor stay recorded as present in its old location. + Fixes bug 9047; bugfix on 0.2.2.6-alpha. + - Fix a memory leak that would occur whenever a configuration + option changed. Fixes bug 8718; bugfix on 0.2.3.3-alpha. + - Paste the description for PathBias parameters from the man + page into or.h, so the code documents them too. Fixes bug 7982; + bugfix on 0.2.3.17-beta and 0.2.4.8-alpha. + - Relays now treat a changed IPv6 ORPort as sufficient reason to + publish an updated descriptor. Fixes bug 6026; bugfix on + 0.2.4.1-alpha. + - When launching a resolve request on behalf of an AF_UNIX control + socket, omit the address field of the new entry connection, used in + subsequent controller events, rather than letting tor_dup_addr() + set it to "<unknown address type>". Fixes bug 8639; bugfix on + 0.2.4.12-alpha. + + o Minor bugfixes (log messages): + - Fix a scaling issue in the path bias accounting code that + resulted in "Bug:" log messages from either + pathbias_scale_close_rates() or pathbias_count_build_success(). + This represents a bugfix on a previous bugfix: the original fix + attempted in 0.2.4.10-alpha was incomplete. Fixes bug 8235; bugfix + on 0.2.4.1-alpha. + - Give a less useless error message when the user asks for an IPv4 + address on an IPv6-only port, or vice versa. Fixes bug 8846; bugfix + on 0.2.4.7-alpha. + + o Minor features: + - Downgrade "unexpected SENDME" warnings to protocol-warn for 0.2.4.x, + to tolerate bug 8093 for now. + - Add an "ignoring-advertised-bws" boolean to the flag-threshold lines + in directory authority votes to describe whether they have enough + measured bandwidths to ignore advertised (relay descriptor) + bandwidth claims. Resolves ticket 8711. + - Update to the June 5 2013 Maxmind GeoLite Country database. + + o Removed documentation: + - Remove some of the older contents of doc/ as obsolete; move others + to torspec.git. Fixes bug 8965. + + o Code simplification and refactoring: + - Avoid using character buffers when constructing most directory + objects: this approach was unwieldy and error-prone. Instead, + build smartlists of strings, and concatenate them when done. + + +Changes in version 0.2.4.12-alpha - 2013-04-18 + Tor 0.2.4.12-alpha moves Tor forward on several fronts: it starts the + process for lengthening the guard rotation period, makes directory + authority opinions in the consensus a bit less gameable, makes socks5 + username/password circuit isolation actually work, and fixes a wide + variety of other issues. + + o Major features: + - Raise the default time that a client keeps an entry guard from + "1-2 months" to "2-3 months", as suggested by Tariq Elahi's WPES + 2012 paper. (We would make it even longer, but we need better client + load balancing first.) Also, make the guard lifetime controllable + via a new GuardLifetime torrc option and a GuardLifetime consensus + parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha. + - Directory authorities now prefer using measured bandwidths to + advertised ones when computing flags and thresholds. Resolves + ticket 8273. + - Directory authorities that have more than a threshold number + of relays with measured bandwidths now treat relays with unmeasured + bandwidths as having bandwidth 0. Resolves ticket 8435. + + o Major bugfixes (assert / resource use): + - Avoid a bug where our response to TLS renegotiation under certain + network conditions could lead to a busy-loop, with 100% CPU + consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha. + - Avoid an assertion when we discover that we'd like to write a cell + onto a closing connection: just discard the cell. Fixes another + case of bug 7350; bugfix on 0.2.4.4-alpha. + + o Major bugfixes (client-side privacy): + - When we mark a circuit as unusable for new circuits, have it + continue to be unusable for new circuits even if MaxCircuitDirtiness + is increased too much at the wrong time, or the system clock jumps + backwards. Fixes bug 6174; bugfix on 0.0.2pre26. + - If ClientDNSRejectInternalAddresses ("do not believe DNS queries + which have resolved to internal addresses") is set, apply that + rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha. + - When an exit relay rejects a stream with reason "exit policy", but + we only know an exit policy summary (e.g. from the microdesc + consensus) for it, do not mark the relay as useless for all exiting. + Instead, mark just the circuit as unsuitable for that particular + address. Fixes part of bug 7582; bugfix on 0.2.3.2-alpha. + - Allow applications to get proper stream isolation with + IsolateSOCKSAuth. Many SOCKS5 clients that want to offer + username/password authentication also offer "no authentication". Tor + had previously preferred "no authentication", so the applications + never actually sent Tor their auth details. Now Tor selects + username/password authentication if it's offered. You can disable + this behavior on a per-SOCKSPort basis via PreferSOCKSNoAuth. Fixes + bug 8117; bugfix on 0.2.3.3-alpha. + + o Major bugfixes (other): + - When unable to find any working directory nodes to use as a + directory guard, give up rather than adding the same non-working + nodes to the directory guard list over and over. Fixes bug 8231; + bugfix on 0.2.4.8-alpha. + + o Minor features: + - Reject as invalid most directory objects containing a NUL. + Belt-and-suspender fix for bug 8037. + - In our testsuite, create temporary directories with a bit more + entropy in their name to make name collisions less likely. Fixes + bug 8638. + - Add CACHED keyword to ADDRMAP events in the control protocol + to indicate whether a DNS result will be cached or not. Resolves + ticket 8596. + - Update to the April 3 2013 Maxmind GeoLite Country database. + + o Minor features (build): + - Detect and reject attempts to build Tor with threading support + when OpenSSL has been compiled without threading support. + Fixes bug 6673. + - Clarify that when autoconf is checking for nacl, it is checking + specifically for nacl with a fast curve25519 implementation. + Fixes bug 8014. + - Warn if building on a platform with an unsigned time_t: there + are too many places where Tor currently assumes that time_t can + hold negative values. We'd like to fix them all, but probably + some will remain. + + o Minor bugfixes (build): + - Fix some bugs in tor-fw-helper-natpmp when trying to build and + run it on Windows. More bugs likely remain. Patch from Gisle Vanem. + Fixes bug 7280; bugfix on 0.2.3.1-alpha. + - Add the old src/or/micro-revision.i filename to CLEANFILES. + On the off chance that somebody has one, it will go away as soon + as they run "make clean". Fix for bug 7143; bugfix on 0.2.4.1-alpha. + - Build Tor correctly on 32-bit platforms where the compiler can build + but not run code using the "uint128_t" construction. Fixes bug 8587; + bugfix on 0.2.4.8-alpha. + - Fix compilation warning with some versions of clang that would + prefer the -Wswitch-enum compiler flag to warn about switch + statements with missing enum values, even if those switch + statements have a "default:" statement. Fixes bug 8598; bugfix + on 0.2.4.10-alpha. + + o Minor bugfixes (protocol): + - Fix the handling of a TRUNCATE cell when it arrives while the + circuit extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1. + - Fix a misframing issue when reading the version numbers in a + VERSIONS cell. Previously we would recognize [00 01 00 02] as + 'version 1, version 2, and version 0x100', when it should have + only included versions 1 and 2. Fixes bug 8059; bugfix on + 0.2.0.10-alpha. Reported pseudonymously. + - Make the format and order of STREAM events for DNS lookups + consistent among the various ways to launch DNS lookups. Fixes + bug 8203; bugfix on 0.2.0.24-rc. Patch by "Desoxy." + - Correct our check for which versions of Tor support the EXTEND2 + cell. We had been willing to send it to Tor 0.2.4.7-alpha and + later, when support was really added in version 0.2.4.8-alpha. + Fixes bug 8464; bugfix on 0.2.4.8-alpha. + + o Minor bugfixes (other): + - Correctly store microdescriptors and extrainfo descriptors with + an internal NUL byte. Fixes bug 8037; bugfix on 0.2.0.1-alpha. + Bug reported by "cypherpunks". + - Increase the width of the field used to remember a connection's + link protocol version to two bytes. Harmless for now, since the + only currently recognized versions are one byte long. Reported + pseudonymously. Fixes bug 8062; bugfix on 0.2.0.10-alpha. + - If the state file's path bias counts are invalid (presumably from a + buggy Tor prior to 0.2.4.10-alpha), make them correct. Also add + additional checks and log messages to the scaling of Path Bias + counts, in case there still are remaining issues with scaling. + Should help resolve bug 8235. + - Eliminate several instances where we use "Nickname=ID" to refer to + nodes in logs. Use "Nickname (ID)" instead. (Elsewhere, we still use + "$ID=Nickname", which is also acceptable.) Fixes bug 7065. Bugfix + on 0.2.3.21-rc, 0.2.4.5-alpha, 0.2.4.8-alpha, and 0.2.4.10-alpha. + + o Minor bugfixes (syscalls): + - Always check the return values of functions fcntl() and + setsockopt(). We don't believe these are ever actually failing in + practice, but better safe than sorry. Also, checking these return + values should please analysis tools like Coverity. Patch from + 'flupzor'. Fixes bug 8206; bugfix on all versions of Tor. + - Use direct writes rather than stdio when building microdescriptor + caches, in an attempt to mitigate bug 8031, or at least make it + less common. + + o Minor bugfixes (config): + - When rejecting a configuration because we were unable to parse a + quoted string, log an actual error message. Fixes bug 7950; bugfix + on 0.2.0.16-alpha. + - Behave correctly when the user disables LearnCircuitBuildTimeout + but doesn't tell us what they would like the timeout to be. Fixes + bug 6304; bugfix on 0.2.2.14-alpha. + - When autodetecting the number of CPUs, use the number of available + CPUs in preference to the number of configured CPUs. Inform the + user if this reduces the number of available CPUs. Fixes bug 8002; + bugfix on 0.2.3.1-alpha. + - Make it an error when you set EntryNodes but disable UseGuardNodes, + since it will (surprisingly to some users) ignore EntryNodes. Fixes + bug 8180; bugfix on 0.2.3.11-alpha. + - Allow TestingTorNetworks to override the 4096-byte minimum for + the Fast threshold. Otherwise they can't bootstrap until they've + observed more traffic. Fixes bug 8508; bugfix on 0.2.4.10-alpha. + - Fix some logic errors when the user manually overrides the + PathsNeededToBuildCircuits option in torrc. Fixes bug 8599; bugfix + on 0.2.4.10-alpha. + + o Minor bugfixes (log messages to help diagnose bugs): + - If we fail to free a microdescriptor because of bug 7164, log + the filename and line number from which we tried to free it. + - Add another diagnostic to the heartbeat message: track and log + overhead that TLS is adding to the data we write. If this is + high, we are sending too little data to SSL_write at a time. + Diagnostic for bug 7707. + - Add more detail to a log message about relaxed timeouts, to help + track bug 7799. + - Warn more aggressively when flushing microdescriptors to a + microdescriptor cache fails, in an attempt to mitigate bug 8031, + or at least make it more diagnosable. + - Improve debugging output to help track down bug 8185 ("Bug: + outgoing relay cell has n_chan==NULL. Dropping.") + - Log the purpose of a path-bias testing circuit correctly. + Improves a log message from bug 8477; bugfix on 0.2.4.8-alpha. + + o Minor bugfixes (0.2.4.x log messages that were too noisy): + - Don't attempt to relax the timeout of already opened 1-hop circuits. + They might never timeout. This should eliminate some/all cases of + the relaxed timeout log message. + - Use circuit creation time for network liveness evaluation. This + should eliminate warning log messages about liveness caused + by changes in timeout evaluation. Fixes bug 6572; bugfix on + 0.2.4.8-alpha. + - Reduce a path bias length check from notice to info. The message + is triggered when creating controller circuits. Fixes bug 8196; + bugfix on 0.2.4.8-alpha. + - Fix a path state issue that triggered a notice during relay startup. + Fixes bug 8320; bugfix on 0.2.4.10-alpha. + - Reduce occurrences of warns about circuit purpose in + connection_ap_expire_building(). Fixes bug 8477; bugfix on + 0.2.4.11-alpha. + + o Minor bugfixes (pre-0.2.4.x log messages that were too noisy): + - If we encounter a write failure on a SOCKS connection before we + finish our SOCKS handshake, don't warn that we closed the + connection before we could send a SOCKS reply. Fixes bug 8427; + bugfix on 0.1.0.1-rc. + - Correctly recognize that [::1] is a loopback address. Fixes + bug 8377; bugfix on 0.2.1.3-alpha. + - Fix a directory authority warn caused when we have a large amount + of badexit bandwidth. Fixes bug 8419; bugfix on 0.2.2.10-alpha. + - Don't log inappropriate heartbeat messages when hibernating: a + hibernating node is _expected_ to drop out of the consensus, + decide it isn't bootstrapped, and so forth. Fixes bug 7302; + bugfix on 0.2.3.1-alpha. + - Don't complain about bootstrapping problems while hibernating. + These complaints reflect a general code problem, but not one + with any problematic effects (no connections are actually + opened). Fixes part of bug 7302; bugfix on 0.2.3.2-alpha. + + o Documentation fixes: + - Update tor-fw-helper.1.txt and tor-fw-helper.c to make option + names match. Fixes bug 7768. + - Make the torify manpage no longer refer to tsocks; torify hasn't + supported tsocks since 0.2.3.14-alpha. + - Make the tor manpage no longer reference tsocks. + - Fix the GeoIPExcludeUnknown documentation to refer to + ExcludeExitNodes rather than the currently nonexistent + ExcludeEntryNodes. Spotted by "hamahangi" on tor-talk. + + o Removed files: + - The tor-tsocks.conf is no longer distributed or installed. We + recommend that tsocks users use torsocks instead. Resolves + ticket 8290. + + +Changes in version 0.2.4.11-alpha - 2013-03-11 + Tor 0.2.4.11-alpha makes relay measurement by directory authorities + more robust, makes hidden service authentication work again, and + resolves a DPI fingerprint for Tor's SSL transport. + + o Major features (directory authorities): + - Directory authorities now support a new consensus method (17) + where they cap the published bandwidth of servers for which + insufficient bandwidth measurements exist. Fixes part of bug 2286. + - Directory authorities that set "DisableV2DirectoryInfo_ 1" no longer + serve any v2 directory information. Now we can test disabling the + old deprecated v2 directory format, and see whether doing so has + any effect on network load. Begins to fix bug 6783. + - Directory authorities now include inside each vote a statement of + the performance thresholds they used when assigning flags. + Implements ticket 8151. + + o Major bugfixes (directory authorities): + - Stop marking every relay as having been down for one hour every + time we restart a directory authority. These artificial downtimes + were messing with our Stable and Guard flag calculations. Fixes + bug 8218 (introduced by the fix for 1035). Bugfix on 0.2.2.23-alpha. + + o Major bugfixes (hidden services): + - Allow hidden service authentication to succeed again. When we + refactored the hidden service introduction code back + in 0.2.4.1-alpha, we didn't update the code that checks + whether authentication information is present, causing all + authentication checks to return "false". Fix for bug 8207; bugfix + on 0.2.4.1-alpha. Found by Coverity; this is CID 718615. + + o Minor features (relays, bridges): + - Make bridge relays check once a minute for whether their IP + address has changed, rather than only every 15 minutes. Resolves + bugs 1913 and 1992. + - Refactor resolve_my_address() so it returns the method by which we + decided our public IP address (explicitly configured, resolved from + explicit hostname, guessed from interfaces, learned by gethostname). + Now we can provide more helpful log messages when a relay guesses + its IP address incorrectly (e.g. due to unexpected lines in + /etc/hosts). Resolves ticket 2267. + - Teach bridge-using clients to avoid 0.2.2 bridges when making + microdescriptor-related dir requests, and only fall back to normal + descriptors if none of their bridges can handle microdescriptors + (as opposed to the fix in ticket 4013, which caused them to fall + back to normal descriptors if *any* of their bridges preferred + them). Resolves ticket 4994. + - Randomize the lifetime of our SSL link certificate, so censors can't + use the static value for filtering Tor flows. Resolves ticket 8443; + related to ticket 4014 which was included in 0.2.2.33. + + o Minor features (portability): + - Tweak the curve25519-donna*.c implementations to tolerate systems + that lack stdint.h. Fixes bug 3894; bugfix on 0.2.4.8-alpha. + - Use Ville Laurikari's implementation of AX_CHECK_SIGN() to determine + the signs of types during autoconf. This is better than our old + approach, which didn't work when cross-compiling. + - Detect the sign of enum values, rather than assuming that MSC is the + only compiler where enum types are all signed. Fixes bug 7727; + bugfix on 0.2.4.10-alpha. + + o Minor features (other): + - Say "KBytes" rather than "KB" in the man page (for various values + of K), to further reduce confusion about whether Tor counts in + units of memory or fractions of units of memory. Resolves ticket 7054. + - Clear the high bit on curve25519 public keys before passing them to + our backend, in case we ever wind up using a backend that doesn't do + so itself. If we used such a backend, and *didn't* clear the high bit, + we could wind up in a situation where users with such backends would + be distinguishable from users without. Fixes bug 8121; bugfix on + 0.2.4.8-alpha. + - Update to the March 6 2013 Maxmind GeoLite Country database. + + o Minor bugfixes (clients): + - When we receive a RELAY_END cell with the reason DONE, or with no + reason, before receiving a RELAY_CONNECTED cell, report the SOCKS + status as "connection refused". Previously we reported these cases + as success but then immediately closed the connection. Fixes bug + 7902; bugfix on 0.1.0.1-rc. Reported by "oftc_must_be_destroyed". + - Downgrade an assertion in connection_ap_expire_beginning to an + LD_BUG message. The fix for bug 8024 should prevent this message + from displaying, but just in case, a warn that we can diagnose + is better than more assert crashes. Fixes bug 8065; bugfix on + 0.2.4.8-alpha. + - Lower path use bias thresholds to .80 for notice and .60 for warn. + Also make the rate limiting flags for the path use bias log messages + independent from the original path bias flags. Fixes bug 8161; + bugfix on 0.2.4.10-alpha. + + o Minor bugfixes (relays): + - Stop trying to resolve our hostname so often (e.g. every time we + think about doing a directory fetch). Now we reuse the cached + answer in some cases. Fixes bugs 1992 (bugfix on 0.2.0.20-rc) + and 2410 (bugfix on 0.1.2.2-alpha). + - Stop sending a stray "(null)" in some cases for the server status + "EXTERNAL_ADDRESS" controller event. Resolves bug 8200; bugfix + on 0.1.2.6-alpha. + - When choosing which stream on a formerly stalled circuit to wake + first, make better use of the platform's weak RNG. Previously, + we had been using the % ("modulo") operator to try to generate a + 1/N chance of picking each stream, but this behaves badly with + many platforms' choice of weak RNG. Fixes bug 7801; bugfix on + 0.2.2.20-alpha. + - Use our own weak RNG when we need a weak RNG. Windows's rand() and + Irix's random() only return 15 bits; Solaris's random() returns more + bits but its RAND_MAX says it only returns 15, and so on. Motivated + by the fix for bug 7801; bugfix on 0.2.2.20-alpha. + + o Minor bugfixes (directory authorities): + - Directory authorities now use less space when formatting identical + microdescriptor lines in directory votes. Fixes bug 8158; bugfix + on 0.2.4.1-alpha. + + o Minor bugfixes (memory leaks spotted by Coverity -- bug 7816): + - Avoid leaking memory if we fail to compute a consensus signature + or we generate a consensus we can't parse. Bugfix on 0.2.0.5-alpha. + - Fix a memory leak when receiving headers from an HTTPS proxy. Bugfix + on 0.2.1.1-alpha. + - Fix a memory leak during safe-cookie controller authentication. + Bugfix on 0.2.3.13-alpha. + - Avoid memory leak of IPv6 policy content if we fail to format it into + a router descriptor. Bugfix on 0.2.4.7-alpha. + + o Minor bugfixes (other code correctness issues): + - Avoid a crash if we fail to generate an extrainfo descriptor. + Fixes bug 8208; bugfix on 0.2.3.16-alpha. Found by Coverity; + this is CID 718634. + - When detecting the largest possible file descriptor (in order to + close all file descriptors when launching a new program), actually + use _SC_OPEN_MAX. The old code for doing this was very, very broken. + Fixes bug 8209; bugfix on 0.2.3.1-alpha. Found by Coverity; this + is CID 743383. + - Fix a copy-and-paste error when adding a missing A1 to a routerset + because of GeoIPExcludeUnknown. Fix for Coverity CID 980650. + Bugfix on 0.2.4.10-alpha. + - Fix an impossible-to-trigger integer overflow when estimating how + long our onionskin queue would take. (This overflow would require us + to accept 4 million onionskins before processing 100 of them.) Fixes + bug 8210; bugfix on 0.2.4.10-alpha. + + o Code simplification and refactoring: + - Add a wrapper function for the common "log a message with a + rate-limit" case. + + Changes in version 0.2.4.10-alpha - 2013-02-04 Tor 0.2.4.10-alpha adds defenses at the directory authority level from certain attacks that flood the network with relays; changes the queue @@ -3322,7 +3814,7 @@ Changes in version 0.2.3.4-alpha - 2011-09-13 by an attacker who controls both an introduction point and a rendezvous point, and who uses the malleability of AES-CTR to alter the encrypted g^x portion of the INTRODUCE1 cell. We think - that these attacks is infeasible (requiring the attacker to send + that these attacks are infeasible (requiring the attacker to send on the order of zettabytes of altered cells in a short interval), but we'd rather block them off in case there are any classes of this attack that we missed. Reported by Willem Pinckaers. diff --git a/Makefile.am b/Makefile.am index 4639c22c41..0361d87cec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,12 @@ EXTRA_DIST+= \ README \ ReleaseNotes +if COVERAGE_ENABLED +TEST_CFLAGS=-fno-inline -fprofile-arcs -ftest-coverage +else +TEST_CFLAGS= +endif + #install-data-local: # $(INSTALL) -m 755 -d $(LOCALSTATEDIR)/lib/tor @@ -60,6 +66,14 @@ doxygen: test: all ./src/test/test +# Note that test-network requires a copy of Chutney in $CHUTNEY_PATH. +# Chutney can be cloned from https://git.torproject.org/chutney.git . +test-network: all + ./src/test/test-network.sh + +reset-gcov: + rm -f src/*/*.gcda + # Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c, # eventdns.[hc], tinytest*.[ch] check-spaces: @@ -84,3 +98,5 @@ version: (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \ fi +mostlyclean-local: + rm -f src/*/*.gc{da,no} diff --git a/changes/6783_big_hammer b/changes/6783_big_hammer deleted file mode 100644 index 2ff3249b33..0000000000 --- a/changes/6783_big_hammer +++ /dev/null @@ -1,6 +0,0 @@ - o Major features (deprecation): - - There's now a "DisableV2DirectoryInfo_" option that prevents us - from serving any directory requests for v2 directory information. - This is for us to test disabling the old deprecated V2 directory - format, so that we can see whether doing so has any effect on - network load. Part of a fix for bug 6783. diff --git a/changes/address_tests b/changes/address_tests new file mode 100644 index 0000000000..b5a8012436 --- /dev/null +++ b/changes/address_tests @@ -0,0 +1,2 @@ + o New unit tests: + - More unit tests for address-manipulation functions. diff --git a/changes/bug1992 b/changes/bug1992 deleted file mode 100644 index 6a751dc7e6..0000000000 --- a/changes/bug1992 +++ /dev/null @@ -1,11 +0,0 @@ - o Minor bugfixes: - - Stop trying to resolve our hostname so often (e.g. every time we - think about doing a directory fetch). Now we reuse the cached - answer in some cases. Fixes bugs 1992 (bugfix on 0.2.0.20-rc) - and 2410 (bugfix on 0.1.2.2-alpha). - - o Minor features: - - Make bridge relays check once a minute for whether their IP - address has changed, rather than only every 15 minutes. Resolves - bugs 1913 and 1992. - diff --git a/changes/bug2286 b/changes/bug2286 deleted file mode 100644 index 4f8dfbbf68..0000000000 --- a/changes/bug2286 +++ /dev/null @@ -1,5 +0,0 @@ - o Major features (directory authority): - - Directory authorities now support a new consensus method (17) - where they cap the published bandwidth of servers for which - insufficient bandwidth measurements exist. Fixes part of bug - 2286. diff --git a/changes/bug3594 b/changes/bug3594 new file mode 100644 index 0000000000..110252d008 --- /dev/null +++ b/changes/bug3594 @@ -0,0 +1,3 @@ + o Major bugfixes: + - Add support for passing arguments to managed pluggable transport + proxies. Implements ticket #3594. diff --git a/changes/bug4282 b/changes/bug4282 new file mode 100644 index 0000000000..4d4f4896fe --- /dev/null +++ b/changes/bug4282 @@ -0,0 +1,4 @@ + o Code simplifications and refactoring: + - Extract the common duplicated code for creating a subdirectory + of the data directory and writing to a file in it. Fixes ticket + 4282; patch from Peter Retzlaff. diff --git a/changes/bug5170 b/changes/bug5170 new file mode 100644 index 0000000000..4e52c5ea6b --- /dev/null +++ b/changes/bug5170 @@ -0,0 +1,5 @@ + o Code simplification and refactoring: + - Remove contrib/id_to_fp.c since it wasn't used anywhere. + - Since OpenSSL 0.9.7 i2d_* functions support allocating output + buffer. Avoid calling twice: i2d_RSAPublicKey, i2d_DHparams, + i2d_X509, i2d_PublicKey. Fixes #5170. diff --git a/changes/bug5584 b/changes/bug5584 new file mode 100644 index 0000000000..a81be00ae4 --- /dev/null +++ b/changes/bug5584 @@ -0,0 +1,4 @@ + o Minor features: + - Raise awareness of safer logging - notice user of potentially + unsafe configuration options: logging above "notice" or + clearning SafeLogging flag. Fixes #5584. diff --git a/changes/bug5650 b/changes/bug5650 deleted file mode 100644 index 401e317074..0000000000 --- a/changes/bug5650 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes: - - Avoid a bug where our response to TLS renegotation under certain - network conditions could lead to a busy-loop, with 100% CPU - consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha. - diff --git a/changes/bug6174 b/changes/bug6174 deleted file mode 100644 index 79d2930ec3..0000000000 --- a/changes/bug6174 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes: - - When we mark a circuit as unusable for new circuits, have it - continue to be unusable for new circuits even if MaxCircuitDirtiness - is increased too much at the wrong time, or the system clock jumped - backwards. Fix for bug 6174; bugfix on 0.0.2pre26. - diff --git a/changes/bug6206 b/changes/bug6206 deleted file mode 100644 index 61a16d291a..0000000000 --- a/changes/bug6206 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes: - - Always check the return values of functions fcntl() and - setsockopt(). We don't believe these are ever actually failing in - practice, but better safe than sorry. Also, checking these return - values should please some analysis tools (like Coverity). Patch - from 'flupzor'. Fix for bug 8206; bugfix on all versions of Tor. diff --git a/changes/bug6304 b/changes/bug6304 deleted file mode 100644 index 445560a8e1..0000000000 --- a/changes/bug6304 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Behave correctly when the user disables LearnCircuitBuildTimeout - but doesn't tell us what they would like the timeout to be. Fixes - bug 6304; bugfix on 0.2.2.14-alpha. diff --git a/changes/bug6506 b/changes/bug6506 new file mode 100644 index 0000000000..4c6f4900da --- /dev/null +++ b/changes/bug6506 @@ -0,0 +1,4 @@ + o Minor features (build): + - Detect a missing asciidoc, and warn the user about it, during + configure, rather than at build time. Fixes issue 6506. Patch + from Arlo Breault. diff --git a/changes/bug6520 b/changes/bug6520 new file mode 100644 index 0000000000..9f24f0dc39 --- /dev/null +++ b/changes/bug6520 @@ -0,0 +1,5 @@ + o Removed features: + - Remove migration code from when we renamed the "cached-routers" + file to "cached-descriptors" back in 0.2.0.8-alpha. This + incidentally resolves #6502 by cleaning up the related code + a bit. Patch from Akshay Hebbar. diff --git a/changes/bug6572 b/changes/bug6572 deleted file mode 100644 index 6508d1bcb5..0000000000 --- a/changes/bug6572 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (log messages) - - Use circuit creation time for network liveness evaluation. This - should eliminate warning log messages about liveness caused by - changes in timeout evaluation. Fixes bug 6572; bugfix on 0.2.4.8-alpha. diff --git a/changes/bug6673 b/changes/bug6673 deleted file mode 100644 index 506b449892..0000000000 --- a/changes/bug6673 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (build): - - Detect and reject attempts to build Tor with threading support - when OpenSSL have been compiled with threading support disabled. - Fixes bug 6673. diff --git a/changes/bug6752 b/changes/bug6752 new file mode 100644 index 0000000000..8d620d56ee --- /dev/null +++ b/changes/bug6752 @@ -0,0 +1,5 @@ + o Minor features: + - Lower directory fetch retry schedules and maximum interval without + directory requests, and raise maximum download tries in testing + networks. Implements #6752. + diff --git a/changes/bug7054 b/changes/bug7054 deleted file mode 100644 index 15680d72ce..0000000000 --- a/changes/bug7054 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (man page): - - Say "KBytes" rather than "KB" in the man page (for various values - of K), to further reduce confusion about whether Tor counts in - units of memory or fractions of units of memory. Fixes bug 7054. diff --git a/changes/bug7065 b/changes/bug7065 deleted file mode 100644 index 1ca6841021..0000000000 --- a/changes/bug7065 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfix (log cleanups): - - Eliminate several instances where we use Nickname=ID to refer to - nodes in logs. Use Nickname (ID) instead. (Elsewhere, we still use - $ID=Nickname, which is also acceptable.) Fixes bug #7065. Bugfix - on 0.2.3.21-rc, 0.2.4.5-alpha, 0.2.4.8-alpha, and 0.2.4.10-alpha. diff --git a/changes/bug7143 b/changes/bug7143 deleted file mode 100644 index d26135ae65..0000000000 --- a/changes/bug7143 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes (build): - - Add the old src/or/micro-revision.i filename to CLEANFILES. - On the off chance that somebody has one, it will go away as soon - as they run "make clean". Fix for bug 7143; bugfix on 0.2.4.1-alpha. diff --git a/changes/bug7164_diagnostic b/changes/bug7164_diagnostic deleted file mode 100644 index 8bedfc4bd5..0000000000 --- a/changes/bug7164_diagnostic +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features (bug diagnostic): - - If we fail to free a microdescriptor because of bug #7164, log - the filename and line number from which we tried to free it. - This should help us finally fix #7164. diff --git a/changes/bug7280 b/changes/bug7280 deleted file mode 100644 index ef5d36a802..0000000000 --- a/changes/bug7280 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Fix some bugs in tor-fw-helper-natpmp when trying to build and - run it on Windows. More bugs likely remain. Patch from Gisle Vanem. - Fixes bug 7280; bugfix on 0.2.3.1-alpha. diff --git a/changes/bug7302 b/changes/bug7302 deleted file mode 100644 index fec615ff90..0000000000 --- a/changes/bug7302 +++ /dev/null @@ -1,11 +0,0 @@ - o Minor bugfixes: - - Don't log inappropriate heartbeat messages when hibernating: a - hibernating node is _expected_ to drop out of the consensus, - decide it isn't bootstrapped, and so forth. Fixes part of bug - 7302; bugfix on 0.2.3.1-alpha. - - - Don't complain about bootstrapping problems while hibernating. - These complaints reflect a general code problems, but not one - with any problematic effects. (No connections are actually - opened.) Fixes part of bug 7302; bugfix on 0.2.3.2-alpha. - diff --git a/changes/bug7350 b/changes/bug7350 deleted file mode 100644 index b0ee9d0919..0000000000 --- a/changes/bug7350 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes: - - Avoid an assertion when we discover that we'd like to write a cell - onto a closing connection: just discard the cell. Fixes another - case of bug 7350; bugfix on 0.2.4.4-alpha. diff --git a/changes/bug7582 b/changes/bug7582 deleted file mode 100644 index f3b0635765..0000000000 --- a/changes/bug7582 +++ /dev/null @@ -1,9 +0,0 @@ - o Major bugfixes: - - - When an exit node tells us that it is rejecting because of its - exit policy a stream we expected it to accept (because of its exit - policy), do not mark the node as useless for exiting if our - expectation was only based on an exit policy summary. Instead, - mark the circuit as unsuitable for that particular address. Fixes - part of bug 7582; bugfix on 0.2.3.2-alpha. - diff --git a/changes/bug7707_diagnostic b/changes/bug7707_diagnostic deleted file mode 100644 index 0c3138e785..0000000000 --- a/changes/bug7707_diagnostic +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features: - - Add another diagnostic to the heartbeat message: track and log - overhead that TLS is adding to the data we write. If this is - high, we are sending too little data to SSL_write at a time. - Diagnostic for bug 7707. diff --git a/changes/bug7768 b/changes/bug7768 deleted file mode 100644 index e3f9600afb..0000000000 --- a/changes/bug7768 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation fixes: - - Update tor-fw-helper.1.txt and tor-fw-helper.c to make option - names match. Fixes bug 7768. diff --git a/changes/bug7799 b/changes/bug7799 deleted file mode 100644 index ed4570129c..0000000000 --- a/changes/bug7799 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor changes (log clarification) - - Add more detail to a log message about relaxed timeouts. Hopefully - this additional detail will allow us to diagnose the cause of bug 7799. - o Minor bugfixes - - Don't attempt to relax the timeout of already opened 1-hop circuits. - They might never timeout. This should eliminate some/all cases of - the relaxed timeout log message. diff --git a/changes/bug7801 b/changes/bug7801 deleted file mode 100644 index 1d6d021f3f..0000000000 --- a/changes/bug7801 +++ /dev/null @@ -1,13 +0,0 @@ - o Minor bugfixes: - - When choosing which stream on a formerly stalled circuit to wake - first, make better use of the platform's weak RNG. Previously, we - had been using the % ("modulo") operator to try to generate a 1/N - chance of picking each stream, but this behaves badly with many - platforms' choice of weak RNG. Fix for bug 7801; bugfix on - 0.2.2.20-alpha. - - Use our own weak RNG when we need a weak RNG. Windows's rand() - and Irix's random() only return 15 bits; Solaris's random() - returns more bits but its RAND_MAX says it only returns 15, and - so on. Fixes another aspect of bug 7801; bugfix on - 0.2.2.20-alpha. - diff --git a/changes/bug7816.024 b/changes/bug7816.024 deleted file mode 100644 index b5d55f5d6d..0000000000 --- a/changes/bug7816.024 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor bugfixes: - - Avoid leaking IPv6 policy content if we fail to format it into - a router descriptor. Spotted by Coverity. Fixes part of 7816; - bugfix on 0.2.4.7-alpha. - - - Avoid leaking memory if we fail to compute a consensus signature - or we generated a consensus we couldn't parse. Spotted by Coverity. - Fixes part of 7816; bugfix on 0.2.0.5-alpha. diff --git a/changes/bug7816_023 b/changes/bug7816_023 deleted file mode 100644 index a4530292cc..0000000000 --- a/changes/bug7816_023 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (memory leak, controller): - - Fix a memory leak during safe-cookie controller authentication. - Spotted by Coverity. Fixes part of bug 7816; bugfix on 0.2.3.13-alpha. - - o Minor bugfixes (memory leak, HTTPS proxy support): - - Fix a memory leak when receiving headers from an HTTPS proxy. - Spotted by Coverity. Fixes part of bug 7816; bugfix on 0.2.1.1-alpha. diff --git a/changes/bug7816_023_small b/changes/bug7816_023_small deleted file mode 100644 index cd90f035f1..0000000000 --- a/changes/bug7816_023_small +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Fix various places where we leak file descriptors or memory on - error cases. Spotted by coverity. Fixes parts of bug 7816. diff --git a/changes/bug7902 b/changes/bug7902 deleted file mode 100644 index 051759dc0a..0000000000 --- a/changes/bug7902 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes: - - When we receive a RELAY_END cell with the reason DONE, or with no - reason, before receiving a RELAY_CONNECTED cell, report the SOCKS - status as "connection refused." Previously we reporting these - cases as success but then immediately closing the connection. - Fixes bug 7902; bugfix on 0.1.0.1-rc. Reported by "oftc_must_ - be_destroyed." diff --git a/changes/bug7912 b/changes/bug7912 new file mode 100644 index 0000000000..48c65d2241 --- /dev/null +++ b/changes/bug7912 @@ -0,0 +1,8 @@ + o Major bugfixes: + - Instead of writing destroy cells directly to outgoing connection + buffers, queue them and intersperse them with other outgoing cells. + This can prevent a set of resource starvation conditions where too + many pending destroy cells prevent data cells from actually getting + delivered. Reported by "oftc_must_be_destroyed". Fixes bug 7912; + bugfix on 0.2.0.1-alpha. + diff --git a/changes/bug7947 b/changes/bug7947 deleted file mode 100644 index 6200ba2d8a..0000000000 --- a/changes/bug7947 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Fix the handling of a TRUNCATE cell when it arrives while the circuit - extension is in progress. Fixes bug 7947; bugfix on 0.0.7.1. - diff --git a/changes/bug7950 b/changes/bug7950 deleted file mode 100644 index e62cca07a1..0000000000 --- a/changes/bug7950 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - When rejecting a configuration because we were unable to parse a - quoted string, log an actual error message. Fix for bug 7950; - bugfix on 0.2.0.16-alpha. diff --git a/changes/bug8002 b/changes/bug8002 deleted file mode 100644 index d6e2ff2492..0000000000 --- a/changes/bug8002 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes: - - When autodetecting the number of CPUs, use the number of available - CPUs in preferernce to the number of configured CPUs. Inform the - user if this reduces the number of avialable CPUs. Fix for bug 8002. - Bugfix on 0.2.3.1-alpha. diff --git a/changes/bug8014 b/changes/bug8014 deleted file mode 100644 index c09a86098c..0000000000 --- a/changes/bug8014 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor usability improvements (build): - - Clarify that when autconf is checking for nacl, it is checking - specifically for nacl with a fast curve25519 implementation. - Fixes bug 8014. - diff --git a/changes/bug8031 b/changes/bug8031 deleted file mode 100644 index 17329ec5b5..0000000000 --- a/changes/bug8031 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes: - - Use direct writes rather than stdio when building microdescriptor - caches, in an attempt to mitigate bug 8031, or at least make it - less common. - - Warn more aggressively when flushing microdescriptors to a - microdescriptor cache fails, in an attempt to mitegate bug 8031, - or at least make it more diagnosable. diff --git a/changes/bug8037 b/changes/bug8037 deleted file mode 100644 index 989745fc39..0000000000 --- a/changes/bug8037 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor bugfixes: - - Correctly store microdescriptors and extrainfo descriptors with - an internal NUL byte. Fixes bug 8037; bugfix on 0.2.0.1-alpha. - Bug reported by "cypherpunks". - - o Minor features: - - Reject as invalid most directory objects containing a - NUL. Belt-and-suspender fix for bug 8037. diff --git a/changes/bug8059 b/changes/bug8059 deleted file mode 100644 index 47273ed0ac..0000000000 --- a/changes/bug8059 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes (protocol conformance): - - Fix a misframing issue when reading the version numbers in a - VERSIONS cell. Previously we would recognize [00 01 00 02] as - 'version 1, version 2, and version 0x100', when it should have - only included versions 1 and 2. Fixes bug 8059; bugfix on - 0.2.0.10-alpha. Reported pseudonymously. diff --git a/changes/bug8062 b/changes/bug8062 deleted file mode 100644 index 805e51ed41..0000000000 --- a/changes/bug8062 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes: - - Increase the width of the field used to remember a connection's - link protocol version to two bytes. Harmless for now, since the - only currently recognized versions are one byte long. Reported - pseudynmously. Fixes bug 8062, bugfix on 0.2.0.10-alpha. diff --git a/changes/bug8065 b/changes/bug8065 deleted file mode 100644 index 06dbae8cd7..0000000000 --- a/changes/bug8065 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes: - - Downgrade an assertion in connection_ap_expire_beginning to - an LD_BUG message. The fix for bug 8024 should prevent this - message from displaying, but just in case a warn that we can - diagnose is better than more assert crashes. Fix for bug 8065; - bugfix on 0.2.4.8-alpha. diff --git a/changes/bug8093.part2 b/changes/bug8093.part2 new file mode 100644 index 0000000000..263c7e8b86 --- /dev/null +++ b/changes/bug8093.part2 @@ -0,0 +1,3 @@ + o Minor features: + - Return the "unexpected sendme" warnings to a warn severity, but make + them rate limited. Related to ticket #8093. diff --git a/changes/bug8117 b/changes/bug8117 deleted file mode 100644 index 910e8056f4..0000000000 --- a/changes/bug8117 +++ /dev/null @@ -1,13 +0,0 @@ - o Major bugfixes: - - - Many SOCKS5 clients, when configured to offer a username/password, - offer both username/password authentication and "no authentication". - Tor had previously preferred no authentication, but this was - problematic when trying to make applications get proper stream - isolation with IsolateSOCKSAuth. Now, on any SOCKS port with - IsolateSOCKSAuth turned on (which is the default), Tor selects - username/password authentication if it's offered. If this confuses your - application, you can disable it on a per-SOCKSPort basis via - PreferSOCKSNoAuth. Fixes bug 8117; bugfix on 0.2.3.3-alpha. - - diff --git a/changes/bug8121 b/changes/bug8121 deleted file mode 100644 index 60cba72848..0000000000 --- a/changes/bug8121 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features: - - Clear the high bit on curve25519 public keys before passing them to - our backend, in case we ever wind up using a backend that doesn't do - so itself. If we used such a backend, and *didn't* clear the high bit, - we could wind up in a situation where users with such backends would - be distinguishable from users without. Fix for bug 8121; bugfix on - 0.2.4.8-alpha. diff --git a/changes/bug8151 b/changes/bug8151 deleted file mode 100644 index e20fa3c31a..0000000000 --- a/changes/bug8151 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (directory authority): - - Include inside each vote a statement of the performance - thresholds that made the authority vote for its flags. Implements - ticket 8151. -
\ No newline at end of file diff --git a/changes/bug8158 b/changes/bug8158 deleted file mode 100644 index 65b21c2a26..0000000000 --- a/changes/bug8158 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Use less space when formatting identical microdescriptor lines in - directory votes. Fixes bug 8158; bugfix on 0.2.4.1-alpha. diff --git a/changes/bug8161 b/changes/bug8161 deleted file mode 100644 index ab7b9c0cad..0000000000 --- a/changes/bug8161 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor changes: - - Lower path use bias thresholds to .80 for notice and .60 for warn. - Fixes bug #8161; bugfix on 0.2.4.10-alpa. - - Make the rate limiting flags for the path use bias log messages - independent from the original path bias flags. Fixes bug #8161; - bugfix on 0.2.4.10-alpha. diff --git a/changes/bug8180 b/changes/bug8180 deleted file mode 100644 index 39e6ce7f9a..0000000000 --- a/changes/bug8180 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor bugfixes (security usability): - - Elevate the severity of the warning message when setting - EntryNodes but disabling UseGuardNodes to an error. The outcome - of letting Tor procede with those options enabled (which causes - EntryNodes to get ignored) is sufficiently different from what - was expected that it's best to just refuse to proceed. Fixes bug - 8180; bugfix on 0.2.3.11-alpha. diff --git a/changes/bug8185_diagnostic b/changes/bug8185_diagnostic deleted file mode 100644 index b0f8884758..0000000000 --- a/changes/bug8185_diagnostic +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Improve debugging output to attempt to diagnose the underlying - cause of bug 8185. diff --git a/changes/bug8200 b/changes/bug8200 deleted file mode 100644 index 65fc9dd03a..0000000000 --- a/changes/bug8200 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfix: - - Stop sending a stray "(null)" in some cases for the server status - "EXTERNAL_ADDRESS" controller event. Resolves bug 8200; bugfix - on 0.1.2.6-alpha. - diff --git a/changes/bug8203 b/changes/bug8203 deleted file mode 100644 index d26dc0fccf..0000000000 --- a/changes/bug8203 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Make the format and order of STREAM events for DNS lookups consistent - among the various ways to launch DNS lookups. Fix for bug 8203; - bugfix on 0.2.0.24-rc. Patch by "Desoxy." diff --git a/changes/bug8207 b/changes/bug8207 deleted file mode 100644 index 0028d3380f..0000000000 --- a/changes/bug8207 +++ /dev/null @@ -1,7 +0,0 @@ - o Major bugfixes (hidden services): - - Allow hidden service authentication to succeed again. When we - refactored the hidden service introduction code back in 0.2.4.1-alpha, - we didn't update the code that checks whether authentication - information is present, causing all authentication checks to - return "false". Fix for bug 8207; bugfix on 0.2.4.1-alpha. Found by - Coverity; this is CID 718615. diff --git a/changes/bug8208 b/changes/bug8208 deleted file mode 100644 index c85db90b52..0000000000 --- a/changes/bug8208 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Avoid a crash if we fail to generate an extrinfo descriptor. - Fixes bug 8208; bugfix on 0.2.3.16-alpha. Found by Coverity; - this is CID 718634. diff --git a/changes/bug8209 b/changes/bug8209 deleted file mode 100644 index c58923540b..0000000000 --- a/changes/bug8209 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes: - - When detecting the largest possible file descriptor (in order to close - all file descriptors when launching a new program), actually use - _SC_OPEN_MAX. The old code for doing this was very, very broken. - Fix for bug 8209; bugfix on 0.2.3.1-alpha. Found by Coverity; this - is CID 743383. diff --git a/changes/bug8210 b/changes/bug8210 deleted file mode 100644 index 85d41b844a..0000000000 --- a/changes/bug8210 +++ /dev/null @@ -1,6 +0,0 @@ - o Minor bugfixes: - - Fix an impossible-to-trigger integer overflow when - estimating how long out onionskin queue would take. (This overflow - would require us to accept 4 million onionskins before processing - 100 of them.) Fixes bug 8210; bugfix on 0.2.4.10-alpha. - diff --git a/changes/bug8218 b/changes/bug8218 deleted file mode 100644 index ce8d53ba62..0000000000 --- a/changes/bug8218 +++ /dev/null @@ -1,6 +0,0 @@ - o Major bugfixes: - - Stop marking every relay as having been down for one hour every - time we restart a directory authority. These artificial downtimes - were messing with our Stable and Guard flag calculations. Fixes - bug 8218 (introduced by the fix for 1035). Bugfix on 0.2.2.23-alpha. - diff --git a/changes/bug8231 b/changes/bug8231 deleted file mode 100644 index fd87a1daec..0000000000 --- a/changes/bug8231 +++ /dev/null @@ -1,5 +0,0 @@ - o Major bugfixes: - - When unable to find any working directory nodes to use as a - directory guard, give up rather than adding the same non-working - nodes to the list over and over. Fixes bug 8231; bugfix on - 0.2.4.8-alpha. diff --git a/changes/bug8235-diagnosing b/changes/bug8235-diagnosing deleted file mode 100644 index b760035cfc..0000000000 --- a/changes/bug8235-diagnosing +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features (diagnostic) - - If the state file's path bias counts are invalid (presumably from a - buggy tor prior to 0.2.4.10-alpha), make them correct. - - Add additional checks and log messages to the scaling of Path Bias - counts, in case there still are remaining issues with scaling. diff --git a/changes/bug8273 b/changes/bug8273 deleted file mode 100644 index 257f57e7ab..0000000000 --- a/changes/bug8273 +++ /dev/null @@ -1,3 +0,0 @@ - o Critical bugfixes: - - When dirserv.c computes flags and thresholds, use measured bandwidths - in preference to advertised ones. diff --git a/changes/bug8290 b/changes/bug8290 deleted file mode 100644 index d1fce7d8b5..0000000000 --- a/changes/bug8290 +++ /dev/null @@ -1,9 +0,0 @@ - o Removed files: - - The tor-tsocks.conf is no longer distributed or installed. We - recommend that tsocks users use torsocks instead. Resolves - ticket 8290. - - o Documentation fixes: - - The torify manpage no longer refers to tsocks; torify hasn't - supported tsocks since 0.2.3.14-alpha. - - The manpages no longer reference tsocks. diff --git a/changes/bug8377 b/changes/bug8377 deleted file mode 100644 index c9ad151bc9..0000000000 --- a/changes/bug8377 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Correctly recognize that [::1] is a loopback address. Fixes bug #8377; - bugfix on 0.2.1.3-alpha. diff --git a/changes/bug8408 b/changes/bug8408 deleted file mode 100644 index ae9cf172e1..0000000000 --- a/changes/bug8408 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Allow TestingTorNetworks to override the 4096-byte minimum for the Fast - threshold. Otherwise they can't bootstrap until they've observed more - traffic. Fixes bug 8508; bugfix on 0.2.4.10-alpha. diff --git a/changes/bug8427 b/changes/bug8427 deleted file mode 100644 index 22b003fc38..0000000000 --- a/changes/bug8427 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes: - - If we encounter a write failure on a SOCKS connection before we - finish our SOCKS handshake, don't warn that we closed the - connection before we could send a SOCKS reply. Fixes bug 8427; - bugfix on 0.1.0.1-rc. diff --git a/changes/bug8435 b/changes/bug8435 deleted file mode 100644 index da7ca7c1f8..0000000000 --- a/changes/bug8435 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes: - - When dirserv.c computes flags and thresholds, ignore advertised - bandwidths if we have more than a threshold number of routers with - measured bandwidths. diff --git a/changes/bug8464 b/changes/bug8464 deleted file mode 100644 index 74ff2e39ff..0000000000 --- a/changes/bug8464 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes: - - Correct our check for which versions of Tor support the EXTEND2 - cell. We had been willing to send it to Tor 0.2.4.7-alpha and - later, when support was really added in version 0.2.4.8-alpha. - Fixes bug 8464; bugfix on 0.2.4.8-alpha. diff --git a/changes/bug8475 b/changes/bug8475 deleted file mode 100644 index eb8debedba..0000000000 --- a/changes/bug8475 +++ /dev/null @@ -1,4 +0,0 @@ - o Major bugfixes: - - If configured via ClientDNSRejectInternalAddresses not to report - DNS queries which have resolved to internal addresses, apply that - rule to IPv6 as well. Fixes bug 8475; bugfix on 0.2.0.7-alpha. diff --git a/changes/bug8477-easypart b/changes/bug8477-easypart deleted file mode 100644 index 0f8f1031c5..0000000000 --- a/changes/bug8477-easypart +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Log the purpose of a path-bias testing circuit correctly. - Improves a log message from bug 8477; bugfix on 0.2.4.8-alpha. diff --git a/changes/bug8530 b/changes/bug8530 new file mode 100644 index 0000000000..f66b602dbd --- /dev/null +++ b/changes/bug8530 @@ -0,0 +1,3 @@ + o Enhancements + - Add make target 'test-network' running tests on a Chutney + network. diff --git a/changes/bug8532 b/changes/bug8532 new file mode 100644 index 0000000000..e9fd06829a --- /dev/null +++ b/changes/bug8532 @@ -0,0 +1,4 @@ + o Minor features + - Add support for offsetting the voting interval in order to + bootstrap a network faster by adding configuration option + TestingV3AuthVotingStartOffset. Addresses #8532. diff --git a/changes/bug8561 b/changes/bug8561 new file mode 100644 index 0000000000..598071a728 --- /dev/null +++ b/changes/bug8561 @@ -0,0 +1,3 @@ + o Major features: + - The ntor handshake is now on-by-default, no matter what the + directory authorities recommend. Implements ticket 8561. diff --git a/changes/bug8587 b/changes/bug8587 deleted file mode 100644 index 84d2f1ec0d..0000000000 --- a/changes/bug8587 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (build): - - Build Tor correctly on 32-bit platforms where the compiler can build - but not run code using the "uint128_t" construction. Fixes bug 8587; - bugfix on 0.2.4.8-alpha. - diff --git a/changes/bug8596 b/changes/bug8596 deleted file mode 100644 index dd36bad855..0000000000 --- a/changes/bug8596 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Add CACHED keyword to ADDRMAP events in the control protocol to indicate - whether a DNS result will be cached or not. diff --git a/changes/bug8598 b/changes/bug8598 deleted file mode 100644 index e31c8f3c74..0000000000 --- a/changes/bug8598 +++ /dev/null @@ -1,6 +0,0 @@ - o Bugfixes: - - Fix compilation warning with some versions of clang that would prefer - the -Wswitch-enum compiler flag to warn about switch statements with - missing enum values, even if those switch statements have a default: - statement. Fixes bug 8598; bugfix on 0.2.4.10-alpha. - diff --git a/changes/bug8599 b/changes/bug8599 deleted file mode 100644 index 204ef58c3f..0000000000 --- a/changes/bug8599 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Fix some logic errors when the user manually overrides the - PathsNeededToBuildCircuits option in torrc. Fixes bug 8599; bugfix - on 0.2.4.10-alpha. diff --git a/changes/bug8638 b/changes/bug8638 deleted file mode 100644 index 3a790e567d..0000000000 --- a/changes/bug8638 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features - In our testsuite, create temporary directories with a bit more entropy - in their name to make name collissions less likely. Fixes bug 8638. diff --git a/changes/bug8789 b/changes/bug8789 new file mode 100644 index 0000000000..e3bcc40749 --- /dev/null +++ b/changes/bug8789 @@ -0,0 +1,3 @@ + o Code simplifications and refactoring: + - Clean up exit path from connection_listener_new. Closes bug + 8789. Patch from Arlo Breault. diff --git a/changes/bug8790 b/changes/bug8790 new file mode 100644 index 0000000000..9f1f0ba17d --- /dev/null +++ b/changes/bug8790 @@ -0,0 +1,6 @@ + o Minor code improvements: + - Remove instances of strcpy from the unit tests. They weren't + hurting anything, since they were only in the unit tests, but + it's embarassing to have strcpy() in the code at all, and some + analysis tools don't like it. Fixes 8790. Patch from Arlo Breault. + diff --git a/changes/bug8791 b/changes/bug8791 new file mode 100644 index 0000000000..0a65e286c0 --- /dev/null +++ b/changes/bug8791 @@ -0,0 +1,5 @@ + o Minor bugfixes: + - In the function munge_extrainfo_into_routerinfo(), check the return + value of memchr(). This would have been a serious issue if we ever + passed a non-extrainfo to munge_extrainfo_into_routerinfo. Fixes + bug 8791; bugfix on 0.2.0.6-alpha. Patch from Arlo Breault. diff --git a/changes/bug8792 b/changes/bug8792 new file mode 100644 index 0000000000..6f4e3bf7b1 --- /dev/null +++ b/changes/bug8792 @@ -0,0 +1,4 @@ + o Removed code + - Remove constants and tests for PKCS1 padding; it's insecure and + shouldn't be used for anything new. Fixes bug #8792; patch + from Arlo Breault. diff --git a/changes/bug8929 b/changes/bug8929 new file mode 100644 index 0000000000..2a1898b8a9 --- /dev/null +++ b/changes/bug8929 @@ -0,0 +1,4 @@ + o Minor features: + - Add a new torrc option "ServerTransportOptions" that allows + bridge operators to pass configuration parameters to their + pluggable transports. Resolves ticket 8929. diff --git a/changes/bug9030 b/changes/bug9030 new file mode 100644 index 0000000000..d0be582929 --- /dev/null +++ b/changes/bug9030 @@ -0,0 +1,4 @@ + o Minor bugfixes: + - The tor-fw-helper program now follows the standard convention and + exits with status code "0" on success. Fixes bug 9030; bugfix on + 0.2.3.1-alpha. Patch by Arlo Breault. diff --git a/changes/bug9043 b/changes/bug9043 new file mode 100644 index 0000000000..c3135ef0f4 --- /dev/null +++ b/changes/bug9043 @@ -0,0 +1,3 @@ + o Code simplification and refactoring: + - Since OpenSSL 0.9.8 we can use EVP_PKEY_cmp instead of + implementing the same thing as pkey_eq. Fixes #9043. diff --git a/changes/bug9063 b/changes/bug9063 index dcbecf6179..e1d0a5e780 100644 --- a/changes/bug9063 +++ b/changes/bug9063 @@ -1,3 +1,4 @@ - o Normal bugfixes: - - Close any circuit that has more cells queued than the spec permits. - Fixes bug #9063; bugfix on 0.2.4.12. + o Normal bugfixes: + - Close any circuit that has 10% more cells queued than the spec permits + and warn when the queue length exceeds that threshold. Fixes bug + #9063; bugfix on 0.2.4.12. diff --git a/changes/bug9258 b/changes/bug9258 new file mode 100644 index 0000000000..5165b3a677 --- /dev/null +++ b/changes/bug9258 @@ -0,0 +1,6 @@ + o Minor bugfixes: + - Reject relative control socket paths and emit a warning. + Previously single-component control socket paths would be rejected, + but Tor would not log why it could not validate the config. + Now we reject all relative control socket paths and print a warning. + Fixes bug 9047; bugfix on 0.2.2.6-alpha. diff --git a/changes/bug9267 b/changes/bug9267 new file mode 100644 index 0000000000..95a621148d --- /dev/null +++ b/changes/bug9267 @@ -0,0 +1,4 @@ + o Minor bugfixes: + - Added optional parameter to contrib/coverage script to specify directory + to put gcov files in, and added reset-gcov target to top-level makefile. + Fixes bug #9267. diff --git a/changes/cov980650 b/changes/cov980650 deleted file mode 100644 index cbbada2e66..0000000000 --- a/changes/cov980650 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Fix a copy-and-paste error when adding a missing A1 to a routerset - because of GeoIPExcludeUnknown. Fix for coverity CID 980650. - Bugfix on 0.2.4.10-alpha. diff --git a/changes/easy.ratelim b/changes/easy.ratelim deleted file mode 100644 index cadd1e4f5e..0000000000 --- a/changes/easy.ratelim +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplification and refactoring: - - Add a wrapper function for the common "log a message with a rate-limit" - case. diff --git a/changes/fancy_testing b/changes/fancy_testing new file mode 100644 index 0000000000..fa5b5703c4 --- /dev/null +++ b/changes/fancy_testing @@ -0,0 +1,27 @@ + o Build features: + + - Tor now builds each source file in two modes: a mode that avoids + exposing identifiers needlessly, and another mode that exposes + more identifiers for testing. This lets the compiler do better at + optimizing the production code, while enabling us to take more + radical measures to let the unit tests test things. + + - The production builds no longer include functions used only + in the unit tests; all functions exposed from a module for + unit-testing only are now static in production builds. + + - Add an --enable-coverage configuration option to make the unit + tests (and a new src/or/tor-cov target) to build with gcov test + coverage support. + + o Testing: + + - We now have rudimentary function mocking support that our unit + tests can use to test functions in isolation. Function mocking + lets the tests temporarily replace a function's dependencies with + stub functions, so that the tests can check the function without + invoking the other functions it calls. + + - Add more unit tests for the <circid,channel>->circuit map, and + the destroy-cell-tracking code to fix bug 7912. + diff --git a/changes/feature4994 b/changes/feature4994 deleted file mode 100644 index 4fa0e037b7..0000000000 --- a/changes/feature4994 +++ /dev/null @@ -1,7 +0,0 @@ - o Minor features: - - Teach bridge-using clients to avoid 0.2.2 bridges when making - microdescriptor-related dir requests, and only fall back to normal - descriptors if none of their bridges can handle microdescriptors - (as opposed to the fix in ticket 4013, which caused them to fall - back to normal descriptors if *any* of their bridges preferred - them). Resolves ticket 4994. diff --git a/changes/fix-geoipexclude-doc b/changes/fix-geoipexclude-doc deleted file mode 100644 index 63b544ef29..0000000000 --- a/changes/fix-geoipexclude-doc +++ /dev/null @@ -1,4 +0,0 @@ - o Documentation fixes: - - Fix the GeoIPExcludeUnknown documentation to refer to ExcludeExitNodes - rather than the currently nonexistent ExcludeEntryNodes. Spotted by - "hamahangi" on tor-talk. diff --git a/changes/fomit-frame-pointer b/changes/fomit-frame-pointer new file mode 100644 index 0000000000..67706246ad --- /dev/null +++ b/changes/fomit-frame-pointer @@ -0,0 +1,6 @@ + o Minor features (performance): + - If we're using the pure-C 32-bit curve25519_donna implementation + of curve25519, build it with the -fomit-frame-pointer option to + make it go faster on register-starved hosts. This improves our + handshake performance by about 6% on i386 hosts without nacl. + Closes ticket 8109. diff --git a/changes/geoip-apr2013 b/changes/geoip-apr2013 deleted file mode 100644 index 74d9c63b79..0000000000 --- a/changes/geoip-apr2013 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Update to the April 3 2013 Maxmind GeoLite Country database. - diff --git a/changes/geoip-feb2013 b/changes/geoip-feb2013 deleted file mode 100644 index b5d794258f..0000000000 --- a/changes/geoip-feb2013 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Update to the February 6 2013 Maxmind GeoLite Country database. - diff --git a/changes/geoip-mar2013 b/changes/geoip-mar2013 deleted file mode 100644 index e9cc3981b3..0000000000 --- a/changes/geoip-mar2013 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Update to the March 6 2013 Maxmind GeoLite Country database. - diff --git a/changes/integers_donna b/changes/integers_donna deleted file mode 100644 index e9c69e8e1c..0000000000 --- a/changes/integers_donna +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes (portability) - - Tweak the curve25519-donna*.c implementations to tolerate systems - that lack stdint.h. Fixes bug 3894; bugfix on 0.2.4.8-alpha. diff --git a/changes/log-noise b/changes/log-noise deleted file mode 100644 index bbbf0d2c0c..0000000000 --- a/changes/log-noise +++ /dev/null @@ -1,11 +0,0 @@ - o Minor bugfixes (log message reduction) - - Fix a path state issue that triggered a notice during relay startup. - Fixes bug #8320; bugfix on 0.2.4.10-alpha. - - Reduce occurrences of warns about circuit purpose in - connection_ap_expire_building(). Fixes bug #8477; bugfix on - 0.2.4.11-alpha. - - Fix a directory authority warn caused when we have a large amount - of badexit bandwidth. Fixes bug #8419; bugfix on 0.2.2.10-alpha. - - Reduce a path bias length check notice log to info. The notice - is triggered when creating controller circuits. Fixes bug #8196; - bugfix on 0.2.4.8-alpha. diff --git a/changes/onion_tap_tests b/changes/onion_tap_tests new file mode 100644 index 0000000000..f98243323e --- /dev/null +++ b/changes/onion_tap_tests @@ -0,0 +1,2 @@ + o New unit tests: + - Unit tests for failing cases of the TAP onion handshake. diff --git a/changes/seccomp2_sandbox b/changes/seccomp2_sandbox new file mode 100644 index 0000000000..73b3a8d5e4 --- /dev/null +++ b/changes/seccomp2_sandbox @@ -0,0 +1,12 @@ + o Major features (security): + - Use the seccomp2 syscall filtering facility on Linux to limit + which system calls Tor can invoke. This is an experimental, + Linux-only feature to provide defense-in-depth against unknown + attacks. To try turning it on, set "Sandbox 1" in your torrc + file. This is an experimental feature, however, and some things + may break, so please be ready to report bugs. We hope to add + support for better sandboxing in the future, + including more fine-grained filters, better division of + responsibility, and support for more platforms. This work has + been done by Cristian-Matei Toader for Google Summer of Code. + diff --git a/changes/signof_enum b/changes/signof_enum deleted file mode 100644 index ba4fb597d7..0000000000 --- a/changes/signof_enum +++ /dev/null @@ -1,7 +0,0 @@ - o Code simplifications and refactoring: - - Use Ville Laurikari's implementation of AX_CHECK_SIGN() to determine - the signs of types during autoconf. This is better than our old - approach, which didn't work when cross-compiling. - - Detect the sign of enum values, rather than assuming that MSC is the - only compiler where enum types are all signed. Fix for bug 7727; - bugfix on 0.2.4.10-alpha. diff --git a/changes/ticket2267 b/changes/ticket2267 deleted file mode 100644 index b589b5721f..0000000000 --- a/changes/ticket2267 +++ /dev/null @@ -1,8 +0,0 @@ - o Minor features: - - Refactor resolve_my_address() so it returns the method by which we - decided our public IP address (explicitly configured, resolved from - explicit hostname, guessed from interfaces, learned by gethostname). - Now we can provide more helpful log messages when a relay guesses - its IP address incorrectly (e.g. due to unexpected lines in - /etc/hosts). Resolves ticket 2267. - diff --git a/changes/ticket8240 b/changes/ticket8240 deleted file mode 100644 index 91e6f8c14a..0000000000 --- a/changes/ticket8240 +++ /dev/null @@ -1,4 +0,0 @@ - o Major security fixes: - - Make the default guard lifetime controllable via a new - GuardLifetime torrc option and a GuardLifetime consensus - parameter. Start of a fix for bug 8240; bugfix on 0.1.1.11-alpha. diff --git a/changes/ticket8443 b/changes/ticket8443 deleted file mode 100644 index ca6fb2f471..0000000000 --- a/changes/ticket8443 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor features: - - Randomize the lifetime of our SSL link certificate, so censors can't - use the static value for filtering Tor flows. Resolves ticket 8443; - related to ticket 4014 which was included in 0.2.2.33. diff --git a/changes/ticket_9214 b/changes/ticket_9214 new file mode 100644 index 0000000000..f1e43caeb0 --- /dev/null +++ b/changes/ticket_9214 @@ -0,0 +1,6 @@ + o Minor features: + - Accept bandwidth and space limits in bits as well as bytes. + (Anywhere in the configuration file that you can say "2 Kilobytes", + you can now say "16 kilobits", and so on.) Resolves ticket 9214. + Patch by CharlieB. + diff --git a/changes/warn-unsigned-time_t b/changes/warn-unsigned-time_t index 5f0c36d099..f57f85ae37 100644 --- a/changes/warn-unsigned-time_t +++ b/changes/warn-unsigned-time_t @@ -1,3 +1,9 @@ + o Minor bugfixes (portability): + - On the chance that somebody manages to build Tor on a + platform where time_t is unsigned, correct the way that + microdesc_add_to_cache handles negative time arguments. Fix for + bug 8042; bugfix on 0.2.3.1-alpha. + o Build improvements: - Warn if building on a platform with an unsigned time_t: there are too many places where Tor currently assumes that time_t can diff --git a/configure.ac b/configure.ac index 6f40ac4ad2..4aeec929ef 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson dnl Copyright (c) 2007-2013, The Tor Project, Inc. dnl See LICENSE for licensing information -AC_INIT([tor],[0.2.4.10-alpha-dev]) +AC_INIT([tor],[0.2.5.0-alpha-dev]) AC_CONFIG_SRCDIR([src/or/main.c]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE @@ -39,6 +39,13 @@ AC_ARG_ENABLE(static-tor, AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir)) AC_ARG_ENABLE(curve25519, AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support)) +AC_ARG_ENABLE(unittests, + AS_HELP_STRING(--disable-unittests, [Don't build unit tests for Tor. Risky!])) +AC_ARG_ENABLE(coverage, + AS_HELP_STRING(--enable-coverage, [Enable coverage support in the unit-test build])) + +AM_CONDITIONAL(UNITTESTS_ENABLED, test x$enable_unittests != xno) +AM_CONDITIONAL(COVERAGE_ENABLED, test x$enable_coverage = xyes) if test "$enable_static_tor" = "yes"; then enable_static_libevent="yes"; @@ -584,6 +591,19 @@ if test x$enable_linker_hardening != xno; then fi dnl ------------------------------------------------------ +dnl Now see if we have a -fomit-frame-pointer compiler option. + +saved_CFLAGS="$CFLAGS" +TOR_CHECK_CFLAGS(-fomit-frame-pointer) +if test "$saved_CFLAGS" != "$CFLAGS"; then + F_OMIT_FRAME_POINTER='-fomit-frame-pointer' +else + F_OMIT_FRAME_POINTER='' +fi +CFLAGS="$saved_CFLAGS" +AC_SUBST(F_OMIT_FRAME_POINTER) + +dnl ------------------------------------------------------ dnl Where do you live, libnatpmp? And how do we call you? dnl There are no packages for Debian or Redhat as of this patch @@ -643,6 +663,12 @@ if test "$upnp" = "true"; then fi dnl ============================================================ +dnl Check for libseccomp + +AC_CHECK_HEADERS([seccomp.h]) +AC_SEARCH_LIBS(seccomp_init, [seccomp]) + +dnl ============================================================ dnl We need an implementation of curve25519. dnl set these defaults. @@ -1440,7 +1466,12 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy # CFLAGS="$CFLAGS -Winline" fi - +if test "$enable_coverage" = yes && test "$have_clang" = "no"; then + case "$host_os" in + darwin*) + AC_MSG_WARN([Tried to enable coverage on OSX without using the clang compiler. This might not work! If coverage fails, use CC=clang when configuring with --enable-profiling.]) + esac +fi CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib" @@ -1455,6 +1486,22 @@ AC_CONFIG_FILES([ src/config/torrc.sample ]) +if test x$asciidoc = xtrue && test "$ASCIIDOC" = "none" ; then + regular_mans="doc/tor doc/tor-gencert doc/tor-resolve doc/torify" + for file in $regular_mans ; do + if ! [[ -f "$srcdir/$file.1.in" ]] || ! [[ -f "$srcdir/$file.html.in" ]] ; then + echo "=================================="; + echo; + echo "You need asciidoc installed to be able to build the manpage."; + echo "To build without manpages, use the --disable-asciidoc argument"; + echo "when calling configure."; + echo; + echo "=================================="; + exit 1; + fi + done +fi + AC_OUTPUT if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then diff --git a/contrib/cov-blame b/contrib/cov-blame new file mode 100755 index 0000000000..601f211952 --- /dev/null +++ b/contrib/cov-blame @@ -0,0 +1,48 @@ +#!/usr/bin/python + +import os +import re +import subprocess +import sys + +def handle_file(source_fname, cov_fname): + + lines_blm = subprocess.Popen(["git", "blame", source_fname], stdout=subprocess.PIPE).stdout.readlines() + lines_cov = open(cov_fname).readlines() + + # XXXX expensive! + while re.match(r'\s*-:\s*0:', lines_cov[0]): + del lines_cov[0] + + if len(lines_blm) != len(lines_cov): + print >>sys.stderr, "MISMATCH IN NUMBER OF LINES in",source_fname + + for b,c in zip(lines_blm, lines_cov): + m = re.match(r'\s*([^\s:]+):', c) + if not m: + print >>sys.stderr, "CONFUSING LINE %r"% c + cov = 'X' + elif m.group(1) == '-': + cov = '-' + elif m.group(1)[0] == '#': + cov = '#' + elif m.group(1)[0].isdigit(): + cov = '1' + else: + print >>sys.stderr, "CONFUSING LINE %r"% c + cov = 'X' + + print cov, b, + +COV_DIR = sys.argv[1] +SOURCES = sys.argv[2:] + +for fn in SOURCES: + _, base = os.path.split(fn) + cfn = os.path.join(COV_DIR, base) + cfn += ".gcov" + if os.path.exists(cfn): + handle_file(fn, cfn) + else: + print >>sys.stderr, "NO FILE EXISTS CALLED ",cfn + diff --git a/contrib/cov-diff b/contrib/cov-diff new file mode 100755 index 0000000000..33a54802b6 --- /dev/null +++ b/contrib/cov-diff @@ -0,0 +1,17 @@ +#!/bin/sh +# Copyright 2013 The Tor Project, Inc. +# See LICENSE for licensing information. + +# cov-diff -- compare two directories full of gcov files. + +DIRA="$1" +DIRB="$2" + +for A in $DIRA/*; do + B=$DIRB/`basename $A` + perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/;' "$A" > "$A.tmp" + perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/;' "$B" > "$B.tmp" + diff -u "$A.tmp" "$B.tmp" + rm "$A.tmp" "$B.tmp" +done + diff --git a/contrib/coverage b/contrib/coverage new file mode 100755 index 0000000000..f4ae475828 --- /dev/null +++ b/contrib/coverage @@ -0,0 +1,46 @@ +#!/bin/sh +# Copyright 2013 The Tor Project, Inc. +# See LICENSE for licensing information. + +# coverage -- run gcov on the appropriate set of object files to extract +# coverage information. + +dst=$1 + +for fn in src/or/*.c src/common/*.c; do + BN=`basename $fn` + DN=`dirname $fn` + F=`echo $BN | sed -e 's/\.c$//;'` + GC="${BN}.gcov" + # Figure out the object file names + ONS=`echo ${DN}/src_*-${F}.o` + ONS_WILDCARD_LITERAL="${DN}/src_*-${F}.o" + # If the wildcard didn't expand, no files + if [ "$ONS" != "${ONS_WILDCARD_LITERAL}" ] + then + for on in $ONS; do + # We should have a gcno file + GCNO=`echo $on | sed -e 's/\.o$/\.gcno/;'` + if [ -e $GCNO ] + then + # No need to test for gcda, since gcov assumes no execution + # if it's absent + rm -f $GC + gcov -o $on $fn + if [ -e $GC ] + then + if [ -n $dst ] + then + mv $GC $dst/$GC + fi + else + echo "gcov -o $on $fn didn't make a .gcov file" + fi + else + echo "Couldn't find gcno file for $on" + fi + done + else + echo "No object file found matching source file $fn" + fi +done diff --git a/contrib/findMergedChanges.pl b/contrib/findMergedChanges.pl index e4ff6163e7..a35b0cf503 100755 --- a/contrib/findMergedChanges.pl +++ b/contrib/findMergedChanges.pl @@ -21,13 +21,13 @@ if (! @ARGV) { Usage: findMergedChanges.pl [--merged/--unmerged/--weird/--list] [--branch=<branchname] changes/* -A change is "merged" if it has ever been merged to release-0.2.2 and it has had +A change is "merged" if it has ever been merged to release-0.2.4 and it has had no subsequent changes in master. -A change is "unmerged" if it has never been merged to release-0.2.2 and it +A change is "unmerged" if it has never been merged to release-0.2.4 and it has had changes in master. -A change is "weird" if it has been merged to release-0.2.2 and it *has* had +A change is "weird" if it has been merged to release-0.2.4 and it *has* had subsequent changes in master. Suggested application: @@ -36,7 +36,7 @@ Suggested application: EOF } -my $target_branch = "origin/release-0.2.2"; +my $target_branch = "origin/release-0.2.4"; while (@ARGV and $ARGV[0] =~ /^--/) { my $flag = shift @ARGV; diff --git a/contrib/id_to_fp.c b/contrib/id_to_fp.c deleted file mode 100644 index 55b025dfaf..0000000000 --- a/contrib/id_to_fp.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright 2006 Nick Mathewson; see LICENSE for licensing information */ - -/* id_to_fp.c : Helper for directory authority ops. When somebody sends us - * a private key, this utility converts the private key into a fingerprint - * so you can de-list that fingerprint. - */ - -#include <openssl/rsa.h> -#include <openssl/bio.h> -#include <openssl/sha.h> -#include <openssl/pem.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define die(s) do { fprintf(stderr, "%s\n", s); goto err; } while (0) - -int -main(int argc, char **argv) -{ - BIO *b = NULL; - RSA *key = NULL; - unsigned char *buf = NULL, *bufp; - int len, i; - unsigned char digest[20]; - int status = 1; - - if (argc < 2) { - fprintf(stderr, "Reading key from stdin...\n"); - if (!(b = BIO_new_fp(stdin, BIO_NOCLOSE))) - die("couldn't read from stdin"); - } else if (argc == 2) { - if (strcmp(argv[1], "-h") == 0 || - strcmp(argv[1], "--help") == 0) { - fprintf(stdout, "Usage: %s [keyfile]\n", argv[0]); - status = 0; - goto err; - } else { - if (!(b = BIO_new_file(argv[1], "r"))) - die("couldn't open file"); - } - } else { - fprintf(stderr, "Usage: %s [keyfile]\n", argv[0]); - goto err; - } - if (!(key = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL))) - die("couldn't parse key"); - - len = i2d_RSAPublicKey(key, NULL); - if (len < 0) - die("Bizarre key"); - bufp = buf = malloc(len+1); - if (!buf) - die("Out of memory"); - len = i2d_RSAPublicKey(key, &bufp); - if (len < 0) - die("Bizarre key"); - - SHA1(buf, len, digest); - for (i=0; i < 20; i += 2) { - printf("%02X%02X ", (int)digest[i], (int)digest[i+1]); - } - printf("\n"); - - status = 0; - -err: - if (buf) - free(buf); - if (key) - RSA_free(key); - if (b) - BIO_free(b); - return status; -} - diff --git a/contrib/tor-mingw.nsi.in b/contrib/tor-mingw.nsi.in index d5379bd578..05d9ebc5c3 100644 --- a/contrib/tor-mingw.nsi.in +++ b/contrib/tor-mingw.nsi.in @@ -8,7 +8,7 @@ !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters -!define VERSION "0.2.4.10-alpha-dev" +!define VERSION "0.2.5.0-alpha-dev" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 86e9afc18d..8bc15d9c2e 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -124,42 +124,42 @@ option name with a forward slash. GENERAL OPTIONS --------------- -**BandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**BandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: A token bucket limits the average incoming bandwidth usage on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. If you want to run a relay in the public network, this needs to be _at the very least_ 30 KBytes (that is, 30720 bytes). (Default: 1 GByte) -**BandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**BandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: Limit the maximum token bucket size (also known as the burst) to the given number of bytes in each direction. (Default: 1 GByte) -**MaxAdvertisedBandwidth** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**MaxAdvertisedBandwidth** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: If set, we will not advertise more than this amount of bandwidth for our BandwidthRate. Server operators who want to reduce the number of clients who ask to build circuits through them (since this is proportional to advertised bandwidth rate) can thus reduce the CPU demands on their server without impacting network performance. -**RelayBandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**RelayBandwidthRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: If not 0, a separate token bucket limits the average incoming bandwidth usage for \_relayed traffic_ on this node to the specified number of bytes per second, and the average outgoing bandwidth usage to that same value. Relayed traffic currently is calculated to include answers to directory requests, but that may change in future versions. (Default: 0) -**RelayBandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**RelayBandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: If not 0, limit the maximum token bucket size (also known as the burst) for \_relayed traffic_ to the given number of bytes in each direction. (Default: 0) -**PerConnBWRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**PerConnBWRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0) -**PerConnBWBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**PerConnBWBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: If set, do separate rate limiting for each connection from a non-relay. You should never need to change this value, since a network-wide value is published in the consensus and your relay will use that value. (Default: 0) @@ -186,6 +186,11 @@ GENERAL OPTIONS listening address of any pluggable transport proxy that tries to launch __transport__. +**ServerTransportOptions** __transport__ __k=v__ __k=v__ ...:: + When this option is set, Tor will pass the __k=v__ parameters to + any pluggable transport proxy that tries to launch __transport__. + + (Example: ServerTransportOptions obfs45 shared-secret=bridgepasswd cache=/var/lib/tor/cache) + **ConnLimit** __NUM__:: The minimum number of file descriptors that must be available to the Tor process before it will start. Tor will ask the OS for as many file @@ -423,6 +428,11 @@ GENERAL OPTIONS proxy authentication that Tor supports; feel free to submit a patch if you want it to support others. +**Sandbox** **0**|**1**:: + If set to 1, Tor will run securely through the use of a syscall sandbox. + Otherwise the sandbox will be disabled. The option is currently an + experimental feature. (Default: 0) + **Socks4Proxy** __host__[:__port__]:: Tor will make all OR connections through the SOCKS 4 proxy at host:port (or host:1080 if port is not specified). @@ -1255,9 +1265,9 @@ The following options are useful only for clients (that is, if it too early might make your client stand out. If this option is 0, your Tor client won't use the ntor handshake. If it's 1, your Tor client will use the ntor handshake to extend circuits through servers that - support it. If this option is "auto" (recommended), then your client + support it. If this option is "auto", then your client will use the ntor handshake once enough directory authorities recommend - it. (Default: auto) + it. (Default: 1) **PathBiasCircThreshold** __NUM__ + @@ -1534,7 +1544,7 @@ is non-zero): server is still alive and doing useful things. Settings this to 0 will disable the heartbeat. (Default: 6 hours) -**AccountingMax** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**:: +**AccountingMax** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**|**TBytes**:: Never send more than the specified number of bytes in a given accounting period, or receive more than that number in the period. For example, with AccountingMax set to 1 GByte, a server could send 900 MBytes and @@ -1866,12 +1876,12 @@ DIRECTORY AUTHORITY SERVER OPTIONS Authoritative directories only. Like AuthDirMaxServersPerAddr, but applies to addresses shared with directory authorities. (Default: 5) -**AuthDirFastGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**AuthDirFastGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: Authoritative directories only. If non-zero, always vote the Fast flag for any relay advertising this amount of capacity or more. (Default: 100 KBytes) -**AuthDirGuardBWGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**AuthDirGuardBWGuarantee** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: Authoritative directories only. If non-zero, this advertised capacity or more is always sufficient to satisfy the bandwidth requirement for the Guard flag. (Default: 250 KBytes) @@ -2016,6 +2026,17 @@ The following options are used for running a testing Tor network. TestingV3AuthInitialDistDelay 20 seconds TestingAuthDirTimeToLearnReachability 0 minutes TestingEstimatedDescriptorPropagationTime 0 minutes + TestingServerDownloadSchedule 0, 0, 0, 5, 10, 15, 20, 30, 60 + TestingClientDownloadSchedule 0, 0, 5, 10, 15, 20, 30, 60 + TestingServerConsensusDownloadSchedule 0, 0, 5, 10, 15, 20, 30, 60 + TestingClientConsensusDownloadSchedule 0, 0, 5, 10, 15, 20, 30, 60 + TestingBridgeDownloadSchedule 60, 30, 30, 60 + TestingClientMaxIntervalWithoutRequest 5 seconds + TestingDirConnectionMaxStall 30 seconds + TestingConsensusMaxDownloadTries 80 + TestingDescriptorMaxDownloadTries 80 + TestingMicrodescMaxDownloadTries 80 + TestingCertMaxDownloadTries 80 **TestingV3AuthInitialVotingInterval** __N__ **minutes**|**hours**:: Like V3AuthVotingInterval, but for initial voting interval before the first @@ -2032,6 +2053,10 @@ The following options are used for running a testing Tor network. the first consensus has been created. Changing this requires that **TestingTorNetwork** is set. (Default: 5 minutes) +**TestingV3AuthVotingStartOffset** __N__ **seconds**|**minutes**|**hours**:: + Directory authorities offset voting start time by this much. + Changing this requires that **TestingTorNetwork** is set. (Default: 0) + **TestingAuthDirTimeToLearnReachability** __N__ **minutes**|**hours**:: After starting as an authority, do not make claims about whether routers are Running until this much time has passed. Changing this requires @@ -2042,10 +2067,60 @@ The following options are used for running a testing Tor network. time. Changing this requires that **TestingTorNetwork** is set. (Default: 10 minutes) -**TestingMinFastFlagThreshold** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**:: +**TestingMinFastFlagThreshold** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**:: Minimum value for the Fast flag. Overrides the ordinary minimum taken from the consensus when TestingTorNetwork is set. (Default: 0.) +**TestingServerDownloadSchedule** __N__,__N__,__...__:: + Schedule for when servers should download things in general. Changing this + requires that **TestingTorNetwork** is set. (Default: 0, 0, 0, 60, 60, 120, + 300, 900, 2147483647) + +**TestingClientDownloadSchedule** __N__,__N__,__...__:: + Schedule for when clients should download things in general. Changing this + requires that **TestingTorNetwork** is set. (Default: 0, 0, 60, 300, 600, + 2147483647) + +**TestingServerConsensusDownloadSchedule** __N__,__N__,__...__:: + Schedule for when servers should download consensuses. Changing this + requires that **TestingTorNetwork** is set. (Default: 0, 0, 60, 300, 600, + 1800, 1800, 1800, 1800, 1800, 3600, 7200) + +**TestingClientConsensusDownloadSchedule** __N__,__N__,__...__:: + Schedule for when clients should download consensuses. Changing this + requires that **TestingTorNetwork** is set. (Default: 0, 0, 60, 300, 600, + 1800, 3600, 3600, 3600, 10800, 21600, 43200) + +**TestingBridgeDownloadSchedule** __N__,__N__,__...__:: + Schedule for when clients should download bridge descriptors. Changing this + requires that **TestingTorNetwork** is set. (Default: 3600, 900, 900, 3600) + +**TestingClientMaxIntervalWithoutRequest** __N__ **seconds**|**minutes**:: + When directory clients have only a few descriptors to request, they batch + them until they have more, or until this amount of time has passed. + Changing this requires that **TestingTorNetwork** is set. (Default: 10 + minutes) + +**TestingDirConnectionMaxStall** __N__ **seconds**|**minutes**:: + Let a directory connection stall this long before expiring it. + Changing this requires that **TestingTorNetwork** is set. (Default: + 5 minutes) + +**TestingConsensusMaxDownloadTries** __NUM__:: + Try this often to download a consensus before giving up. Changing + this requires that **TestingTorNetwork** is set. (Default: 8) + +**TestingDescriptorMaxDownloadTries** __NUM__:: + Try this often to download a router descriptor before giving up. + Changing this requires that **TestingTorNetwork** is set. (Default: 8) + +**TestingMicrodescMaxDownloadTries** __NUM__:: + Try this often to download a microdesc descriptor before giving up. + Changing this requires that **TestingTorNetwork** is set. (Default: 8) + +**TestingCertMaxDownloadTries** __NUM__:: + Try this often to download a v3 authority certificate before giving up. + Changing this requires that **TestingTorNetwork** is set. (Default: 8) SIGNALS ------- diff --git a/src/common/compat.c b/src/common/compat.c index 69eb0643d0..0e943f38fe 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -1746,6 +1746,15 @@ get_user_homedir(const char *username) * actually examine the filesystem; does a purely syntactic modification. * * The parent of the root director is considered to be iteself. + * + * Path separators are the forward slash (/) everywhere and additionally + * the backslash (\) on Win32. + * + * Cuts off any number of trailing path separators but otherwise ignores + * them for purposes of finding the parent directory. + * + * Returns 0 if a parent directory was successfully found, -1 otherwise (fname + * did not have any path separators or only had them at the end). * */ int get_parent_directory(char *fname) diff --git a/src/common/compat.h b/src/common/compat.h index 8ab7190526..258fc99020 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -84,13 +84,19 @@ /* ===== Compiler compatibility */ -/* GCC can check printf types on arbitrary functions. */ +/* GCC can check printf and scanf types on arbitrary functions. */ #ifdef __GNUC__ #define CHECK_PRINTF(formatIdx, firstArg) \ __attribute__ ((format(printf, formatIdx, firstArg))) #else #define CHECK_PRINTF(formatIdx, firstArg) #endif +#ifdef __GNUC__ +#define CHECK_SCANF(formatIdx, firstArg) \ + __attribute__ ((format(scanf, formatIdx, firstArg))) +#else +#define CHECK_SCANF(formatIdx, firstArg) +#endif /* inline is __inline on windows. */ #ifdef _WIN32 diff --git a/src/common/container.c b/src/common/container.c index eec497a3e6..476dc82913 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -243,6 +243,25 @@ smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) return 1; } +/** Return true iff the two lists contain the same int pointer values in + * the same order, or if they are both NULL. */ +int +smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, int *, cp1, { + int *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (*cp1 != *cp2) + return 0; + }); + return 1; +} + /** Return true iff <b>sl</b> has some element E such that * tor_memeq(E,<b>element</b>,DIGEST_LEN) */ diff --git a/src/common/container.h b/src/common/container.h index 1a68b8f67b..1bcc540665 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -42,6 +42,7 @@ int smartlist_contains_string_case(const smartlist_t *sl, const char *element); int smartlist_contains_int_as_string(const smartlist_t *sl, int num); int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); int smartlist_contains_digest(const smartlist_t *sl, const char *element); +int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); diff --git a/src/common/crypto.c b/src/common/crypto.c index 0ababeaea5..730ce08286 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -114,7 +114,6 @@ crypto_get_rsa_padding_overhead(int padding) switch (padding) { case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; - case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD; default: tor_assert(0); return -1; } } @@ -126,7 +125,6 @@ crypto_get_rsa_padding(int padding) { switch (padding) { - case PK_PKCS1_PADDING: return RSA_PKCS1_PADDING; case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; default: tor_assert(0); return -1; } @@ -1154,22 +1152,21 @@ int crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len) { int len; - unsigned char *buf, *cp; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0 || (size_t)len > dest_len || dest_len > SIZE_T_CEILING) + unsigned char *buf = NULL; + + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - cp = buf = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &cp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); + + if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) { + OPENSSL_free(buf); return -1; } /* We don't encode directly into 'dest', because that would be illegal * type-punning. (C99 is smarter than me, C99 is smarter than me...) */ memcpy(dest,buf,len); - tor_free(buf); + OPENSSL_free(buf); return len; } @@ -1200,24 +1197,17 @@ crypto_pk_asn1_decode(const char *str, size_t len) int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out) { - unsigned char *buf, *bufp; + unsigned char *buf = NULL; int len; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0) + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - buf = bufp = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &bufp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); - return -1; - } if (crypto_digest(digest_out, (char*)buf, len) < 0) { - tor_free(buf); + OPENSSL_free(buf); return -1; } - tor_free(buf); + OPENSSL_free(buf); return 0; } @@ -1226,31 +1216,24 @@ crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out) int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out) { - unsigned char *buf, *bufp; + unsigned char *buf = NULL; int len; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0) - return -1; - buf = bufp = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &bufp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - } if (crypto_digest_all(digests_out, (char*)buf, len) < 0) { - tor_free(buf); + OPENSSL_free(buf); return -1; } - tor_free(buf); + OPENSSL_free(buf); return 0; } /** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces * every four spaces. */ -/* static */ void -add_spaces_to_fp(char *out, size_t outlen, const char *in) +void +crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) { int n = 0; char *end = out+outlen; @@ -1287,7 +1270,7 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space) } base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN); if (add_space) { - add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); + crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); } else { strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1); } @@ -1637,21 +1620,6 @@ crypto_digest_smartlist(char *digest_out, size_t len_out, crypto_digest_free(d); } -/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using - * the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result - * in <b>hmac_out</b>. - */ -void -crypto_hmac_sha1(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - HMAC(EVP_sha1(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); -} - /** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte * result in <b>hmac_out</b>. @@ -1720,7 +1688,7 @@ crypto_store_dynamic_dh_modulus(const char *fname) { int len, new_len; DH *dh = NULL; - unsigned char *dh_string_repr = NULL, *cp = NULL; + unsigned char *dh_string_repr = NULL; char *base64_encoded_dh = NULL; char *file_string = NULL; int retval = -1; @@ -1744,15 +1712,8 @@ crypto_store_dynamic_dh_modulus(const char *fname) if (!BN_set_word(dh->g, DH_GENERATOR)) goto done; - len = i2d_DHparams(dh, NULL); - if (len < 0) { - log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (1)."); - goto done; - } - - cp = dh_string_repr = tor_malloc_zero(len+1); - len = i2d_DHparams(dh, &cp); - if ((len < 0) || ((cp - dh_string_repr) != len)) { + len = i2d_DHparams(dh, &dh_string_repr); + if ((len < 0) || (dh_string_repr == NULL)) { log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2)."); goto done; } @@ -1779,7 +1740,8 @@ crypto_store_dynamic_dh_modulus(const char *fname) done: if (dh) DH_free(dh); - tor_free(dh_string_repr); + if (dh_string_repr) + OPENSSL_free(dh_string_repr); tor_free(base64_encoded_dh); tor_free(file_string); diff --git a/src/common/crypto.h b/src/common/crypto.h index 2fbca4c260..651d553a4e 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -15,6 +15,7 @@ #include <stdio.h> #include "torint.h" +#include "testsupport.h" /* Macro to create an arbitrary OpenSSL version number as used by @@ -69,13 +70,9 @@ * signs removed. */ #define BASE64_DIGEST256_LEN 43 -/** Constant used to indicate PKCS1 padding for public-key encryption */ -#define PK_PKCS1_PADDING 60001 /** Constant used to indicate OAEP padding for public-key encryption */ #define PK_PKCS1_OAEP_PADDING 60002 -/** Number of bytes added for PKCS1 padding. */ -#define PKCS1_PADDING_OVERHEAD 11 /** Number of bytes added for PKCS1-OAEP padding. */ #define PKCS1_OAEP_PADDING_OVERHEAD 42 @@ -221,9 +218,6 @@ void crypto_digest_get_digest(crypto_digest_t *digest, crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest); void crypto_digest_assign(crypto_digest_t *into, const crypto_digest_t *from); -void crypto_hmac_sha1(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len); void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len); @@ -290,7 +284,6 @@ void secret_to_key(char *key_out, size_t key_out_len, const char *secret, /** OpenSSL-based utility functions. */ void memwipe(void *mem, uint8_t byte, size_t sz); -#ifdef CRYPTO_PRIVATE /* Prototypes for private functions only used by tortls.c, crypto.c, and the * unit tests. */ struct rsa_st; @@ -301,9 +294,8 @@ crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa); struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private); struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); -/* Prototypes for private functions only used by crypto.c and test.c*/ -void add_spaces_to_fp(char *out, size_t outlen, const char *in); -#endif + +void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); #endif diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c index 88c723f37c..9e83440e16 100644 --- a/src/common/crypto_curve25519.c +++ b/src/common/crypto_curve25519.c @@ -29,7 +29,7 @@ int curve25519_donna(uint8_t *mypublic, #endif #endif -int +STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, const uint8_t *basepoint) { diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h index 652f1883c6..f9d533ba22 100644 --- a/src/common/crypto_curve25519.h +++ b/src/common/crypto_curve25519.h @@ -4,6 +4,7 @@ #ifndef TOR_CRYPTO_CURVE25519_H #define TOR_CRYPTO_CURVE25519_H +#include "testsupport.h" #include "torint.h" /** Length of a curve25519 public key when encoded. */ @@ -52,8 +53,8 @@ int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, const char *fname); #ifdef CRYPTO_CURVE25519_PRIVATE -int curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *basepoint); +STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, + const uint8_t *basepoint); #endif #endif diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c index 93932f839c..be669c8d2b 100644 --- a/src/common/crypto_format.c +++ b/src/common/crypto_format.c @@ -3,7 +3,6 @@ /* Formatting and parsing code for crypto-related data structures. */ -#define CRYPTO_CURVE25519_PRIVATE #include "orconfig.h" #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> diff --git a/src/common/include.am b/src/common/include.am index b796ebfae8..032befd209 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -1,5 +1,15 @@ -noinst_LIBRARIES+= src/common/libor.a src/common/libor-crypto.a src/common/libor-event.a +noinst_LIBRARIES += \ + src/common/libor.a \ + src/common/libor-crypto.a \ + src/common/libor-event.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += \ + src/common/libor-testing.a \ + src/common/libor-crypto-testing.a \ + src/common/libor-event-testing.a +endif EXTRA_DIST+= \ src/common/common_sha1.i \ @@ -14,9 +24,13 @@ else libor_extra_source= endif +src_common_libcurve25519_donna_a_CFLAGS= + if BUILD_CURVE25519_DONNA src_common_libcurve25519_donna_a_SOURCES=\ src/ext/curve25519_donna/curve25519-donna.c +src_common_libcurve25519_donna_a_CFLAGS+=\ + @F_OMIT_FRAME_POINTER@ noinst_LIBRARIES+=src/common/libcurve25519_donna.a LIBDONNA=src/common/libcurve25519_donna.a else @@ -30,13 +44,11 @@ LIBDONNA= endif endif -src_common_libcurve25519_donna_a_CFLAGS = - if CURVE25519_ENABLED libcrypto_extra_source=src/common/crypto_curve25519.c endif -src_common_libor_a_SOURCES = \ +LIBOR_A_SOURCES = \ src/common/address.c \ src/common/compat.c \ src/common/container.c \ @@ -47,9 +59,10 @@ src_common_libor_a_SOURCES = \ src/common/procmon.c \ src/common/util.c \ src/common/util_codedigest.c \ + src/common/sandbox.c \ $(libor_extra_source) -src_common_libor_crypto_a_SOURCES = \ +LIBOR_CRYPTO_A_SOURCES = \ src/common/aes.c \ src/common/crypto.c \ src/common/crypto_format.c \ @@ -57,7 +70,23 @@ src_common_libor_crypto_a_SOURCES = \ src/common/tortls.c \ $(libcrypto_extra_source) -src_common_libor_event_a_SOURCES = src/common/compat_libevent.c +LIBOR_EVENT_A_SOURCES = src/common/compat_libevent.c + +src_common_libor_a_SOURCES = $(LIBOR_A_SOURCES) +src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES) +src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SOURCES) + +src_common_libor_testing_a_SOURCES = $(LIBOR_A_SOURCES) +src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES) +src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SOURCES) + +src_common_libor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS) +src_common_libor_crypto_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS) +src_common_libor_event_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS) +src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + COMMONHEADERS = \ src/common/address.h \ @@ -72,6 +101,8 @@ COMMONHEADERS = \ src/common/memarea.h \ src/common/mempool.h \ src/common/procmon.h \ + src/common/sandbox.h \ + src/common/testsupport.h \ src/common/torgzip.h \ src/common/torint.h \ src/common/torlog.h \ diff --git a/src/common/log.c b/src/common/log.c index e196a11287..303fba93a1 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -36,6 +36,10 @@ #include "torlog.h" #include "container.h" +/** Given a severity, yields an index into log_severity_list_t.masks to use + * for that severity. */ +#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR) + /** @{ */ /** The string we stick at the end of a log message when it is too long, * and its length. */ @@ -1138,6 +1142,22 @@ get_min_log_level(void) return min; } +/** Return the fd of a file log that is receiving ERR messages, or -1 if + * no such log exists. */ +int +get_err_logging_fd(void) +{ + const logfile_t *lf; + for (lf = logfiles; lf; lf = lf->next) { + if (lf->is_temporary || lf->is_syslog || !lf->filename || + lf->callback || lf->seems_dead || lf->fd < 0) + continue; + if (lf->severities->masks[LOG_ERR] & LD_GENERAL) + return lf->fd; + } + return -1; +} + /** Switch all logs to output at most verbose level. */ void switch_logs_debug(void) diff --git a/src/common/sandbox.c b/src/common/sandbox.c new file mode 100644 index 0000000000..dbb1657cdb --- /dev/null +++ b/src/common/sandbox.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file sandbox.c + * \brief Code to enable sandboxing. + **/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "orconfig.h" +#include "sandbox.h" +#include "torlog.h" +#include "util.h" + +#if defined(HAVE_SECCOMP_H) && defined(__linux__) +#define USE_LIBSECCOMP +#endif + +#define DEBUGGING_CLOSE + +#if defined(USE_LIBSECCOMP) + +#include <sys/syscall.h> +#include <seccomp.h> +#include <signal.h> +#include <unistd.h> + +/** Variable used for storing all syscall numbers that will be allowed with the + * stage 1 general Tor sandbox. + */ +static int general_filter[] = { + SCMP_SYS(access), + SCMP_SYS(brk), + SCMP_SYS(clock_gettime), + SCMP_SYS(close), + SCMP_SYS(clone), + SCMP_SYS(epoll_create), + SCMP_SYS(epoll_ctl), + SCMP_SYS(epoll_wait), + SCMP_SYS(execve), + SCMP_SYS(fcntl), +#ifdef __NR_fcntl64 + /* Older libseccomp versions don't define PNR entries for all of these, + * so we need to ifdef them here.*/ + SCMP_SYS(fcntl64), +#endif + SCMP_SYS(flock), + SCMP_SYS(fstat), +#ifdef __NR_fstat64 + SCMP_SYS(fstat64), +#endif + SCMP_SYS(futex), + SCMP_SYS(getdents64), + SCMP_SYS(getegid), +#ifdef __NR_getegid32 + SCMP_SYS(getegid32), +#endif + SCMP_SYS(geteuid), +#ifdef __NR_geteuid32 + SCMP_SYS(geteuid32), +#endif + SCMP_SYS(getgid), +#ifdef __NR_getgid32 + SCMP_SYS(getgid32), +#endif + SCMP_SYS(getrlimit), + SCMP_SYS(gettimeofday), + SCMP_SYS(getuid), +#ifdef __NR_getuid32 + SCMP_SYS(getuid32), +#endif + SCMP_SYS(lseek), +#ifdef __NR__llseek + SCMP_SYS(_llseek), +#endif + SCMP_SYS(mkdir), + SCMP_SYS(mlockall), + SCMP_SYS(mmap), +#ifdef __NR_mmap2 + SCMP_SYS(mmap2), +#endif + SCMP_SYS(mprotect), + SCMP_SYS(mremap), + SCMP_SYS(munmap), + SCMP_SYS(open), + SCMP_SYS(openat), + SCMP_SYS(poll), + SCMP_SYS(prctl), + SCMP_SYS(read), + SCMP_SYS(rename), + SCMP_SYS(rt_sigaction), + SCMP_SYS(rt_sigprocmask), + SCMP_SYS(rt_sigreturn), +#ifdef __NR_sigreturn + SCMP_SYS(sigreturn), +#endif + SCMP_SYS(set_robust_list), + SCMP_SYS(set_thread_area), + SCMP_SYS(set_tid_address), + SCMP_SYS(stat), +#ifdef __NR_stat64 + SCMP_SYS(stat64), +#endif + SCMP_SYS(time), + SCMP_SYS(uname), + SCMP_SYS(write), + SCMP_SYS(exit_group), + SCMP_SYS(exit), + + // socket syscalls + SCMP_SYS(accept4), + SCMP_SYS(bind), + SCMP_SYS(connect), + SCMP_SYS(getsockname), + SCMP_SYS(getsockopt), + SCMP_SYS(listen), +#if __NR_recv >= 0 + /* This is a kludge; It's necessary on 64-bit with libseccomp 1.0.0; I + * don't know if other 64-bit or other versions require it. */ + SCMP_SYS(recv), +#endif + SCMP_SYS(recvmsg), +#if __NR_send >= 0 + SCMP_SYS(send), +#endif + SCMP_SYS(sendto), + SCMP_SYS(setsockopt), + SCMP_SYS(socket), + SCMP_SYS(socketpair), + + // TODO: remove when accept4 is fixed +#ifdef __NR_socketcall + SCMP_SYS(socketcall), +#endif + + SCMP_SYS(recvfrom), + SCMP_SYS(unlink) +}; + +/** + * Function responsible for setting up and enabling a global syscall filter. + * The function is a prototype developed for stage 1 of sandboxing Tor. + * Returns 0 on success. + */ +static int +install_glob_syscall_filter(void) +{ + int rc = 0, i, filter_size; + scmp_filter_ctx ctx; + + ctx = seccomp_init(SCMP_ACT_TRAP); + if (ctx == NULL) { + log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context"); + rc = -1; + goto end; + } + + if (general_filter != NULL) { + filter_size = sizeof(general_filter) / sizeof(general_filter[0]); + } else { + filter_size = 0; + } + + // add general filters + for (i = 0; i < filter_size; i++) { + rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, general_filter[i], 0); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add syscall index %d, " + "received libseccomp error %d", i, rc); + goto end; + } + } + + rc = seccomp_load(ctx); + + end: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} + +/** Additional file descriptor to use when logging seccomp2 failures */ +static int sigsys_debugging_fd = -1; + +/** Use the file descriptor <b>fd</b> to log seccomp2 failures. */ +static void +sigsys_set_debugging_fd(int fd) +{ + sigsys_debugging_fd = fd; +} + +/** + * Function called when a SIGSYS is caught by the application. It notifies the + * user that an error has occurred and either terminates or allows the + * application to continue execution, based on the DEBUGGING_CLOSE symbol. + */ +static void +sigsys_debugging(int nr, siginfo_t *info, void *void_context) +{ + ucontext_t *ctx = (ucontext_t *) (void_context); + char message[256]; + int rv = 0, syscall, length, err; + (void) nr; + + if (info->si_code != SYS_SECCOMP) + return; + + if (!ctx) + return; + + syscall = ctx->uc_mcontext.gregs[REG_SYSCALL]; + + strlcpy(message, "\n\n(Sandbox) Caught a bad syscall attempt (syscall 0x", + sizeof(message)); + (void) format_hex_number_sigsafe(syscall, message+strlen(message), + sizeof(message)-strlen(message)); + strlcat(message, ")\n", sizeof(message)); + length = strlen(message); + + err = 0; + if (sigsys_debugging_fd >= 0) { + rv = write(sigsys_debugging_fd, message, length); + err += rv != length; + } + + rv = write(STDOUT_FILENO, message, length); + err += rv != length; + + if (err) + _exit(2); + +#if defined(DEBUGGING_CLOSE) + _exit(1); +#endif // DEBUGGING_CLOSE +} + +/** + * Function that adds a handler for SIGSYS, which is the signal thrown + * when the application is issuing a syscall which is not allowed. The + * main purpose of this function is to help with debugging by identifying + * filtered syscalls. + */ +static int +install_sigsys_debugging(void) +{ + struct sigaction act; + sigset_t mask; + + memset(&act, 0, sizeof(act)); + sigemptyset(&mask); + sigaddset(&mask, SIGSYS); + + act.sa_sigaction = &sigsys_debugging; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGSYS, &act, NULL) < 0) { + log_err(LD_BUG,"(Sandbox) Failed to register SIGSYS signal handler"); + return -1; + } + + if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { + log_err(LD_BUG,"(Sandbox) Failed call to sigprocmask()"); + return -2; + } + + return 0; +} +#endif // USE_LIBSECCOMP + +#ifdef USE_LIBSECCOMP +/** + * Initialises the syscall sandbox filter for any linux architecture, taking + * into account various available features for different linux flavours. + */ +static int +initialise_libseccomp_sandbox(void) +{ + if (install_sigsys_debugging()) + return -1; + + if (install_glob_syscall_filter()) + return -2; + + return 0; +} + +#endif // USE_LIBSECCOMP + +/** + * Enables the stage 1 general sandbox. It applies a syscall filter which does + * not restrict any Tor features. The filter is representative for the whole + * application. + */ +int +tor_global_sandbox(void) +{ + +#if defined(USE_LIBSECCOMP) + return initialise_libseccomp_sandbox(); + +#elif defined(_WIN32) + log_warn(LD_BUG,"Windows sandboxing is not implemented. The feature is " + "currently disabled."); + return 0; + +#elif defined(TARGET_OS_MAC) + log_warn(LD_BUG,"Mac OSX sandboxing is not implemented. The feature is " + "currently disabled"); + return 0; +#else + log_warn(LD_BUG,"Sandboxing is not implemented for your platform. The " + "feature is currently disabled"); + return 0; +#endif +} + +/** Use <b>fd</b> to log non-survivable sandbox violations. */ +void +sandbox_set_debugging_fd(int fd) +{ +#ifdef USE_LIBSECCOMP + sigsys_set_debugging_fd(fd); +#else + (void)fd; +#endif +} + diff --git a/src/common/sandbox.h b/src/common/sandbox.h new file mode 100644 index 0000000000..bd6f0cfb47 --- /dev/null +++ b/src/common/sandbox.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file sandbox.h + * \brief Header file for sandbox.c. + **/ + +#ifndef SANDBOX_H_ +#define SANDBOX_H_ + +#ifndef SYS_SECCOMP + +/** + * Used by SIGSYS signal handler to check if the signal was issued due to a + * seccomp2 filter violation. + */ +#define SYS_SECCOMP 1 + +#endif + +/** + * Linux definitions + */ +#ifdef __linux__ + +#define __USE_GNU +#include <sys/ucontext.h> + +/** + * Linux 32 bit definitions + */ +#if defined(__i386__) + +#define REG_SYSCALL REG_EAX + +/** + * Linux 64 bit definitions + */ +#elif defined(__x86_64__) + +#define REG_SYSCALL REG_RAX + +#endif + +#endif // __linux__ + +void sandbox_set_debugging_fd(int fd); +int tor_global_sandbox(void); + +#endif /* SANDBOX_H_ */ + diff --git a/src/common/testsupport.h b/src/common/testsupport.h new file mode 100644 index 0000000000..4a4f50b69b --- /dev/null +++ b/src/common/testsupport.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TESTSUPPORT_H +#define TOR_TESTSUPPORT_H + +#ifdef TOR_UNIT_TESTS +#define STATIC +#else +#define STATIC static +#endif + +/** Quick and dirty macros to implement test mocking. + * + * To use them, suppose that you have a function you'd like to mock + * with the signature "void writebuf(size_t n, char *buf)". You can then + * declare the function as: + * + * MOCK_DECL(void, writebuf, (size_t n, char *buf)); + * + * and implement it as: + * + * MOCK_IMPL(void + * writebuf,(size_t n, char *buf) + * { + * ... + * } + * + * For the non-testing build, this will expand simply into: + * + * void writebuf(size_t n, char *buf); + * void + * writebuf(size_t n, char *buf) + * { + * ... + * } + * + * But for the testing case, it will expand into: + * + * void writebuf__real(size_t n, char *buf); + * extern void (*writebuf)(size_t n, char *buf); + * + * void (*writebuf)(size_t n, char *buf) = writebuf__real; + * void + * writebuf__real(size_t n, char *buf) + * { + * ... + * } + * + * This is not a great mocking system! It is deliberately "the simplest + * thing that could work", and pays for its simplicity in its lack of + * features, and in its uglification of the Tor code. Replacing it with + * something clever would be a fine thing. + * + * @{ */ +#ifdef TOR_UNIT_TESTS +#define MOCK_DECL(rv, funcname, arglist) \ + rv funcname ##__real arglist; \ + extern rv(*funcname) arglist +#define MOCK_IMPL(rv, funcname, arglist) \ + rv(*funcname) arglist = funcname ##__real; \ + rv funcname ##__real arglist +#define MOCK(func, replacement) \ + do { \ + (func) = (replacement); \ + } while (0) +#define UNMOCK(func) \ + do { \ + func = func ##__real; \ + } while (0) +#else +#define MOCK_DECL(rv, funcname, arglist) \ + rv funcname arglist +#define MOCK_IMPL(rv, funcname, arglist) \ + rv funcname arglist +#endif +/** @} */ + +#endif + diff --git a/src/common/torlog.h b/src/common/torlog.h index 8675d7b6e7..ecd7e121eb 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -114,12 +114,6 @@ typedef struct log_severity_list_t { log_domain_mask_t masks[LOG_DEBUG-LOG_ERR+1]; } log_severity_list_t; -#ifdef LOG_PRIVATE -/** Given a severity, yields an index into log_severity_list_t.masks to use - * for that severity. */ -#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR) -#endif - /** Callback type used for add_callback_log. */ typedef void (*log_callback)(int severity, uint32_t domain, const char *msg); @@ -142,6 +136,7 @@ int get_min_log_level(void); void switch_logs_debug(void); void logs_free_all(void); void add_temp_log(int min_severity); +int get_err_logging_fd(void); void close_temp_logs(void); void rollback_log_changes(void); void mark_logs_temp(void); diff --git a/src/common/tortls.c b/src/common/tortls.c index b7e5bc1a5f..df706b0012 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -48,9 +48,6 @@ #include "compat_libevent.h" #endif -#define CRYPTO_PRIVATE /* to import prototypes from crypto.h */ -#define TORTLS_PRIVATE - #include "crypto.h" #include "tortls.h" #include "util.h" @@ -806,24 +803,24 @@ tor_cert_new(X509 *x509_cert) tor_cert_t *cert; EVP_PKEY *pkey; RSA *rsa; - int length, length2; - unsigned char *cp; + int length; + unsigned char *buf = NULL; if (!x509_cert) return NULL; - length = i2d_X509(x509_cert, NULL); + length = i2d_X509(x509_cert, &buf); cert = tor_malloc_zero(sizeof(tor_cert_t)); - if (length <= 0) { + if (length <= 0 || buf == NULL) { tor_free(cert); log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate"); X509_free(x509_cert); return NULL; } cert->encoded_len = (size_t) length; - cp = cert->encoded = tor_malloc(length); - length2 = i2d_X509(x509_cert, &cp); - tor_assert(length2 == length); + cert->encoded = tor_malloc(length); + memcpy(cert->encoded, buf, length); + OPENSSL_free(buf); cert->cert = x509_cert; @@ -979,31 +976,6 @@ tor_tls_cert_get_key(tor_cert_t *cert) return result; } -/** Return true iff <b>a</b> and <b>b</b> represent the same public key. */ -static int -pkey_eq(EVP_PKEY *a, EVP_PKEY *b) -{ - /* We'd like to do this, but openssl 0.9.7 doesn't have it: - return EVP_PKEY_cmp(a,b) == 1; - */ - unsigned char *a_enc=NULL, *b_enc=NULL, *a_ptr, *b_ptr; - int a_len1, b_len1, a_len2, b_len2, result; - a_len1 = i2d_PublicKey(a, NULL); - b_len1 = i2d_PublicKey(b, NULL); - if (a_len1 != b_len1) - return 0; - a_ptr = a_enc = tor_malloc(a_len1); - b_ptr = b_enc = tor_malloc(b_len1); - a_len2 = i2d_PublicKey(a, &a_ptr); - b_len2 = i2d_PublicKey(b, &b_ptr); - tor_assert(a_len2 == a_len1); - tor_assert(b_len2 == b_len1); - result = tor_memeq(a_enc, b_enc, a_len1); - tor_free(a_enc); - tor_free(b_enc); - return result; -} - /** Return true iff the other side of <b>tls</b> has authenticated to us, and * the key certified in <b>cert</b> is the same as the key they used to do it. */ @@ -1019,7 +991,7 @@ tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert) link_key = X509_get_pubkey(peercert); cert_key = X509_get_pubkey(cert->cert); - result = link_key && cert_key && pkey_eq(cert_key, link_key); + result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1; X509_free(peercert); if (link_key) diff --git a/src/common/util.c b/src/common/util.c index db160fdf0a..fc247acbeb 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -879,6 +879,39 @@ tor_digest_is_zero(const char *digest) return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); } +/** Return true if <b>string</b> is a valid '<key>=[<value>]' string. + * <value> is optional, to indicate the empty string. Log at logging + * <b>severity</b> if something ugly happens. */ +int +string_is_key_value(int severity, const char *string) +{ + /* position of equal sign in string */ + const char *equal_sign_pos = NULL; + + tor_assert(string); + + if (strlen(string) < 2) { /* "x=" is shortest args string */ + tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", + escaped(string)); + return 0; + } + + equal_sign_pos = strchr(string, '='); + if (!equal_sign_pos) { + tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); + return 0; + } + + /* validate that the '=' is not in the beginning of the string. */ + if (equal_sign_pos == string) { + tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", + escaped(string)); + return 0; + } + + return 1; +} + /** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ int tor_digest256_is_zero(const char *digest) @@ -1190,6 +1223,43 @@ escaped(const char *s) return escaped_val_; } +/** Return a newly allocated string equal to <b>string</b>, except that every + * character in <b>chars_to_escape</b> is preceded by a backslash. */ +char * +tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) +{ + char *new_string = NULL; + char *new_cp = NULL; + size_t length, new_length; + + tor_assert(string); + + length = strlen(string); + + if (!length) /* If we were given the empty string, return the same. */ + return tor_strdup(""); + /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => + (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ + if (length > (SIZE_MAX - 1)/2) /* check for overflow */ + return NULL; + + /* this should be enough even if all characters must be escaped */ + new_length = (length * 2) + 1; + + new_string = new_cp = tor_malloc(new_length); + + while (*string) { + if (strchr(chars_to_escape, *string)) + *new_cp++ = '\\'; + + *new_cp++ = *string++; + } + + *new_cp = '\0'; /* NUL-terminate the new string */ + + return new_string; +} + /* ===== * Time * ===== */ @@ -3309,13 +3379,13 @@ tor_join_win_cmdline(const char *argv[]) } /** - * Helper function to output hex numbers, called by - * format_helper_exit_status(). This writes the hexadecimal digits of x into - * buf, up to max_len digits, and returns the actual number of digits written. - * If there is insufficient space, it will write nothing and return 0. + * Helper function to output hex numbers from within a signal handler. + * + * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer + * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits + * written, not counting the terminal NUL. * - * This function DOES NOT add a terminating NUL character to its output: be - * careful! + * If there is insufficient space, write nothing and return 0. * * This accepts an unsigned int because format_helper_exit_status() needs to * call it with a signed int and an unsigned char, and since the C standard @@ -3330,15 +3400,14 @@ tor_join_win_cmdline(const char *argv[]) * arbitrary C functions. */ int -format_hex_number_for_helper_exit_status(unsigned int x, char *buf, - int max_len) +format_hex_number_sigsafe(unsigned int x, char *buf, int buf_len) { int len; unsigned int tmp; char *cur; /* Sanity check */ - if (!buf || max_len <= 0) + if (!buf || buf_len <= 1) return 0; /* How many chars do we need for x? */ @@ -3354,7 +3423,7 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf, } /* Bail if we would go past the end of the buffer */ - if (len > max_len) + if (len+1 > buf_len) return 0; /* Point to last one */ @@ -3366,10 +3435,13 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf, x >>= 4; } while (x != 0 && cur >= buf); + buf[len] = '\0'; + /* Return len */ return len; } +#ifndef _WIN32 /** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler * safe. @@ -3385,7 +3457,7 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf, * On success return the number of characters added to hex_errno, not counting * the terminating NUL; return -1 on error. */ -int +STATIC int format_helper_exit_status(unsigned char child_state, int saved_errno, char *hex_errno) { @@ -3416,8 +3488,8 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, cur = hex_errno; /* Emit child_state */ - written = format_hex_number_for_helper_exit_status(child_state, - cur, left); + written = format_hex_number_sigsafe(child_state, cur, left); + if (written <= 0) goto err; @@ -3446,8 +3518,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, } /* Emit unsigned_errno */ - written = format_hex_number_for_helper_exit_status(unsigned_errno, - cur, left); + written = format_hex_number_sigsafe(unsigned_errno, cur, left); if (written <= 0) goto err; @@ -3478,6 +3549,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, done: return res; } +#endif /* Maximum number of file descriptors, if we cannot get it via sysconf() */ #define DEFAULT_MAX_FD 256 @@ -3894,9 +3966,9 @@ tor_spawn_background(const char *const filename, const char **argv, * <b>process_handle</b>. * If <b>also_terminate_process</b> is true, also terminate the * process of the process handle. */ -void -tor_process_handle_destroy(process_handle_t *process_handle, - int also_terminate_process) +MOCK_IMPL(void, +tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)) { if (!process_handle) return; @@ -4405,9 +4477,9 @@ stream_status_to_string(enum stream_status stream_status) /** Return a smartlist containing lines outputted from * <b>handle</b>. Return NULL on error, and set * <b>stream_status_out</b> appropriately. */ -smartlist_t * -tor_get_lines_from_handle(HANDLE *handle, - enum stream_status *stream_status_out) +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle, (HANDLE *handle, + enum stream_status *stream_status_out)) { int pos; char stdout_buf[600] = {0}; @@ -4495,8 +4567,8 @@ log_from_handle(HANDLE *pipe, int severity) /** Return a smartlist containing lines outputted from * <b>handle</b>. Return NULL on error, and set * <b>stream_status_out</b> appropriately. */ -smartlist_t * -tor_get_lines_from_handle(FILE *handle, enum stream_status *stream_status_out) +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle,(FILE *handle, enum stream_status *stream_status_out)) { enum stream_status stream_status; char stdout_buf[400]; diff --git a/src/common/util.h b/src/common/util.h index 96a02dd775..dd7a169a1b 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -15,6 +15,7 @@ #include "torint.h" #include "compat.h" #include "di_ops.h" +#include "testsupport.h" #include <stdio.h> #include <stdlib.h> #ifdef _WIN32 @@ -222,23 +223,22 @@ const char *find_whitespace_eos(const char *s, const char *eos); const char *find_str_at_start_of_line(const char *haystack, const char *needle); int string_is_C_identifier(const char *string); +int string_is_key_value(int severity, const char *string); int tor_mem_is_zero(const char *mem, size_t len); int tor_digest_is_zero(const char *digest); int tor_digest256_is_zero(const char *digest); char *esc_for_log(const char *string) ATTR_MALLOC; const char *escaped(const char *string); + +char *tor_escape_str_for_pt_args(const char *string, + const char *chars_to_escape); + struct smartlist_t; -int tor_vsscanf(const char *buf, const char *pattern, va_list ap) -#ifdef __GNUC__ - __attribute__((format(scanf, 2, 0))) -#endif - ; +int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ + CHECK_SCANF(2, 0); int tor_sscanf(const char *buf, const char *pattern, ...) -#ifdef __GNUC__ - __attribute__((format(scanf, 2, 3))) -#endif - ; + CHECK_SCANF(2, 3); void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) CHECK_PRINTF(2, 3); @@ -492,18 +492,21 @@ FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle); #endif #ifdef _WIN32 -struct smartlist_t * -tor_get_lines_from_handle(HANDLE *handle, - enum stream_status *stream_status); +MOCK_DECL(struct smartlist_t *, +tor_get_lines_from_handle,(HANDLE *handle, + enum stream_status *stream_status)); #else -struct smartlist_t * -tor_get_lines_from_handle(FILE *handle, - enum stream_status *stream_status); +MOCK_DECL(struct smartlist_t *, +tor_get_lines_from_handle,(FILE *handle, + enum stream_status *stream_status)); #endif -int tor_terminate_process(process_handle_t *process_handle); -void tor_process_handle_destroy(process_handle_t *process_handle, - int also_terminate_process); +int +tor_terminate_process(process_handle_t *process_handle); + +MOCK_DECL(void, +tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)); /* ===== Insecure rng */ typedef struct tor_weak_rng_t { @@ -519,12 +522,13 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); * <b>n</b> */ #define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) +int format_hex_number_sigsafe(unsigned int x, char *buf, int max_len); + #ifdef UTIL_PRIVATE /* Prototypes for private functions only used by util.c (and unit tests) */ -int format_hex_number_for_helper_exit_status(unsigned int x, char *buf, - int max_len); -int format_helper_exit_status(unsigned char child_state, +#ifndef _WIN32 +STATIC int format_helper_exit_status(unsigned char child_state, int saved_errno, char *hex_errno); /* Space for hex values of child state, a slash, saved_errno (with @@ -533,6 +537,8 @@ int format_helper_exit_status(unsigned char child_state, 1 + sizeof(int) * 2 + 1) #endif +#endif + const char *libor_get_digests(void); #endif diff --git a/src/config/deanonymind.py b/src/config/deanonymind.py index c86dadca99..31d0658eea 100755 --- a/src/config/deanonymind.py +++ b/src/config/deanonymind.py @@ -156,23 +156,34 @@ def apply_manual_changes(assignments, manual_assignments): entry['end_num'] == manual_entry['end_num']: if len(manual_entry['country_code']) != 2: print '-%s' % (line, ) # only remove, don't replace - else: + del manual_dict[start_num] + elif entry['country_code'] != \ + manual_entry['country_code']: new_line = format_line_with_other_country(entry, manual_entry) print '-%s\n+%s' % (line, new_line, ) result.append(new_line) - del manual_dict[start_num] + del manual_dict[start_num] + else: + print ('Warning: not applying ineffective manual ' + 'change:\n %s\n %s' % (line, manual_line, )) + result.append(line) else: - print ('Warning: only partial match between ' - 'original/automatically replaced assignment and ' - 'manual assignment:\n %s\n %s\nNot applying ' - 'manual change.' % (line, manual_line, )) + print ('Warning: not applying manual change that is only ' + 'a partial match:\n %s\n %s' % + (line, manual_line, )) result.append(line) + elif 'country_code' in entry and \ + entry['country_code'] == 'A1': + print ('Warning: no manual replacement for A1 entry:\n %s' + % (line, )) + result.append(line) else: result.append(line) if len(manual_dict) > 0: - print ('Warning: could not apply all manual assignments: %s' % - ('\n '.join(manual_dict.values())), ) + print 'Warning: could not apply all manual assignments:' + for line in manual_dict.values(): + print ' %s' % (line, ) return result def write_file(path, assignments, long_format=True): diff --git a/src/config/geoip-manual b/src/config/geoip-manual index 99c897ff42..ff9be5691c 100644 --- a/src/config/geoip-manual +++ b/src/config/geoip-manual @@ -3,11 +3,10 @@ # directory to process this file when producing a new geoip file. See # README.geoip in the same directory for details. -# Remove MaxMind entry 0.116.0.0-0.119.255.255 which MaxMind says is AT, -# but which is part of reserved range 0.0.0.0/8. -KL 2012-06-13 -# Disabled, because MaxMind apparently removed this range from their -# database. -KL 2013-02-08 -#"0.116.0.0","0.119.255.255","7602176","7864319","","" +# GB, because previous MaxMind entry 31.6.16.0-31.6.25.255 is GB, and RIR +# delegation files say entire range 31.6.0.0-31.6.63.255 is GB. +# -KL 2013-03-07 +"31.6.26.0","31.6.27.255","520493568","520494079","GB","United Kingdom" # NL, because previous MaxMind entry 31.171.128.0-31.171.133.255 is NL, # and RIR delegation files say 31.171.128.0-31.171.135.255 is NL. @@ -20,6 +19,17 @@ # -KL 2012-11-27 "37.139.64.0","37.139.64.0","629882880","629882880","EU","Europe" +# US, because next MaxMind entry 38.99.145.0-38.99.149.255 is US and +# RIR delegation files say entire range 38.0.0.0-38.255.255.255 is US. +# -KL 2013-05-13 +"38.99.144.0","38.99.144.255","644059136","644059391","US","United States" + +# GB, because RIR delegation files say exactly this range +# 46.16.32.0-46.16.39.255 is GB, even though neither previous nor next +# MaxMind range is GB. Both previous and next MaxMind ranges match RIR +# delegation files, too. -KL 2013-03-07 +"46.16.32.0","46.16.39.255","772808704","772810751","GB","United Kingdom" + # CH, because previous MaxMind entry 46.19.141.0-46.19.142.255 is CH, and # RIR delegation files say 46.19.136.0-46.19.143.255 is CH. # -KL 2012-11-27 @@ -30,17 +40,15 @@ # -KL 2012-11-27 "46.166.128.0","46.166.128.255","782663680","782663935","GB","United Kingdom" -# US, though could as well be CA. Previous MaxMind entry -# 64.237.32.52-64.237.34.127 is US, next MaxMind entry -# 64.237.34.144-64.237.34.151 is CA, and RIR delegation files say the -# entire block 64.237.32.0-64.237.63.255 is US. -KL 2012-11-27 -"64.237.34.128","64.237.34.143","1089282688","1089282703","US","United States" +# GB, because previous MaxMind entry 46.166.129.0-46.166.134.255 is GB, +# and RIR delegation files say entire range 46.166.128.0-46.166.191.255 is +# GB. -KL 2013-03-07 +"46.166.135.0","46.166.139.255","782665472","782666751","GB","United Kingdom" -# US, though could as well be UY. Previous MaxMind entry -# 67.15.170.0-67.15.182.255 is US, next MaxMind entry -# 67.15.183.128-67.15.183.159 is UY, and RIR delegation files say the -# entire block 67.15.0.0-67.15.255.255 is US. -KL 2012-11-27 -"67.15.183.0","67.15.183.127","1125103360","1125103487","US","United States" +# Removing, because RIR delegation files don't even have an entry for this +# single-address range, and there's no previous or next range in MaxMind. +# -KL 2013-03-07 +"64.185.237.110","64.185.237.110","1085926766","1085926766","","" # US, because next MaxMind entry 67.43.145.0-67.43.155.255 is US, and RIR # delegation files say 67.43.144.0-67.43.159.255 is US. @@ -61,6 +69,24 @@ # US. -KL 2012-11-27 "70.232.245.60","70.232.245.255","1189672252","1189672447","US","United States" +# SE, because previous MaxMind entry 80.67.11.200-80.67.13.255 is SE, and +# RIR delegation files say entire range 80.67.0.0-80.67.15.255 is SE. +# -KL 2013-03-07 +"80.67.14.0","80.67.15.255","1346571776","1346572287","SE","Sweden" + +# NL, because previous MaxMind entry 81.171.56.0-81.171.80.255 is NL, and +# RIR delegation files say entire range 81.171.64.0-81.171.127.255 is NL. +# -KL 2013-03-07 +"81.171.81.0","81.171.81.127","1370181888","1370182015","NL","Netherlands" + +# GB, because RIPE NCC says 85.237.192.0-85.237.223.255 is GB. +"85.237.222.0","85.237.222.255","1441652224","1441652479","GB","United Kingdom" + +# BE, because next MaxMind entry 86.39.147.0-86.39.148.31 is BE, and RIR +# delegation files say entire range 86.39.128.0-86.39.255.255 is BE. +# -KL 2013-04-08 +"86.39.146.0","86.39.146.255","1445433856","1445434111","BE","Belgium" + # GB, despite neither previous (GE) nor next (LV) MaxMind entry being GB, # but because RIR delegation files agree with both previous and next # MaxMind entry and say GB for 91.228.0.0-91.228.3.255. -KL 2012-11-27 @@ -77,9 +103,14 @@ # -KL 2012-11-27 "91.238.214.0","91.238.215.255","1542379008","1542379519","GB","United Kingdom" -# US, because next MaxMind entry 173.0.16.0-173.0.65.255 is US, and RIR -# delegation files say 173.0.0.0-173.0.15.255 is US. -KL 2012-11-27 -"173.0.0.0","173.0.15.255","2902458368","2902462463","US","United States" +# NL, because next MaxMind entry 176.56.173.0-176.56.173.63 is NL, and RIR +# delegation files say 176.56.160.0-176.56.191.255 is NL. -KL 2013-05-13 +"176.56.172.0","176.56.172.255","2956504064","2956504319","NL","Netherlands" + +# NL, despite neither previous (RU) nor next (GB) MaxMind entry being NL, +# but because RIR delegation files say entire range +# 176.56.160.0-176.56.191.255 is NL. -KL 2013-05-13 +"176.56.174.0","176.56.174.255","2956504576","2956504831","NL","Netherlands" # US, because next MaxMind entry 176.67.84.0-176.67.84.79 is US, and RIR # delegation files say 176.67.80.0-176.67.87.255 is US. -KL 2012-11-27 @@ -90,6 +121,12 @@ # -KL 2012-11-27 "176.67.86.0","176.67.87.255","2957202944","2957203455","US","United States" +# GB, because RIR delegation files say exactly this range +# 185.25.84.0-185.25.87.255 is GB, even though neither previous nor next +# MaxMind range is GB. Both previous and next MaxMind ranges match RIR +# delegation files, too. -KL 2013-05-13 +"185.25.84.0","185.25.87.255","3105444864","3105445887","GB","United Kingdom" + # EU, despite neither previous (RU) nor next (UA) MaxMind entry being EU, # but because RIR delegation files agree with both previous and next # MaxMind entry and say EU for 193.200.150.0-193.200.150.255. @@ -101,11 +138,29 @@ # -KL 2012-11-27 "199.96.87.128","199.96.87.255","3344979840","3344979967","US","United States" +# US, because next MaxMind entry 199.101.193.0-199.101.195.255 is US, and, +# together with next entries, matches RIR delegation file entry +# 199.101.192.0-199.101.199.255 which is US. -KL 2013-05-13 +"199.101.192.0","199.101.192.255","3345334272","3345334527","US","United States" + +# US, because ARIN says 199.255.208.0-199.255.215.255 is US. +"199.255.213.0","199.255.215.255","3355432192","3355432959","US","United States" + +# US, because next MaxMind entry 204.12.162.0-204.12.197.119 is US, and +# RIR delegation files say 204.12.160.0-204.12.191.255 is US. +# -KL 2013-05-13 +"204.12.160.0","204.12.161.255","3423379456","3423379967","US","United States" + # US, because previous MaxMind entry 209.58.176.144-209.59.31.255 is US, # and RIR delegation files say 209.59.32.0-209.59.63.255 is US. # -KL 2012-11-27 "209.59.32.0","209.59.63.255","3510312960","3510321151","US","United States" +# EU, despite neither previous (RU) nor next (SE) MaxMind entry being EU, +# but because RIR delegation files agree with previous MaxMind entry and +# say EU for 217.15.160.0-217.15.175.255. -KL 2013-05-13 +"217.15.160.0","217.15.164.255","3641679872","3641681151","EU","Europe" + # FR, because previous MaxMind entry 217.15.166.0-217.15.166.255 is FR, # and RIR delegation files contain a block 217.15.160.0-217.15.175.255 # which, however, is EU, not FR. But merging with next MaxMind entry diff --git a/src/or/addressmap.c b/src/or/addressmap.c index 79e4b7c5e2..9bc79bd84b 100644 --- a/src/or/addressmap.c +++ b/src/or/addressmap.c @@ -798,7 +798,7 @@ address_is_in_virtual_range(const char *address) /** Return a random address conforming to the virtual address configuration * in <b>conf</b>. */ -/* private */ void +STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out) { uint8_t tmp[4]; diff --git a/src/or/addressmap.h b/src/or/addressmap.h index 40210ee990..417832b31f 100644 --- a/src/or/addressmap.h +++ b/src/or/addressmap.h @@ -7,6 +7,8 @@ #ifndef TOR_ADDRESSMAP_H #define TOR_ADDRESSMAP_H +#include "testsupport.h" + void addressmap_init(void); void addressmap_clear_excluded_trackexithosts(const or_options_t *options); void addressmap_clear_invalid_automaps(const or_options_t *options); @@ -52,8 +54,8 @@ typedef struct virtual_addr_conf_t { maskbits_t bits; } virtual_addr_conf_t; -void get_random_virtual_addr(const virtual_addr_conf_t *conf, - tor_addr_t *addr_out); +STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf, + tor_addr_t *addr_out); #endif #endif diff --git a/src/or/buffers.c b/src/or/buffers.c index c4c847ec87..cc5890416f 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1294,7 +1294,7 @@ buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n) /** Return the first position in <b>buf</b> at which the <b>n</b>-character * string <b>s</b> occurs, or -1 if it does not occur. */ -/*private*/ int +STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n) { buf_pos_t pos; diff --git a/src/or/buffers.h b/src/or/buffers.h index c947f0ba98..910494a874 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -12,6 +12,8 @@ #ifndef TOR_BUFFERS_H #define TOR_BUFFERS_H +#include "testsupport.h" + buf_t *buf_new(void); buf_t *buf_new_with_capacity(size_t size); void buf_free(buf_t *buf); @@ -89,7 +91,7 @@ int generic_buffer_set_to_copy(generic_buffer_t **output, void assert_buf_ok(buf_t *buf); #ifdef BUFFERS_PRIVATE -int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); +STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); #endif #endif diff --git a/src/or/channel.c b/src/or/channel.c index 602797d0dc..05f269b8fa 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -122,6 +122,8 @@ static cell_queue_entry_t * cell_queue_entry_new_fixed(cell_t *cell); static cell_queue_entry_t * cell_queue_entry_new_var(var_cell_t *var_cell); +static int is_destroy_cell(channel_t *chan, + const cell_queue_entry_t *q, circid_t *circid_out); /* Functions to maintain the digest map */ static void channel_add_to_digest_map(channel_t *chan); @@ -801,6 +803,7 @@ channel_free(channel_t *chan) /* Get rid of cmux */ if (chan->cmux) { circuitmux_detach_all_circuits(chan->cmux); + circuitmux_mark_destroyed_circids_usable(chan->cmux, chan); circuitmux_free(chan->cmux); chan->cmux = NULL; } @@ -1685,6 +1688,13 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q) chan->timestamp_last_added_nonpadding = approx_time(); } + { + circid_t circ_id; + if (is_destroy_cell(chan, q, &circ_id)) { + channel_note_destroy_not_pending(chan, circ_id); + } + } + /* Can we send it right out? If so, try */ if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) && chan->state == CHANNEL_STATE_OPEN) { @@ -2607,6 +2617,54 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) } } +/** If <b>packed_cell</b> on <b>chan</b> is a destroy cell, then set + * *<b>circid_out</b> to its circuit ID, and return true. Otherwise, return + * false. */ +/* XXXX Move this function. */ +int +packed_cell_is_destroy(channel_t *chan, + const packed_cell_t *packed_cell, + circid_t *circid_out) +{ + if (chan->wide_circ_ids) { + if (packed_cell->body[4] == CELL_DESTROY) { + *circid_out = ntohl(get_uint32(packed_cell->body)); + return 1; + } + } else { + if (packed_cell->body[2] == CELL_DESTROY) { + *circid_out = ntohs(get_uint16(packed_cell->body)); + return 1; + } + } + return 0; +} + +/** DOCDOC */ +static int +is_destroy_cell(channel_t *chan, + const cell_queue_entry_t *q, circid_t *circid_out) +{ + *circid_out = 0; + switch (q->type) { + case CELL_QUEUE_FIXED: + if (q->u.fixed.cell->command == CELL_DESTROY) { + *circid_out = q->u.fixed.cell->circ_id; + return 1; + } + break; + case CELL_QUEUE_VAR: + if (q->u.var.var_cell->command == CELL_DESTROY) { + *circid_out = q->u.var.var_cell->circ_id; + return 1; + } + break; + case CELL_QUEUE_PACKED: + return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out); + } + return 0; +} + /** * Send destroy cell on a channel * @@ -2618,25 +2676,20 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell) int channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) { - cell_t cell; - tor_assert(chan); /* Check to make sure we can send on this channel first */ if (!(chan->state == CHANNEL_STATE_CLOSING || chan->state == CHANNEL_STATE_CLOSED || - chan->state == CHANNEL_STATE_ERROR)) { - memset(&cell, 0, sizeof(cell_t)); - cell.circ_id = circ_id; - cell.command = CELL_DESTROY; - cell.payload[0] = (uint8_t) reason; + chan->state == CHANNEL_STATE_ERROR) && + chan->cmux) { + channel_note_destroy_pending(chan, circ_id); + circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason); log_debug(LD_OR, "Sending destroy (circID %u) on channel %p " "(global ID " U64_FORMAT ")", (unsigned)circ_id, chan, U64_PRINTF_ARG(chan->global_identifier)); - - channel_write_cell(chan, &cell); } else { log_warn(LD_BUG, "Someone called channel_send_destroy() for circID %u " diff --git a/src/or/channel.h b/src/or/channel.h index 0933ec8d39..83d7e900ff 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -477,5 +477,9 @@ uint64_t channel_count_xmitted(channel_t *chan); uint64_t channel_listener_count_accepted(channel_listener_t *chan_l); +int packed_cell_is_destroy(channel_t *chan, + const packed_cell_t *packed_cell, + circid_t *circid_out); + #endif diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index daeaa37b1e..85bacce485 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -8,7 +8,7 @@ * \file circuitlist.c * \brief Manage the global circuit list. **/ - +#define CIRCUITLIST_PRIVATE #include "or.h" #include "channel.h" #include "circuitbuild.h" @@ -41,7 +41,6 @@ circuit_t *global_circuitlist=NULL; /** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */ static smartlist_t *circuits_pending_chans = NULL; -static void circuit_free(circuit_t *circ); static void circuit_free_cpath(crypt_path_t *cpath); static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); @@ -207,18 +206,123 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction, } } +/** Mark that circuit id <b>id</b> shouldn't be used on channel <b>chan</b>, + * even if there is no circuit on the channel. We use this to keep the + * circuit id from getting re-used while we have queued but not yet sent + * a destroy cell. */ +void +channel_mark_circid_unusable(channel_t *chan, circid_t id) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *ent; + + /* See if there's an entry there. That wouldn't be good. */ + memset(&search, 0, sizeof(search)); + search.chan = chan; + search.circ_id = id; + ent = HT_FIND(chan_circid_map, &chan_circid_map, &search); + + if (ent && ent->circuit) { + /* we have a problem. */ + log_warn(LD_BUG, "Tried to mark %u unusable on %p, but there was already " + "a circuit there.", (unsigned)id, chan); + } else if (ent) { + /* It's already marked. */ + } else { + ent = tor_malloc_zero(sizeof(chan_circid_circuit_map_t)); + ent->chan = chan; + ent->circ_id = id; + /* leave circuit at NULL */ + HT_INSERT(chan_circid_map, &chan_circid_map, ent); + } +} + +/** Mark that a circuit id <b>id</b> can be used again on <b>chan</b>. + * We use this to re-enable the circuit ID after we've sent a destroy cell. + */ +void +channel_mark_circid_usable(channel_t *chan, circid_t id) +{ + chan_circid_circuit_map_t search; + chan_circid_circuit_map_t *ent; + + /* See if there's an entry there. That wouldn't be good. */ + memset(&search, 0, sizeof(search)); + search.chan = chan; + search.circ_id = id; + ent = HT_REMOVE(chan_circid_map, &chan_circid_map, &search); + if (ent && ent->circuit) { + log_warn(LD_BUG, "Tried to mark %u usable on %p, but there was already " + "a circuit there.", (unsigned)id, chan); + return; + } + if (_last_circid_chan_ent == ent) + _last_circid_chan_ent = NULL; + tor_free(ent); +} + +/** Called to indicate that a DESTROY is pending on <b>chan</b> with + * circuit ID <b>id</b>, but hasn't been sent yet. */ +void +channel_note_destroy_pending(channel_t *chan, circid_t id) +{ + circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan); + if (circ) { + if (circ->n_chan == chan && circ->n_circ_id == id) { + circ->n_delete_pending = 1; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + if (orcirc->p_chan == chan && orcirc->p_circ_id == id) { + circ->p_delete_pending = 1; + } + } + return; + } + channel_mark_circid_unusable(chan, id); +} + +/** Called to indicate that a DESTROY is no longer pending on <b>chan</b> with + * circuit ID <b>id</b> -- typically, because it has been sent. */ +void +channel_note_destroy_not_pending(channel_t *chan, circid_t id) +{ + circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan); + if (circ) { + if (circ->n_chan == chan && circ->n_circ_id == id) { + circ->n_delete_pending = 0; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + if (orcirc->p_chan == chan && orcirc->p_circ_id == id) { + circ->p_delete_pending = 0; + } + } + /* XXXX this shouldn't happen; log a bug here. */ + return; + } + channel_mark_circid_usable(chan, id); +} + /** Set the p_conn field of a circuit <b>circ</b>, along * with the corresponding circuit ID, and add the circuit as appropriate * to the (chan,id)-\>circuit map. */ void -circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, +circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id, channel_t *chan) { - circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN, - id, chan); + circuit_t *circ = TO_CIRCUIT(or_circ); + channel_t *old_chan = or_circ->p_chan; + circid_t old_id = or_circ->p_circ_id; + + circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan); if (chan) - tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan)); + tor_assert(bool_eq(or_circ->p_chan_cells.n, + or_circ->next_active_on_p_chan)); + + if (circ->p_delete_pending && old_chan) { + channel_mark_circid_unusable(old_chan, old_id); + circ->p_delete_pending = 0; + } } /** Set the n_conn field of a circuit <b>circ</b>, along @@ -228,10 +332,18 @@ void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, channel_t *chan) { + channel_t *old_chan = circ->n_chan; + circid_t old_id = circ->n_circ_id; + circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan); if (chan) tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan)); + + if (circ->n_delete_pending && old_chan) { + channel_mark_circid_unusable(old_chan, old_id); + circ->n_delete_pending = 0; + } } /** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing @@ -570,6 +682,7 @@ init_circuit_base(circuit_t *circ) circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; + cell_queue_init(&circ->n_chan_cells); circuit_add(circ); } @@ -615,6 +728,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan) circuit_set_p_circid_chan(circ, p_circ_id, p_chan); circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT; + cell_queue_init(&circ->p_chan_cells); init_circuit_base(TO_CIRCUIT(circ)); @@ -623,7 +737,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan) /** Deallocate space associated with circ. */ -static void +STATIC void circuit_free(circuit_t *circ) { void *mem; @@ -928,9 +1042,13 @@ circuit_get_by_global_id(uint32_t id) * - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and * - circ is attached to <b>chan</b>, either as p_chan or n_chan. * Return NULL if no such circuit exists. + * + * If <b>found_entry_out</b> is provided, set it to true if we have a + * placeholder entry for circid/chan, and leave it unset otherwise. */ static INLINE circuit_t * -circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan) +circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan, + int *found_entry_out) { chan_circid_circuit_map_t search; chan_circid_circuit_map_t *found; @@ -951,15 +1069,21 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan) " circ_id %u, channel ID " U64_FORMAT " (%p)", found->circuit, (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), chan); + if (found_entry_out) + *found_entry_out = 1; return found->circuit; } log_debug(LD_CIRC, - "circuit_get_by_circid_channel_impl() found nothing for" + "circuit_get_by_circid_channel_impl() found %s for" " circ_id %u, channel ID " U64_FORMAT " (%p)", + found ? "placeholder" : "nothing", (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), chan); + if (found_entry_out) + *found_entry_out = found ? 1 : 0; + return NULL; /* The rest of this checks for bugs. Disabled by default. */ /* We comment it out because coverity complains otherwise. @@ -993,7 +1117,7 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan) circuit_t * circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan) { - circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan); + circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan, NULL); if (!circ || circ->marked_for_close) return NULL; else @@ -1009,7 +1133,7 @@ circuit_t * circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, channel_t *chan) { - return circuit_get_by_circid_channel_impl(circ_id, chan); + return circuit_get_by_circid_channel_impl(circ_id, chan, NULL); } /** Return true iff the circuit ID <b>circ_id</b> is currently used by a @@ -1017,7 +1141,9 @@ circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan) { - return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL; + int found = 0; + return circuit_get_by_circid_channel_impl(circ_id, chan, &found) != NULL + || found; } /** Return the circuit that a given edge connection is using. */ @@ -1514,7 +1640,7 @@ marked_circuit_free_cells(circuit_t *circ) } /** Return the number of cells used by the circuit <b>c</b>'s cell queues. */ -static size_t +STATIC size_t n_cells_in_circ_queues(const circuit_t *c) { size_t n = c->n_chan_cells.n; @@ -1689,15 +1815,16 @@ assert_circuit_ok(const circuit_t *c) /* We use the _impl variant here to make sure we don't fail on marked * circuits, which would not be returned by the regular function. */ circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id, - c->n_chan); + c->n_chan, NULL); tor_assert(c == c2); } } if (or_circ && or_circ->p_chan) { if (or_circ->p_circ_id) { /* ibid */ - circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id, - or_circ->p_chan); + circuit_t *c2 = + circuit_get_by_circid_channel_impl(or_circ->p_circ_id, + or_circ->p_chan, NULL); tor_assert(c == c2); } } diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 874f68cd22..4e56f5264f 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -12,6 +12,8 @@ #ifndef TOR_CIRCUITLIST_H #define TOR_CIRCUITLIST_H +#include "testsupport.h" + circuit_t * circuit_get_global_list_(void); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); @@ -23,6 +25,8 @@ void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, channel_t *chan); void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, channel_t *chan); +void channel_mark_circid_unusable(channel_t *chan, circid_t id); +void channel_mark_circid_usable(channel_t *chan, circid_t id); void circuit_set_state(circuit_t *circ, uint8_t state); void circuit_close_all_marked(void); int32_t circuit_initial_package_window(void); @@ -63,5 +67,13 @@ void assert_circuit_ok(const circuit_t *c); void circuit_free_all(void); void circuits_handle_oom(size_t current_allocation); +void channel_note_destroy_pending(channel_t *chan, circid_t id); +void channel_note_destroy_not_pending(channel_t *chan, circid_t id); + +#ifdef CIRCUITLIST_PRIVATE +STATIC void circuit_free(circuit_t *circ); +STATIC size_t n_cells_in_circ_queues(const circuit_t *c); +#endif + #endif diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c index 545cfd0650..47b423066a 100644 --- a/src/or/circuitmux.c +++ b/src/or/circuitmux.c @@ -10,6 +10,7 @@ #include "channel.h" #include "circuitlist.h" #include "circuitmux.h" +#include "relay.h" /* * Private typedefs for circuitmux.c @@ -115,6 +116,22 @@ struct circuitmux_s { */ struct circuit_t *active_circuits_head, *active_circuits_tail; + /** List of queued destroy cells */ + cell_queue_t destroy_cell_queue; + /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit + * returned the destroy queue. Used to force alternation between + * destroy/non-destroy cells. + * + * XXXX There is no reason to think that alternating is a particularly good + * approach -- it's just designed to prevent destroys from starving other + * cells completely. + */ + unsigned int last_cell_was_destroy : 1; + /** Destroy counter: increment this when a destroy gets queued, decrement + * when we unqueue it, so we can test to make sure they don't starve. + */ + int64_t destroy_ctr; + /* * Circuitmux policy; if this is non-NULL, it can override the built- * in round-robin active circuits behavior. This is how EWMA works in @@ -193,6 +210,11 @@ static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux); static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux); static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux); +/* Static global variables */ + +/** Count the destroy balance to debug destroy queue logic */ +static int64_t global_destroy_ctr = 0; + /* Function definitions */ /** @@ -361,6 +383,7 @@ circuitmux_alloc(void) rv = tor_malloc_zero(sizeof(*rv)); rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map))); HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map); + cell_queue_init(&rv->destroy_cell_queue); return rv; } @@ -476,6 +499,31 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux) cmux->n_cells = 0; } +/** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because + * of pending destroy cells in <b>cmux</b>. + * + * This function must be called AFTER circuits are unlinked from the (channel, + * circuid-id) map with circuit_unlink_all_from_channel(), but before calling + * circuitmux_free(). + */ +void +circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan) +{ + packed_cell_t *cell; + int n_bad = 0; + TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) { + circid_t circid = 0; + if (packed_cell_is_destroy(chan, cell, &circid)) { + channel_mark_circid_usable(chan, circid); + } else { + ++n_bad; + } + } + if (n_bad) + log_warn(LD_BUG, "%d cell(s) on destroy queue did not look like a " + "DESTROY cell.", n_bad); +} + /** * Free a circuitmux_t; the circuits must be detached first with * circuitmux_detach_all_circuits(). @@ -508,6 +556,30 @@ circuitmux_free(circuitmux_t *cmux) tor_free(cmux->chanid_circid_map); } + /* + * We're throwing away some destroys; log the counter and + * adjust the global counter by the queue size. + */ + if (cmux->destroy_cell_queue.n > 0) { + cmux->destroy_ctr -= cmux->destroy_cell_queue.n; + global_destroy_ctr -= cmux->destroy_cell_queue.n; + log_debug(LD_CIRC, + "Freeing cmux at %p with %u queued destroys; the last cmux " + "destroy balance was "I64_FORMAT", global is "I64_FORMAT, + cmux, cmux->destroy_cell_queue.n, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + } else { + log_debug(LD_CIRC, + "Freeing cmux at %p with no queued destroys, the cmux destroy " + "balance was "I64_FORMAT", global is "I64_FORMAT, + cmux, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + } + + cell_queue_clear(&cmux->destroy_cell_queue); + tor_free(cmux); } @@ -816,7 +888,7 @@ circuitmux_num_cells(circuitmux_t *cmux) { tor_assert(cmux); - return cmux->n_cells; + return cmux->n_cells + cmux->destroy_cell_queue.n; } /** @@ -851,9 +923,9 @@ circuitmux_num_circuits(circuitmux_t *cmux) * Attach a circuit to a circuitmux, for the specified direction. */ -void -circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, - cell_direction_t direction) +MOCK_IMPL(void, +circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t direction)) { channel_t *chan = NULL; uint64_t channel_id; @@ -1000,8 +1072,8 @@ circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, * no-op if not attached. */ -void -circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ) +MOCK_IMPL(void, +circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ)) { chanid_circid_muxinfo_t search, *hashent = NULL; /* @@ -1368,16 +1440,36 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, /** * Pick a circuit to send from, using the active circuits list or a * circuitmux policy if one is available. This is called from channel.c. + * + * If we would rather send a destroy cell, return NULL and set + * *<b>destroy_queue_out</b> to the destroy queue. + * + * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and + * return NULL. */ circuit_t * -circuitmux_get_first_active_circuit(circuitmux_t *cmux) +circuitmux_get_first_active_circuit(circuitmux_t *cmux, + cell_queue_t **destroy_queue_out) { circuit_t *circ = NULL; tor_assert(cmux); + tor_assert(destroy_queue_out); + + *destroy_queue_out = NULL; + + if (cmux->destroy_cell_queue.n && + (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) { + /* We have destroy cells to send, and either we just sent a relay cell, + * or we have no relay cells to send. */ + + /* XXXX We should let the cmux policy have some say in this eventually. */ + /* XXXX Alternating is not a terribly brilliant approach here. */ + *destroy_queue_out = &cmux->destroy_cell_queue; - if (cmux->n_active_circuits > 0) { + cmux->last_cell_was_destroy = 1; + } else if (cmux->n_active_circuits > 0) { /* We also must have a cell available for this to be the case */ tor_assert(cmux->n_cells > 0); /* Do we have a policy-provided circuit selector? */ @@ -1389,7 +1481,11 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux) tor_assert(cmux->active_circuits_head); circ = cmux->active_circuits_head; } - } else tor_assert(cmux->n_cells == 0); + cmux->last_cell_was_destroy = 0; + } else { + tor_assert(cmux->n_cells == 0); + tor_assert(cmux->destroy_cell_queue.n == 0); + } return circ; } @@ -1463,6 +1559,26 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, circuitmux_assert_okay_paranoid(cmux); } +/** + * Notify the circuitmux that a destroy was sent, so we can update + * the counter. + */ + +void +circuitmux_notify_xmit_destroy(circuitmux_t *cmux) +{ + tor_assert(cmux); + + --(cmux->destroy_ctr); + --(global_destroy_ctr); + log_debug(LD_CIRC, + "Cmux at %p sent a destroy, cmux counter is now "I64_FORMAT", " + "global counter is now "I64_FORMAT, + cmux, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); +} + /* * Circuitmux consistency checking assertions */ @@ -1743,3 +1859,40 @@ circuitmux_assert_okay_pass_three(circuitmux_t *cmux) } } +/*DOCDOC */ +void +circuitmux_append_destroy_cell(channel_t *chan, + circuitmux_t *cmux, + circid_t circ_id, + uint8_t reason) +{ + cell_t cell; + memset(&cell, 0, sizeof(cell_t)); + cell.circ_id = circ_id; + cell.command = CELL_DESTROY; + cell.payload[0] = (uint8_t) reason; + + cell_queue_append_packed_copy(&cmux->destroy_cell_queue, &cell, + chan->wide_circ_ids, 0); + + /* Destroy entering the queue, update counters */ + ++(cmux->destroy_ctr); + ++global_destroy_ctr; + log_debug(LD_CIRC, + "Cmux at %p queued a destroy for circ %u, cmux counter is now " + I64_FORMAT", global counter is now "I64_FORMAT, + cmux, circ_id, + I64_PRINTF_ARG(cmux->destroy_ctr), + I64_PRINTF_ARG(global_destroy_ctr)); + + /* XXXX Duplicate code from append_cell_to_circuit_queue */ + if (!channel_has_queued_writes(chan)) { + /* There is no data at all waiting to be sent on the outbuf. Add a + * cell, so that we can notice when it gets flushed, flushed_some can + * get called, and we can start putting more data onto the buffer then. + */ + log_debug(LD_GENERAL, "Primed a buffer."); + channel_flush_from_first_active_circuit(chan, 1); + } +} + diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h index 25644ffab7..ee2f5d1535 100644 --- a/src/or/circuitmux.h +++ b/src/or/circuitmux.h @@ -10,6 +10,7 @@ #define TOR_CIRCUITMUX_H #include "or.h" +#include "testsupport.h" typedef struct circuitmux_policy_s circuitmux_policy_t; typedef struct circuitmux_policy_data_s circuitmux_policy_data_t; @@ -120,17 +121,27 @@ unsigned int circuitmux_num_circuits(circuitmux_t *cmux); unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux); /* Channel interface */ -circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux); +circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux, + cell_queue_t **destroy_queue_out); void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells); +void circuitmux_notify_xmit_destroy(circuitmux_t *cmux); /* Circuit interface */ -void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ, - cell_direction_t direction); -void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ); +MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux, + circuit_t *circ, + cell_direction_t direction)); +MOCK_DECL(void, circuitmux_detach_circuit, + (circuitmux_t *cmux, circuit_t *circ)); void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ); void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ, unsigned int n_cells); +void circuitmux_append_destroy_cell(channel_t *chan, + circuitmux_t *cmux, circid_t circ_id, + uint8_t reason); +void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, + channel_t *chan); + #endif /* TOR_CIRCUITMUX_H */ diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 1d7812bf2b..95129f9a43 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -29,9 +29,13 @@ /* XXXX024 Make this static; add accessor functions. */ circuit_build_times_t circ_times; +#ifdef TOR_UNIT_TESTS /** If set, we're running the unit tests: we should avoid clobbering * our state file or accessing get_options() or get_or_state() */ static int unit_tests = 0; +#else +#define unit_tests 0 +#endif /** * This function decides if CBT learning should be disabled. It returns @@ -438,7 +442,7 @@ circuit_build_times_get_initial_timeout(void) * Leave estimated parameters, timeout and network liveness intact * for future use. */ -void +STATIC void circuit_build_times_reset(circuit_build_times_t *cbt) { memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times)); @@ -949,7 +953,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt, * an acceptable approximation because we are only concerned with the * accuracy of the CDF of the tail. */ -int +STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt) { build_time_t *x=cbt->circuit_build_times; @@ -1033,7 +1037,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt) * * Return value is in milliseconds. */ -double +STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, double quantile) { @@ -1050,6 +1054,7 @@ circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, return ret; } +#ifdef TOR_UNIT_TESTS /** Pareto CDF */ double circuit_build_times_cdf(circuit_build_times_t *cbt, double x) @@ -1060,7 +1065,9 @@ circuit_build_times_cdf(circuit_build_times_t *cbt, double x) tor_assert(0 <= ret && ret <= 1.0); return ret; } +#endif +#ifdef TOR_UNIT_TESTS /** * Generate a synthetic time using our distribution parameters. * @@ -1093,7 +1100,9 @@ circuit_build_times_generate_sample(circuit_build_times_t *cbt, tor_assert(ret > 0); return ret; } +#endif +#ifdef TOR_UNIT_TESTS /** * Estimate an initial alpha parameter by solving the quantile * function with a quantile point and a specific timeout value. @@ -1114,6 +1123,7 @@ circuit_build_times_initial_alpha(circuit_build_times_t *cbt, (tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms)); tor_assert(cbt->alpha > 0); } +#endif /** * Returns true if we need circuits to be built @@ -1282,7 +1292,7 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt) * to restart the process of building test circuits and estimating a * new timeout. */ -int +STATIC int circuit_build_times_network_check_changed(circuit_build_times_t *cbt) { int total_build_times = cbt->total_build_times; @@ -1546,6 +1556,8 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) cbt->total_build_times); } } + +#ifdef TOR_UNIT_TESTS /** Make a note that we're running unit tests (rather than running Tor * itself), so we avoid clobbering our state file. */ void @@ -1553,4 +1565,5 @@ circuitbuild_running_unit_tests(void) { unit_tests = 1; } +#endif diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h index 87dce99f4f..53ba2b2d2e 100644 --- a/src/or/circuitstats.h +++ b/src/or/circuitstats.h @@ -38,19 +38,23 @@ double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); double circuit_build_times_close_rate(const circuit_build_times_t *cbt); #ifdef CIRCUITSTATS_PRIVATE -double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, +STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, double quantile); +STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt); +STATIC void circuit_build_times_reset(circuit_build_times_t *cbt); + +/* Network liveness functions */ +STATIC int circuit_build_times_network_check_changed( + circuit_build_times_t *cbt); +#endif + +#ifdef TOR_UNIT_TESTS build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt, double q_lo, double q_hi); +double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); void circuit_build_times_initial_alpha(circuit_build_times_t *cbt, double quantile, double time_ms); -int circuit_build_times_update_alpha(circuit_build_times_t *cbt); -double circuit_build_times_cdf(circuit_build_times_t *cbt, double x); void circuitbuild_running_unit_tests(void); -void circuit_build_times_reset(circuit_build_times_t *cbt); - -/* Network liveness functions */ -int circuit_build_times_network_check_changed(circuit_build_times_t *cbt); #endif /* Network liveness functions */ @@ -58,8 +62,5 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt); int circuit_build_times_network_check_live(circuit_build_times_t *cbt); void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); -/* DOCDOC circuit_build_times_get_bw_scale */ -int circuit_build_times_get_bw_scale(networkstatus_t *ns); - #endif diff --git a/src/or/config.c b/src/or/config.c index 72ceea395e..5e2de0792c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -10,7 +10,6 @@ **/ #define CONFIG_PRIVATE - #include "or.h" #include "addressmap.h" #include "channel.h" @@ -40,6 +39,7 @@ #include "rendservice.h" #include "rephist.h" #include "router.h" +#include "sandbox.h" #include "util.h" #include "routerlist.h" #include "routerset.h" @@ -281,6 +281,7 @@ static config_var_t option_vars_[] = { V(IPv6Exit, BOOL, "0"), VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL), V(ServerTransportListenAddr, LINELIST, NULL), + V(ServerTransportOptions, LINELIST, NULL), V(Socks4Proxy, STRING, NULL), V(Socks5Proxy, STRING, NULL), V(Socks5ProxyUsername, STRING, NULL), @@ -370,6 +371,7 @@ static config_var_t option_vars_[] = { V(RunAsDaemon, BOOL, "0"), // V(RunTesting, BOOL, "0"), OBSOLETE("RunTesting"), // currently unused + V(Sandbox, BOOL, "0"), V(SafeLogging, STRING, "1"), V(SafeSocks, BOOL, "0"), V(ServerDNSAllowBrokenConfig, BOOL, "1"), @@ -405,7 +407,7 @@ static config_var_t option_vars_[] = { V(UseEntryGuards, BOOL, "1"), V(UseEntryGuardsAsDirGuards, BOOL, "1"), V(UseMicrodescriptors, AUTOBOOL, "auto"), - V(UseNTorHandshake, AUTOBOOL, "auto"), + V(UseNTorHandshake, AUTOBOOL, "1"), V(User, STRING, NULL), V(UserspaceIOCPBuffers, BOOL, "0"), VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"), @@ -414,6 +416,7 @@ static config_var_t option_vars_[] = { V(TestingV3AuthInitialVotingInterval, INTERVAL, "30 minutes"), V(TestingV3AuthInitialVoteDelay, INTERVAL, "5 minutes"), V(TestingV3AuthInitialDistDelay, INTERVAL, "5 minutes"), + V(TestingV3AuthVotingStartOffset, INTERVAL, "0"), V(V3AuthVotingInterval, INTERVAL, "1 hour"), V(V3AuthVoteDelay, INTERVAL, "5 minutes"), V(V3AuthDistDelay, INTERVAL, "5 minutes"), @@ -434,6 +437,23 @@ static config_var_t option_vars_[] = { VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL), V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"), V(VoteOnHidServDirectoriesV2, BOOL, "1"), + V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, " + "300, 900, 2147483647"), + V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 60, 300, 600, " + "2147483647"), + V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " + "300, 600, 1800, 1800, 1800, 1800, " + "1800, 3600, 7200"), + V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, " + "300, 600, 1800, 3600, 3600, 3600, " + "10800, 21600, 43200"), + V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"), + V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"), + V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"), + V(TestingConsensusMaxDownloadTries, UINT, "8"), + V(TestingDescriptorMaxDownloadTries, UINT, "8"), + V(TestingMicrodescMaxDownloadTries, UINT, "8"), + V(TestingCertMaxDownloadTries, UINT, "8"), VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } @@ -459,9 +479,25 @@ static const config_var_t testing_tor_network_defaults[] = { V(TestingV3AuthInitialVotingInterval, INTERVAL, "5 minutes"), V(TestingV3AuthInitialVoteDelay, INTERVAL, "20 seconds"), V(TestingV3AuthInitialDistDelay, INTERVAL, "20 seconds"), + V(TestingV3AuthVotingStartOffset, INTERVAL, "0"), V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"), V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"), V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"), + V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 5, 10, 15, " + "20, 30, 60"), + V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, 15, 20, " + "30, 60"), + V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " + "15, 20, 30, 60"), + V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, " + "15, 20, 30, 60"), + V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "60, 30, 30, 60"), + V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"), + V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"), + V(TestingConsensusMaxDownloadTries, UINT, "80"), + V(TestingDescriptorMaxDownloadTries, UINT, "80"), + V(TestingMicrodescMaxDownloadTries, UINT, "80"), + V(TestingCertMaxDownloadTries, UINT, "80"), VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } @@ -474,9 +510,6 @@ static const config_var_t testing_tor_network_defaults[] = { #ifdef _WIN32 static char *get_windows_conf_root(void); #endif -static int options_validate(or_options_t *old_options, - or_options_t *options, - int from_setconf, char **msg); static int options_act_reversible(const or_options_t *old_options, char **msg); static int options_act(const or_options_t *old_options); static int options_transition_allowed(const or_options_t *old, @@ -488,7 +521,6 @@ static int options_transition_affects_descriptor( const or_options_t *old_options, const or_options_t *new_options); static int check_nickname_list(const char *lst, const char *name, char **msg); -static int parse_bridge_line(const char *line, int validate_only); static int parse_client_transport_line(const char *line, int validate_only); static int parse_server_transport_line(const char *line, int validate_only); @@ -521,7 +553,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options, #define OR_OPTIONS_MAGIC 9090909 /** Configuration format for or_options_t. */ -static config_format_t options_format = { +STATIC config_format_t options_format = { sizeof(or_options_t), OR_OPTIONS_MAGIC, STRUCT_OFFSET(or_options_t, magic_), @@ -677,7 +709,7 @@ get_short_version(void) /** Release additional memory allocated in options */ -static void +STATIC void or_options_free(or_options_t *options) { if (!options) @@ -971,6 +1003,7 @@ options_act_reversible(const or_options_t *old_options, char **msg) int set_conn_limit = 0; int r = -1; int logs_marked = 0; + int old_min_log_level = get_min_log_level(); /* Daemonize _first_, since we only want to open most of this stuff in * the subprocess. Libevent bases can't be reliably inherited across @@ -1109,6 +1142,8 @@ options_act_reversible(const or_options_t *old_options, char **msg) goto rollback; } + sandbox_set_debugging_fd(get_err_logging_fd()); + commit: r = 0; if (logs_marked) { @@ -1119,6 +1154,13 @@ options_act_reversible(const or_options_t *old_options, char **msg) control_adjust_event_log_severity(); tor_free(severity); } + if (get_min_log_level() >= LOG_INFO && + get_min_log_level() != old_min_log_level) { + log_warn(LD_GENERAL, "Your log may contain sensitive information - you're " + "logging above \"notice\". Please log safely. Don't log unless " + "it serves an important reason. Overwrite the log afterwards."); + } + SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn, { log_notice(LD_NET, "Closing old %s on %s:%d", @@ -1301,14 +1343,23 @@ options_act(const or_options_t *old_options) } #endif + if (options->SafeLogging_ != SAFELOG_SCRUB_ALL && + (!old_options || old_options->SafeLogging_ != options->SafeLogging_)) { + log_warn(LD_GENERAL, "Your log may contain sensitive information - you " + "disabled SafeLogging. Please log safely. Don't log unless it " + "serves an important reason. Overwrite the log afterwards."); + } + if (options->Bridges) { mark_bridge_list(); for (cl = options->Bridges; cl; cl = cl->next) { - if (parse_bridge_line(cl->value, 0)<0) { + bridge_line_t *bridge_line = parse_bridge_line(cl->value); + if (!bridge_line) { log_warn(LD_BUG, "Previously validated Bridge line could not be added!"); return -1; } + bridge_add_from_config(bridge_line); } sweep_bridge_list(); } @@ -1851,7 +1902,8 @@ options_trial_assign(config_line_t *list, int use_defaults, return r; } - if (options_validate(get_options_mutable(), trial_options, 1, msg) < 0) { + if (options_validate(get_options_mutable(), trial_options, + global_default_options, 1, msg) < 0) { config_free(&options_format, trial_options); return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */ } @@ -2281,10 +2333,11 @@ compute_publishserverdescriptor(or_options_t *options) * */ #define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10) -/** Return 0 if every setting in <b>options</b> is reasonable, and a - * permissible transition from <b>old_options</b>. Else return -1. - * Should have no side effects, except for normalizing the contents of - * <b>options</b>. +/** Return 0 if every setting in <b>options</b> is reasonable, is a + * permissible transition from <b>old_options</b>, and none of the + * testing-only settings differ from <b>default_options</b> unless in + * testing mode. Else return -1. Should have no side effects, except for + * normalizing the contents of <b>options</b>. * * On error, tor_strdup an error explanation into *<b>msg</b>. * @@ -2293,9 +2346,9 @@ compute_publishserverdescriptor(or_options_t *options) * Log line should stay empty. If it's 0, then give us a default log * if there are no logs defined. */ -static int +STATIC int options_validate(or_options_t *old_options, or_options_t *options, - int from_setconf, char **msg) + or_options_t *default_options, int from_setconf, char **msg) { int i; config_line_t *cl; @@ -2962,14 +3015,14 @@ options_validate(or_options_t *old_options, or_options_t *options, size_t len; len = strlen(options->Socks5ProxyUsername); - if (len < 1 || len > 255) + if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE) REJECT("Socks5ProxyUsername must be between 1 and 255 characters."); if (!options->Socks5ProxyPassword) REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername."); len = strlen(options->Socks5ProxyPassword); - if (len < 1 || len > 255) + if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE) REJECT("Socks5ProxyPassword must be between 1 and 255 characters."); } else if (options->Socks5ProxyPassword) REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername."); @@ -3053,8 +3106,10 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("If you set UseBridges, you must set TunnelDirConns."); for (cl = options->Bridges; cl; cl = cl->next) { - if (parse_bridge_line(cl->value, 1)<0) - REJECT("Bridge line did not parse. See logs for details."); + bridge_line_t *bridge_line = parse_bridge_line(cl->value); + if (!bridge_line) + REJECT("Bridge line did not parse. See logs for details."); + bridge_line_free(bridge_line); } for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { @@ -3090,6 +3145,19 @@ options_validate(or_options_t *old_options, or_options_t *options, "ServerTransportListenAddr line will be ignored."); } + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + /** If get_options_from_transport_options_line() fails with + 'transport' being NULL, it means that something went wrong + while parsing the ServerTransportOptions line. */ + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, NULL); + if (!options_sl) + REJECT("ServerTransportOptions did not parse. See logs for details."); + + SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp)); + smartlist_free(options_sl); + } + if (options->ConstrainedSockets) { /* If the user wants to constrain socket buffer use, make sure the desired * limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */ @@ -3182,35 +3250,46 @@ options_validate(or_options_t *old_options, or_options_t *options, "ignore you."); } - /*XXXX checking for defaults manually like this is a bit fragile.*/ - - /* Keep changes to hard-coded values synchronous to man page and default - * values table. */ - if (options->TestingV3AuthInitialVotingInterval != 30*60 && - !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { - REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing " - "Tor networks!"); - } else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) { +#define CHECK_DEFAULT(arg) \ + STMT_BEGIN \ + if (!options->TestingTorNetwork && \ + !options->UsingTestNetworkDefaults_ && \ + !config_is_same(&options_format,options, \ + default_options,#arg)) { \ + REJECT(#arg " may only be changed in testing Tor " \ + "networks!"); \ + } STMT_END + CHECK_DEFAULT(TestingV3AuthInitialVotingInterval); + CHECK_DEFAULT(TestingV3AuthInitialVoteDelay); + CHECK_DEFAULT(TestingV3AuthInitialDistDelay); + CHECK_DEFAULT(TestingV3AuthVotingStartOffset); + CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability); + CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime); + CHECK_DEFAULT(TestingServerDownloadSchedule); + CHECK_DEFAULT(TestingClientDownloadSchedule); + CHECK_DEFAULT(TestingServerConsensusDownloadSchedule); + CHECK_DEFAULT(TestingClientConsensusDownloadSchedule); + CHECK_DEFAULT(TestingBridgeDownloadSchedule); + CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest); + CHECK_DEFAULT(TestingDirConnectionMaxStall); + CHECK_DEFAULT(TestingConsensusMaxDownloadTries); + CHECK_DEFAULT(TestingDescriptorMaxDownloadTries); + CHECK_DEFAULT(TestingMicrodescMaxDownloadTries); + CHECK_DEFAULT(TestingCertMaxDownloadTries); +#undef CHECK_DEFAULT + + if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) { REJECT("TestingV3AuthInitialVotingInterval is insanely low."); } else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) { REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into " "30 minutes."); } - if (options->TestingV3AuthInitialVoteDelay != 5*60 && - !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { - - REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing " - "Tor networks!"); - } else if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) { + if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) { REJECT("TestingV3AuthInitialVoteDelay is way too low."); } - if (options->TestingV3AuthInitialDistDelay != 5*60 && - !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { - REJECT("TestingV3AuthInitialDistDelay may only be changed in testing " - "Tor networks!"); - } else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) { + if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) { REJECT("TestingV3AuthInitialDistDelay is way too low."); } @@ -3221,26 +3300,61 @@ options_validate(or_options_t *old_options, or_options_t *options, "must be less than half TestingV3AuthInitialVotingInterval"); } - if (options->TestingAuthDirTimeToLearnReachability != 30*60 && - !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { - REJECT("TestingAuthDirTimeToLearnReachability may only be changed in " - "testing Tor networks!"); - } else if (options->TestingAuthDirTimeToLearnReachability < 0) { + if (options->TestingV3AuthVotingStartOffset > + MIN(options->TestingV3AuthInitialVotingInterval, + options->V3AuthVotingInterval)) { + REJECT("TestingV3AuthVotingStartOffset is higher than the voting " + "interval."); + } + + if (options->TestingAuthDirTimeToLearnReachability < 0) { REJECT("TestingAuthDirTimeToLearnReachability must be non-negative."); } else if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) { COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high."); } - if (options->TestingEstimatedDescriptorPropagationTime != 10*60 && - !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) { - REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in " - "testing Tor networks!"); - } else if (options->TestingEstimatedDescriptorPropagationTime < 0) { + if (options->TestingEstimatedDescriptorPropagationTime < 0) { REJECT("TestingEstimatedDescriptorPropagationTime must be non-negative."); } else if (options->TestingEstimatedDescriptorPropagationTime > 60*60) { COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high."); } + if (options->TestingClientMaxIntervalWithoutRequest < 1) { + REJECT("TestingClientMaxIntervalWithoutRequest is way too low."); + } else if (options->TestingClientMaxIntervalWithoutRequest > 3600) { + COMPLAIN("TestingClientMaxIntervalWithoutRequest is insanely high."); + } + + if (options->TestingDirConnectionMaxStall < 5) { + REJECT("TestingDirConnectionMaxStall is way too low."); + } else if (options->TestingDirConnectionMaxStall > 3600) { + COMPLAIN("TestingDirConnectionMaxStall is insanely high."); + } + + if (options->TestingConsensusMaxDownloadTries < 2) { + REJECT("TestingConsensusMaxDownloadTries must be greater than 1."); + } else if (options->TestingConsensusMaxDownloadTries > 800) { + COMPLAIN("TestingConsensusMaxDownloadTries is insanely high."); + } + + if (options->TestingDescriptorMaxDownloadTries < 2) { + REJECT("TestingDescriptorMaxDownloadTries must be greater than 1."); + } else if (options->TestingDescriptorMaxDownloadTries > 800) { + COMPLAIN("TestingDescriptorMaxDownloadTries is insanely high."); + } + + if (options->TestingMicrodescMaxDownloadTries < 2) { + REJECT("TestingMicrodescMaxDownloadTries must be greater than 1."); + } else if (options->TestingMicrodescMaxDownloadTries > 800) { + COMPLAIN("TestingMicrodescMaxDownloadTries is insanely high."); + } + + if (options->TestingCertMaxDownloadTries < 2) { + REJECT("TestingCertMaxDownloadTries must be greater than 1."); + } else if (options->TestingCertMaxDownloadTries > 800) { + COMPLAIN("TestingCertMaxDownloadTries is insanely high."); + } + if (options->TestingTorNetwork) { log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node " "almost unusable in the public Tor network, and is " @@ -3860,7 +3974,8 @@ options_init_from_string(const char *cf_defaults, const char *cf, } /* Validate newoptions */ - if (options_validate(oldoptions, newoptions, 0, msg) < 0) { + if (options_validate(oldoptions, newoptions, newdefaultoptions, + 0, msg) < 0) { err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/ goto err; } @@ -4117,21 +4232,72 @@ options_init_logs(or_options_t *options, int validate_only) return ok?0:-1; } +/** Given a smartlist of SOCKS arguments to be passed to a transport + * proxy in <b>args</b>, validate them and return -1 if they are + * corrupted. Return 0 if they seem OK. */ +static int +validate_transport_socks_arguments(const smartlist_t *args) +{ + char *socks_string = NULL; + size_t socks_string_len; + + tor_assert(args); + tor_assert(smartlist_len(args) > 0); + + SMARTLIST_FOREACH_BEGIN(args, const char *, s) { + if (!string_is_key_value(LOG_WARN, s)) { /* items should be k=v items */ + log_warn(LD_CONFIG, "'%s' is not a k=v item.", s); + return -1; + } + } SMARTLIST_FOREACH_END(s); + + socks_string = pt_stringify_socks_args(args); + if (!socks_string) + return -1; + + socks_string_len = strlen(socks_string); + tor_free(socks_string); + + if (socks_string_len > MAX_SOCKS5_AUTH_SIZE_TOTAL) { + log_warn(LD_CONFIG, "SOCKS arguments can't be more than %u bytes (%lu).", + MAX_SOCKS5_AUTH_SIZE_TOTAL, + (unsigned long) socks_string_len); + return -1; + } + + return 0; +} + +/** Deallocate a bridge_line_t structure. */ +/* private */ void +bridge_line_free(bridge_line_t *bridge_line) +{ + if (!bridge_line) + return; + + if (bridge_line->socks_args) { + SMARTLIST_FOREACH(bridge_line->socks_args, char*, s, tor_free(s)); + smartlist_free(bridge_line->socks_args); + } + tor_free(bridge_line->transport_name); + tor_free(bridge_line); +} + /** Read the contents of a Bridge line from <b>line</b>. Return 0 * if the line is well-formed, and -1 if it isn't. If * <b>validate_only</b> is 0, and the line is well-formed, then add - * the bridge described in the line to our internal bridge list. */ -static int -parse_bridge_line(const char *line, int validate_only) + * the bridge described in the line to our internal bridge list. + * + * Bridge line format: + * Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ... + */ +/* private */ bridge_line_t * +parse_bridge_line(const char *line) { smartlist_t *items = NULL; - int r; char *addrport=NULL, *fingerprint=NULL; - char *transport_name=NULL; - char *field1=NULL; - tor_addr_t addr; - uint16_t port = 0; - char digest[DIGEST_LEN]; + char *field=NULL; + bridge_line_t *bridge_line = tor_malloc_zero(sizeof(bridge_line_t)); items = smartlist_new(); smartlist_split_string(items, line, NULL, @@ -4141,68 +4307,102 @@ parse_bridge_line(const char *line, int validate_only) goto err; } - /* field1 is either a transport name or addrport */ - field1 = smartlist_get(items, 0); + /* first field is either a transport name or addrport */ + field = smartlist_get(items, 0); smartlist_del_keeporder(items, 0); - if (!(strstr(field1, ".") || strstr(field1, ":"))) { - /* new-style bridge line */ - transport_name = field1; + if (string_is_C_identifier(field)) { + /* It's a transport name. */ + bridge_line->transport_name = field; if (smartlist_len(items) < 1) { log_warn(LD_CONFIG, "Too few items to Bridge line."); goto err; } - addrport = smartlist_get(items, 0); + addrport = smartlist_get(items, 0); /* Next field is addrport then. */ smartlist_del_keeporder(items, 0); } else { - addrport = field1; + addrport = field; } - if (tor_addr_port_lookup(addrport, &addr, &port)<0) { + /* Parse addrport. */ + if (tor_addr_port_lookup(addrport, + &bridge_line->addr, &bridge_line->port)<0) { log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport); goto err; } - if (!port) { + if (!bridge_line->port) { log_info(LD_CONFIG, "Bridge address '%s' has no port; using default port 443.", addrport); - port = 443; + bridge_line->port = 443; } + /* If transports are enabled, next field could be a fingerprint or a + socks argument. If transports are disabled, next field must be + a fingerprint. */ if (smartlist_len(items)) { - fingerprint = smartlist_join_strings(items, "", 0, NULL); + if (bridge_line->transport_name) { /* transports enabled: */ + field = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + /* If it's a key=value pair, then it's a SOCKS argument for the + transport proxy... */ + if (string_is_key_value(LOG_DEBUG, field)) { + bridge_line->socks_args = smartlist_new(); + smartlist_add(bridge_line->socks_args, field); + } else { /* ...otherwise, it's the bridge fingerprint. */ + fingerprint = field; + } + + } else { /* transports disabled: */ + fingerprint = smartlist_join_strings(items, "", 0, NULL); + } + } + + /* Handle fingerprint, if it was provided. */ + if (fingerprint) { if (strlen(fingerprint) != HEX_DIGEST_LEN) { log_warn(LD_CONFIG, "Key digest for Bridge is wrong length."); goto err; } - if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) { + if (base16_decode(bridge_line->digest, DIGEST_LEN, + fingerprint, HEX_DIGEST_LEN)<0) { log_warn(LD_CONFIG, "Unable to decode Bridge key digest."); goto err; } } - if (!validate_only) { - log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)", - fmt_addrport(&addr, port), - transport_name ? transport_name : "no transport", - fingerprint ? fingerprint : "no key listed"); - bridge_add_from_config(&addr, port, - fingerprint ? digest : NULL, transport_name); + /* If we are using transports, any remaining items in the smartlist + should be k=v values. */ + if (bridge_line->transport_name && smartlist_len(items)) { + if (!bridge_line->socks_args) + bridge_line->socks_args = smartlist_new(); + + /* append remaining items of 'items' to 'socks_args' */ + smartlist_add_all(bridge_line->socks_args, items); + smartlist_clear(items); + + tor_assert(smartlist_len(bridge_line->socks_args) > 0); + } + + if (bridge_line->socks_args) { + if (validate_transport_socks_arguments(bridge_line->socks_args) < 0) + goto err; } - r = 0; goto done; err: - r = -1; + bridge_line_free(bridge_line); + bridge_line = NULL; done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); tor_free(addrport); - tor_free(transport_name); tor_free(fingerprint); - return r; + + return bridge_line; } /** Read the contents of a ClientTransportPlugin line from @@ -4392,6 +4592,63 @@ get_bindaddr_from_transport_listen_line(const char *line,const char *transport) return addrport; } +/** Given a ServerTransportOptions <b>line</b>, return a smartlist + * with the options. Return NULL if the line was not well-formed. + * + * If <b>transport</b> is set, return NULL if the line is not + * referring to <b>transport</b>. + * + * The returned smartlist and its strings are allocated on the heap + * and it's the responsibility of the caller to free it. */ +smartlist_t * +get_options_from_transport_options_line(const char *line,const char *transport) +{ + smartlist_t *items = smartlist_new(); + smartlist_t *options = smartlist_new(); + const char *parsed_transport = NULL; + + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 2) { + log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line."); + goto err; + } + + parsed_transport = smartlist_get(items, 0); + /* If 'transport' is given, check if it matches the one on the line */ + if (transport && strcmp(transport, parsed_transport)) + goto err; + + SMARTLIST_FOREACH_BEGIN(items, const char *, option) { + if (option_sl_idx == 0) /* skip the transport field (first field)*/ + continue; + + /* validate that it's a k=v value */ + if (!string_is_key_value(LOG_WARN, option)) { + log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option)); + goto err; + } + + /* add it to the options smartlist */ + smartlist_add(options, tor_strdup(option)); + log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option)); + } SMARTLIST_FOREACH_END(option); + + goto done; + + err: + SMARTLIST_FOREACH(options, char*, s, tor_free(s)); + smartlist_free(options); + options = NULL; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + + return options; +} + /** Given the name of a pluggable transport in <b>transport</b>, check * the configuration file to see if the user has explicitly asked for * it to listen on a specific port. Return a <address:port> string if @@ -4412,6 +4669,26 @@ get_transport_bindaddr_from_config(const char *transport) return NULL; } +/** Given the name of a pluggable transport in <b>transport</b>, check + * the configuration file to see if the user has asked us to pass any + * parameters to the pluggable transport. Return a smartlist + * containing the parameters, otherwise NULL. */ +smartlist_t * +get_options_for_server_transport(const char *transport) +{ + config_line_t *cl; + const or_options_t *options = get_options(); + + for (cl = options->ServerTransportOptions; cl; cl = cl->next) { + smartlist_t *options_sl = + get_options_from_transport_options_line(cl->value, transport); + if (options_sl) + return options_sl; + } + + return NULL; +} + /** Read the contents of a ServerTransportPlugin line from * <b>line</b>. Return 0 if the line is well-formed, and -1 if it * isn't. @@ -5886,6 +6163,43 @@ options_get_datadir_fname2_suffix(const or_options_t *options, return fname; } +/** Check wether the data directory has a private subdirectory + * <b>subdir</b>. If not, try to create it. Return 0 on success, + * -1 otherwise. */ +int +check_or_create_data_subdir(const char *subdir) +{ + char *statsdir = get_datadir_fname(subdir); + int return_val = 0; + + if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) { + log_warn(LD_HIST, "Unable to create %s/ directory!", subdir); + return_val = -1; + } + tor_free(statsdir); + return return_val; +} + +/** Create a file named <b>fname</b> with contents <b>str</b> in the + * subdirectory <b>subdir</b> of the data directory. <b>descr</b> + * should be a short description of the file's content and will be + * used for the warning message, if it's present and the write process + * fails. Return 0 on success, -1 otherwise.*/ +int +write_to_data_subdir(const char* subdir, const char* fname, + const char* str, const char* descr) +{ + char *filename = get_datadir_fname2(subdir, fname); + int return_val = 0; + + if (write_str_to_file(filename, str, 0) < 0) { + log_warn(LD_HIST, "Unable to write %s to disk!", descr ? descr : fname); + return_val = -1; + } + tor_free(filename); + return return_val; +} + /** Given a file name check to see whether the file exists but has not been * modified for a very long time. If so, remove it. */ void @@ -5975,6 +6289,7 @@ getinfo_helper_config(control_connection_t *conn, case CONFIG_TYPE_ISOTIME: type = "Time"; break; case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break; case CONFIG_TYPE_CSV: type = "CommaList"; break; + case CONFIG_TYPE_CSV_INTERVAL: type = "TimeIntervalCommaList"; break; case CONFIG_TYPE_LINELIST: type = "LineList"; break; case CONFIG_TYPE_LINELIST_S: type = "Dependant"; break; case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break; diff --git a/src/or/config.h b/src/or/config.h index ef4acac514..16a8a350d5 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -59,6 +59,10 @@ char *options_get_datadir_fname2_suffix(const or_options_t *options, #define get_datadir_fname_suffix(sub1, suffix) \ get_datadir_fname2_suffix((sub1), NULL, (suffix)) +int check_or_create_data_subdir(const char *subdir); +int write_to_data_subdir(const char* subdir, const char* fname, + const char* str, const char* descr); + int get_num_cpus(const or_options_t *options); const smartlist_t *get_configured_ports(void); @@ -86,10 +90,7 @@ uint32_t get_effective_bwburst(const or_options_t *options); char *get_transport_bindaddr_from_config(const char *transport); -#ifdef CONFIG_PRIVATE -/* Used only by config.c and test.c */ or_options_t *options_new(void); -#endif void config_register_addressmaps(const or_options_t *options); /* XXXX024 move to connection_edge.h */ @@ -98,5 +99,34 @@ int addressmap_register_auto(const char *from, const char *to, addressmap_entry_source_t addrmap_source, const char **msg); +/** Represents the information stored in a torrc Bridge line. */ +typedef struct bridge_line_t { + tor_addr_t addr; /* The IP address of the bridge. */ + uint16_t port; /* The TCP port of the bridge. */ + char *transport_name; /* The name of the pluggable transport that + should be used to connect to the bridge. */ + char digest[DIGEST_LEN]; /* The bridge's identity key digest. */ + smartlist_t *socks_args; /* SOCKS arguments for the pluggable + transport proxy. */ +} bridge_line_t; + +void bridge_line_free(bridge_line_t *bridge_line); +bridge_line_t *parse_bridge_line(const char *line); +smartlist_t *get_options_from_transport_options_line(const char *line, + const char *transport); +smartlist_t *get_options_for_server_transport(const char *transport); + +#ifdef CONFIG_PRIVATE +#ifdef TOR_UNIT_TESTS +extern struct config_format_t options_format; +#endif + +STATIC void or_options_free(or_options_t *options); +STATIC int options_validate(or_options_t *old_options, + or_options_t *options, + or_options_t *default_options, + int from_setconf, char **msg); +#endif + #endif diff --git a/src/or/confparse.c b/src/or/confparse.c index 8863d92409..41055791ef 100644 --- a/src/or/confparse.c +++ b/src/or/confparse.c @@ -223,6 +223,8 @@ config_assign_value(const config_format_t *fmt, void *options, int i, ok; const config_var_t *var; void *lvalue; + int *csv_int; + smartlist_t *csv_str; CONFIG_CHECK(fmt, options); @@ -357,6 +359,36 @@ config_assign_value(const config_format_t *fmt, void *options, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); break; + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t**)lvalue, int *, cp, tor_free(cp)); + smartlist_clear(*(smartlist_t**)lvalue); + } else { + *(smartlist_t**)lvalue = smartlist_new(); + } + csv_str = smartlist_new(); + smartlist_split_string(csv_str, c->value, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(csv_str, char *, str) + { + i = config_parse_interval(str, &ok); + if (!ok) { + tor_asprintf(msg, + "Interval in '%s %s' is malformed or out of bounds.", + c->key, c->value); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_clear(csv_str); + return -1; + } + csv_int = tor_malloc_zero(sizeof(int)); + *csv_int = i; + smartlist_add(*(smartlist_t**)lvalue, csv_int); + } + SMARTLIST_FOREACH_END(str); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_clear(csv_str); + break; + case CONFIG_TYPE_LINELIST: case CONFIG_TYPE_LINELIST_S: { @@ -555,6 +587,7 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, const config_var_t *var; const void *value; config_line_t *result; + smartlist_t *csv_str; tor_assert(options && key); CONFIG_CHECK(fmt, options); @@ -637,6 +670,20 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, else result->value = tor_strdup(""); break; + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)value) { + csv_str = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(*(smartlist_t**)value, int *, i) + { + smartlist_add_asprintf(csv_str, "%d", *i); + } + SMARTLIST_FOREACH_END(i); + result->value = smartlist_join_strings(csv_str, ",", 0, NULL); + SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp)); + smartlist_free(csv_str); + } else + result->value = tor_strdup(""); + break; case CONFIG_TYPE_OBSOLETE: log_fn(LOG_INFO, LD_CONFIG, "You asked me for the value of an obsolete config option '%s'.", @@ -826,6 +873,13 @@ config_clear(const config_format_t *fmt, void *options, *(smartlist_t **)lvalue = NULL; } break; + case CONFIG_TYPE_CSV_INTERVAL: + if (*(smartlist_t**)lvalue) { + SMARTLIST_FOREACH(*(smartlist_t **)lvalue, int *, cp, tor_free(cp)); + smartlist_free(*(smartlist_t **)lvalue); + *(smartlist_t **)lvalue = NULL; + } + break; case CONFIG_TYPE_LINELIST: case CONFIG_TYPE_LINELIST_S: config_free_lines(*(config_line_t **)lvalue); @@ -1072,20 +1126,36 @@ static struct unit_table_t memory_units[] = { { "kbytes", 1<<10 }, { "kilobyte", 1<<10 }, { "kilobytes", 1<<10 }, + { "kilobits", 1<<7 }, + { "kilobit", 1<<7 }, + { "kbits", 1<<7 }, + { "kbit", 1<<7 }, { "m", 1<<20 }, { "mb", 1<<20 }, { "mbyte", 1<<20 }, { "mbytes", 1<<20 }, { "megabyte", 1<<20 }, { "megabytes", 1<<20 }, + { "megabits", 1<<17 }, + { "megabit", 1<<17 }, + { "mbits", 1<<17 }, + { "mbit", 1<<17 }, { "gb", 1<<30 }, { "gbyte", 1<<30 }, { "gbytes", 1<<30 }, { "gigabyte", 1<<30 }, { "gigabytes", 1<<30 }, + { "gigabits", 1<<27 }, + { "gigabit", 1<<27 }, + { "gbits", 1<<27 }, + { "gbit", 1<<27 }, { "tb", U64_LITERAL(1)<<40 }, { "terabyte", U64_LITERAL(1)<<40 }, { "terabytes", U64_LITERAL(1)<<40 }, + { "terabits", U64_LITERAL(1)<<37 }, + { "terabit", U64_LITERAL(1)<<37 }, + { "tbits", U64_LITERAL(1)<<37 }, + { "tbit", U64_LITERAL(1)<<37 }, { NULL, 0 }, }; diff --git a/src/or/confparse.h b/src/or/confparse.h index 1b987f3bf9..924ee0d945 100644 --- a/src/or/confparse.h +++ b/src/or/confparse.h @@ -26,6 +26,9 @@ typedef enum config_type_t { CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to UTC. */ CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and * optional whitespace. */ + CONFIG_TYPE_CSV_INTERVAL, /**< A list of strings, separated by commas and + * optional whitespace, representing intervals in + * seconds, with optional units */ CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */ CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines, * mixed with other keywords. */ @@ -73,7 +76,7 @@ typedef int (*validate_fn_t)(void*,void*,int,char**); /** Information on the keys, value types, key-to-struct-member mappings, * variable descriptions, validation functions, and abbreviations for a * configuration or storage format. */ -typedef struct { +typedef struct config_format_t { size_t size; /**< Size of the struct that everything gets parsed into. */ uint32_t magic; /**< Required 'magic value' to make sure we have a struct * of the right type. */ diff --git a/src/or/connection.c b/src/or/connection.c index 6e754a0f7a..6a3cc7bec4 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -44,6 +44,7 @@ #include "router.h" #include "transports.h" #include "routerparse.h" +#include "transports.h" #ifdef USE_BUFFEREVENTS #include <event2/event.h> @@ -876,8 +877,11 @@ check_location_for_unix_socket(const or_options_t *options, const char *path) int r = -1; char *p = tor_strdup(path); cpd_check_t flags = CPD_CHECK_MODE_ONLY; - if (get_parent_directory(p)<0) + if (get_parent_directory(p)<0 || p[0] != '/') { + log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support " + "relative paths for unix sockets.", path); goto done; + } if (options->ControlSocketsGroupWritable) flags |= CPD_GROUP_OK; @@ -939,8 +943,8 @@ connection_listener_new(const struct sockaddr *listensockaddr, 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 */ + connection_t *conn = NULL; + tor_socket_t s = TOR_INVALID_SOCKET; /* the socket we're going to make */ or_options_t const *options = get_options(); #if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H) struct passwd *pw = NULL; @@ -988,7 +992,7 @@ connection_listener_new(const struct sockaddr *listensockaddr, /* We need to set IPV6_V6ONLY so that this socket can't get used for * IPv4 connections. */ if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY, - (void*)&one, sizeof(one))<0) { + (void*)&one, sizeof(one)) < 0) { int e = tor_socket_errno(s); log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s", tor_socket_strerror(e)); @@ -1004,7 +1008,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, helpfulhint = ". Is Tor already running?"; log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort, tor_socket_strerror(e), helpfulhint); - tor_close_socket(s); goto err; } @@ -1012,7 +1015,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (listen(s,SOMAXCONN) < 0) { log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort, tor_socket_strerror(tor_socket_errno(s))); - tor_close_socket(s); goto err; } } @@ -1061,7 +1063,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) { log_warn(LD_NET,"Bind to %s failed: %s.", address, tor_socket_strerror(tor_socket_errno(s))); - tor_close_socket(s); goto err; } #ifdef HAVE_PWD_H @@ -1070,12 +1071,10 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (pw == NULL) { log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.", address, options->User); - tor_close_socket(s); goto err; } else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) { log_warn(LD_NET,"Unable to chown() %s socket: %s.", address, strerror(errno)); - tor_close_socket(s); goto err; } } @@ -1085,35 +1084,32 @@ connection_listener_new(const struct sockaddr *listensockaddr, * platforms. */ if (chmod(address, 0660) < 0) { log_warn(LD_FS,"Unable to make %s group-writable.", address); - tor_close_socket(s); goto err; } } - if (listen(s,SOMAXCONN) < 0) { + if (listen(s, SOMAXCONN) < 0) { log_warn(LD_NET, "Could not listen on %s: %s", address, tor_socket_strerror(tor_socket_errno(s))); - tor_close_socket(s); goto err; } #else (void)options; #endif /* HAVE_SYS_UN_H */ } else { - log_err(LD_BUG,"Got unexpected address family %d.", - listensockaddr->sa_family); - tor_assert(0); + log_err(LD_BUG, "Got unexpected address family %d.", + listensockaddr->sa_family); + tor_assert(0); } - if (set_socket_nonblocking(s) == -1) { - tor_close_socket(s); + if (set_socket_nonblocking(s) == -1) goto err; - } lis_conn = listener_connection_new(type, listensockaddr->sa_family); conn = TO_CONN(lis_conn); conn->socket_family = listensockaddr->sa_family; conn->s = s; + s = TOR_INVALID_SOCKET; /* Prevent double-close */ conn->address = tor_strdup(address); conn->port = gotPort; tor_addr_copy(&conn->addr, &addr); @@ -1149,7 +1145,6 @@ connection_listener_new(const struct sockaddr *listensockaddr, if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for listener failed. Giving up."); - connection_free(conn); goto err; } @@ -1168,6 +1163,11 @@ connection_listener_new(const struct sockaddr *listensockaddr, return conn; err: + if (SOCKET_OK(s)) + tor_close_socket(s); + if (conn) + connection_free(conn); + return NULL; } @@ -1580,6 +1580,32 @@ connection_proxy_state_to_string(int state) return states[state]; } +/** Returns the global proxy type used by tor. Use this function for + * logging or high-level purposes, don't use it to fill the + * <b>proxy_type</b> field of or_connection_t; use the actual proxy + * protocol instead.*/ +static int +get_proxy_type(void) +{ + const or_options_t *options = get_options(); + + if (options->HTTPSProxy) + return PROXY_CONNECT; + else if (options->Socks4Proxy) + return PROXY_SOCKS4; + else if (options->Socks5Proxy) + return PROXY_SOCKS5; + else if (options->ClientTransportPlugin) + return PROXY_PLUGGABLE; + else + return PROXY_NONE; +} + +/* One byte for the version, one for the command, two for the + port, and four for the addr... and, one more for the + username NUL: */ +#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1) + /** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn * for conn->addr:conn->port, authenticating with the auth details given * in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies @@ -1634,17 +1660,45 @@ connection_proxy_connect(connection_t *conn, int type) } case PROXY_SOCKS4: { - unsigned char buf[9]; + unsigned char *buf; uint16_t portn; uint32_t ip4addr; + size_t buf_size = 0; + char *socks_args_string = NULL; - /* Send a SOCKS4 connect request with empty user id */ + /* Send a SOCKS4 connect request */ if (tor_addr_family(&conn->addr) != AF_INET) { log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6"); return -1; } + { /* If we are here because we are trying to connect to a + pluggable transport proxy, check if we have any SOCKS + arguments to transmit. If we do, compress all arguments to + a single string in 'socks_args_string': */ + + if (get_proxy_type() == PROXY_PLUGGABLE) { + socks_args_string = + pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); + if (socks_args_string) + log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.", + socks_args_string); + } + } + + { /* Figure out the buffer size we need for the SOCKS message: */ + + buf_size = SOCKS4_STANDARD_BUFFER_SIZE; + + /* If we have a SOCKS argument string, consider its size when + calculating the buffer size: */ + if (socks_args_string) + buf_size += strlen(socks_args_string); + } + + buf = tor_malloc_zero(buf_size); + ip4addr = tor_addr_to_ipv4n(&conn->addr); portn = htons(conn->port); @@ -1652,9 +1706,23 @@ connection_proxy_connect(connection_t *conn, int type) buf[1] = SOCKS_COMMAND_CONNECT; /* command */ memcpy(buf + 2, &portn, 2); /* port */ memcpy(buf + 4, &ip4addr, 4); /* addr */ - buf[8] = 0; /* userid (empty) */ - connection_write_to_buf((char *)buf, sizeof(buf), conn); + /* Next packet field is the userid. If we have pluggable + transport SOCKS arguments, we have to embed them + there. Otherwise, we use an empty userid. */ + if (socks_args_string) { /* place the SOCKS args string: */ + tor_assert(strlen(socks_args_string) > 0); + tor_assert(buf_size >= + SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string)); + strlcpy((char *)buf + 8, socks_args_string, buf_size - 8); + tor_free(socks_args_string); + } else { + buf[8] = 0; /* no userid */ + } + + connection_write_to_buf((char *)buf, buf_size, conn); + tor_free(buf); + conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK; break; } @@ -1666,8 +1734,13 @@ connection_proxy_connect(connection_t *conn, int type) buf[0] = 5; /* version */ + /* We have to use SOCKS5 authentication, if we have a + Socks5ProxyUsername or if we want to pass arguments to our + pluggable transport proxy: */ + if ((options->Socks5ProxyUsername) || + (get_proxy_type() == PROXY_PLUGGABLE && + (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) { /* number of auth methods */ - if (options->Socks5ProxyUsername) { buf[1] = 2; buf[2] = 0x00; /* no authentication */ buf[3] = 0x02; /* rfc1929 Username/Passwd auth */ @@ -1861,15 +1934,49 @@ connection_read_proxy_handshake(connection_t *conn) unsigned char buf[1024]; size_t reqsize, usize, psize; const char *user, *pass; + char *socks_args_string = NULL; + + if (get_proxy_type() == PROXY_PLUGGABLE) { + socks_args_string = + pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port); + if (!socks_args_string) { + log_warn(LD_NET, "Could not create SOCKS args string."); + ret = -1; + break; + } + + log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string); + tor_assert(strlen(socks_args_string) > 0); + tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL); + + if (strlen(socks_args_string) > MAX_SOCKS5_AUTH_FIELD_SIZE) { + user = socks_args_string; + usize = MAX_SOCKS5_AUTH_FIELD_SIZE; + pass = socks_args_string + MAX_SOCKS5_AUTH_FIELD_SIZE; + psize = strlen(socks_args_string) - MAX_SOCKS5_AUTH_FIELD_SIZE; + } else { + user = socks_args_string; + usize = strlen(socks_args_string); + pass = "\0"; + psize = 1; + } + } else if (get_options()->Socks5ProxyUsername) { + user = get_options()->Socks5ProxyUsername; + pass = get_options()->Socks5ProxyPassword; + tor_assert(user && pass); + usize = strlen(user); + psize = strlen(pass); + } else { + log_err(LD_BUG, "We entered %s for no reason!", __func__); + tor_fragile_assert(); + ret = -1; + break; + } - user = get_options()->Socks5ProxyUsername; - pass = get_options()->Socks5ProxyPassword; - tor_assert(user && pass); - - /* XXX len of user and pass must be <= 255 !!! */ - usize = strlen(user); - psize = strlen(pass); - tor_assert(usize <= 255 && psize <= 255); + /* Username and password lengths should have been checked + above and during torrc parsing. */ + tor_assert(usize <= MAX_SOCKS5_AUTH_FIELD_SIZE && + psize <= MAX_SOCKS5_AUTH_FIELD_SIZE); reqsize = 3 + usize + psize; buf[0] = 1; /* negotiation version */ @@ -1878,6 +1985,9 @@ connection_read_proxy_handshake(connection_t *conn) buf[2 + usize] = psize; memcpy(buf + 3 + usize, pass, psize); + if (socks_args_string) + tor_free(socks_args_string); + connection_write_to_buf((char *)buf, reqsize, conn); conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK; @@ -3288,8 +3398,8 @@ connection_outbuf_too_full(connection_t *conn) /** Try to flush more bytes onto <b>conn</b>-\>s. * - * This function gets called either from conn_write() in main.c - * when poll() has declared that conn wants to write, or below + * This function gets called either from conn_write_callback() in main.c + * when libevent tells us that conn wants to write, or below * from connection_write_to_buf() when an entire TLS record is ready. * * Update <b>conn</b>-\>timestamp_lastwritten to now, and call flush_buf @@ -4366,7 +4476,7 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, options->Bridges) { const transport_t *transport = NULL; int r; - r = find_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); + r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport); if (r<0) return -1; if (transport) { /* transport found */ @@ -4381,24 +4491,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, return 0; } -/** Returns the global proxy type used by tor. */ -static int -get_proxy_type(void) -{ - const or_options_t *options = get_options(); - - if (options->HTTPSProxy) - return PROXY_CONNECT; - else if (options->Socks4Proxy) - return PROXY_SOCKS4; - else if (options->Socks5Proxy) - return PROXY_SOCKS5; - else if (options->ClientTransportPlugin) - return PROXY_PLUGGABLE; - else - return PROXY_NONE; -} - /** Log a failed connection to a proxy server. * <b>conn</b> is the connection we use the proxy server for. */ void diff --git a/src/or/connection.h b/src/or/connection.h index c78fe6e652..3e656ec06e 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -89,6 +89,14 @@ int connection_connect(connection_t *conn, const char *address, const tor_addr_t *addr, uint16_t port, int *socket_error); +/** Maximum size of information that we can fit into SOCKS5 username + or password fields. */ +#define MAX_SOCKS5_AUTH_FIELD_SIZE 255 + +/** Total maximum size of information that we can fit into SOCKS5 + username and password fields. */ +#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE + int connection_proxy_connect(connection_t *conn, int type); int connection_read_proxy_handshake(connection_t *conn); void log_failed_proxy_connection(connection_t *conn); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index bb7ffb9a40..33585a0944 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -407,7 +407,7 @@ connection_edge_finished_flushing(edge_connection_t *conn) * that the name resolution that led us to <b>addr</b> will be valid for * <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on * success. */ -/* private */int +STATIC int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl) @@ -2265,7 +2265,7 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, * Return -1 in the case where want to send a RELAY_END cell, and < -1 when * we don't. **/ -/* static */ int +STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, uint8_t *end_reason_out) { diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index ea284cbcfd..e3a95ad9ed 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -12,6 +12,8 @@ #ifndef TOR_CONNECTION_EDGE_H #define TOR_CONNECTION_EDGE_H +#include "testsupport.h" + #define connection_mark_unattached_ap(conn, endreason) \ connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__) @@ -130,9 +132,9 @@ typedef struct begin_cell_t { unsigned is_begindir : 1; } begin_cell_t; -int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, +STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell, uint8_t *end_reason_out); -int connected_cell_format_payload(uint8_t *payload_out, +STATIC int connected_cell_format_payload(uint8_t *payload_out, const tor_addr_t *addr, uint32_t ttl); #endif diff --git a/src/or/control.c b/src/or/control.c index a88de12d69..3f8d47c554 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -334,7 +334,7 @@ connection_write_str_to_buf(const char *s, control_connection_t *conn) * the end. Replace all LF characters sequences with CRLF. Return the number * of bytes in *<b>out</b>. */ -/* static */ size_t +STATIC size_t write_escaped_data(const char *data, size_t len, char **out) { size_t sz_out = len+8; @@ -382,7 +382,7 @@ write_escaped_data(const char *data, size_t len, char **out) * that appears at the start of a line, and replacing all CRLF sequences * with LF. Return the number of * bytes in *<b>out</b>. */ -/* static */ size_t +STATIC size_t read_escaped_data(const char *data, size_t len, char **out) { char *outp; @@ -1572,7 +1572,8 @@ munge_extrainfo_into_routerinfo(const char *ri_body, if (!(cp = tor_memstr(ei_body, ei_len, kwd))) continue; ++cp; - eol = memchr(cp, '\n', ei_len - (cp-ei_body)); + if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body)))) + continue; memcpy(outp, cp, eol-cp+1); outp += eol-cp+1; } diff --git a/src/or/control.h b/src/or/control.h index 61062da2c4..d0f682067e 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -91,8 +91,8 @@ void control_event_clients_seen(const char *controller_str); #ifdef CONTROL_PRIVATE /* Used only by control.c and test.c */ -size_t write_escaped_data(const char *data, size_t len, char **out); -size_t read_escaped_data(const char *data, size_t len, char **out); +STATIC size_t write_escaped_data(const char *data, size_t len, char **out); +STATIC size_t read_escaped_data(const char *data, size_t len, char **out); #endif #endif diff --git a/src/or/directory.c b/src/or/directory.c index b4381ac0de..88d6717791 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -3723,57 +3723,27 @@ dir_networkstatus_download_failed(smartlist_t *failed, int status_code) } SMARTLIST_FOREACH_END(fp); } -/** Schedule for when servers should download things in general. */ -static const int server_dl_schedule[] = { - 0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX -}; -/** Schedule for when clients should download things in general. */ -static const int client_dl_schedule[] = { - 0, 0, 60, 60*5, 60*10, INT_MAX -}; -/** Schedule for when servers should download consensuses. */ -static const int server_consensus_dl_schedule[] = { - 0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2 -}; -/** Schedule for when clients should download consensuses. */ -static const int client_consensus_dl_schedule[] = { - 0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12 -}; -/** Schedule for when clients should download bridge descriptors. */ -static const int bridge_dl_schedule[] = { - 60*60, 15*60, 15*60, 60*60 -}; - -/** Decide which download schedule we want to use, and then return a - * pointer to it along with a pointer to its length. Helper function for - * download_status_increment_failure() and download_status_reset(). */ -static void -find_dl_schedule_and_len(download_status_t *dls, int server, - const int **schedule, size_t *schedule_len) +/** Decide which download schedule we want to use based on descriptor type + * in <b>dls</b> and whether we are acting as directory <b>server</b>, and + * then return a list of int pointers defining download delays in seconds. + * Helper function for download_status_increment_failure() and + * download_status_reset(). */ +static const smartlist_t * +find_dl_schedule_and_len(download_status_t *dls, int server) { switch (dls->schedule) { case DL_SCHED_GENERIC: - if (server) { - *schedule = server_dl_schedule; - *schedule_len = sizeof(server_dl_schedule)/sizeof(int); - } else { - *schedule = client_dl_schedule; - *schedule_len = sizeof(client_dl_schedule)/sizeof(int); - } - break; + if (server) + return get_options()->TestingServerDownloadSchedule; + else + return get_options()->TestingClientDownloadSchedule; case DL_SCHED_CONSENSUS: - if (server) { - *schedule = server_consensus_dl_schedule; - *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int); - } else { - *schedule = client_consensus_dl_schedule; - *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int); - } - break; + if (server) + return get_options()->TestingServerConsensusDownloadSchedule; + else + return get_options()->TestingClientConsensusDownloadSchedule; case DL_SCHED_BRIDGE: - *schedule = bridge_dl_schedule; - *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int); - break; + return get_options()->TestingBridgeDownloadSchedule; default: tor_assert(0); } @@ -3787,8 +3757,7 @@ time_t download_status_increment_failure(download_status_t *dls, int status_code, const char *item, int server, time_t now) { - const int *schedule; - size_t schedule_len; + const smartlist_t *schedule; int increment; tor_assert(dls); if (status_code != 503 || server) { @@ -3796,14 +3765,14 @@ download_status_increment_failure(download_status_t *dls, int status_code, ++dls->n_download_failures; } - find_dl_schedule_and_len(dls, server, &schedule, &schedule_len); + schedule = find_dl_schedule_and_len(dls, server); - if (dls->n_download_failures < schedule_len) - increment = schedule[dls->n_download_failures]; + if (dls->n_download_failures < smartlist_len(schedule)) + increment = *(int *)smartlist_get(schedule, dls->n_download_failures); else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD) increment = INT_MAX; else - increment = schedule[schedule_len-1]; + increment = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1); if (increment < INT_MAX) dls->next_attempt_at = now+increment; @@ -3836,14 +3805,11 @@ download_status_increment_failure(download_status_t *dls, int status_code, void download_status_reset(download_status_t *dls) { - const int *schedule; - size_t schedule_len; - - find_dl_schedule_and_len(dls, get_options()->DirPort_set, - &schedule, &schedule_len); + const smartlist_t *schedule = find_dl_schedule_and_len( + dls, get_options()->DirPort_set); dls->n_download_failures = 0; - dls->next_attempt_at = time(NULL) + schedule[0]; + dls->next_attempt_at = time(NULL) + *(int *)smartlist_get(schedule, 0); } /** Return the number of failures on <b>dls</b> since the last success (if @@ -3888,7 +3854,8 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, } else { dls = router_get_dl_status_by_descriptor_digest(digest); } - if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES) + if (!dls || dls->n_download_failures >= + get_options()->TestingDescriptorMaxDownloadTries) continue; download_status_increment_failure(dls, status_code, cp, server, now); } SMARTLIST_FOREACH_END(cp); @@ -3919,7 +3886,8 @@ dir_microdesc_download_failed(smartlist_t *failed, if (!rs) continue; dls = &rs->dl_status; - if (dls->n_download_failures >= MAX_MICRODESC_DOWNLOAD_FAILURES) + if (dls->n_download_failures >= + get_options()->TestingMicrodescMaxDownloadTries) continue; { char buf[BASE64_DIGEST256_LEN+1]; diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 3e46153a55..3243ac47c4 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -1907,7 +1907,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now, * the Weighted Fractional Uptime history, and use them to set thresholds for * the Stable, Fast, and Guard flags. Update the fields stable_uptime, * stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth, - * guard_bandwidh_including_exits, guard_bandwidth_excluding_exits, + * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits. * * Also, set the is_exit flag of each router appropriately. */ static void @@ -2082,7 +2082,7 @@ static digestmap_t *mbw_cache = NULL; /** Store a measured bandwidth cache entry when reading the measured * bandwidths file. */ -void +STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, time_t as_of) { @@ -2112,7 +2112,7 @@ dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, } /** Clear and free the measured bandwidth cache */ -void +STATIC void dirserv_clear_measured_bw_cache(void) { if (mbw_cache) { @@ -2123,7 +2123,7 @@ dirserv_clear_measured_bw_cache(void) } /** Scan the measured bandwidth cache and remove expired entries */ -void +STATIC void dirserv_expire_measured_bw_cache(time_t now) { @@ -2145,7 +2145,7 @@ dirserv_expire_measured_bw_cache(time_t now) } /** Get the current size of the measured bandwidth cache */ -int +STATIC int dirserv_get_measured_bw_cache_size(void) { if (mbw_cache) return digestmap_size(mbw_cache); @@ -2155,7 +2155,7 @@ dirserv_get_measured_bw_cache_size(void) /** Query the cache by identity digest, return value indicates whether * we found it. The bw_out and as_of_out pointers receive the cached * bandwidth value and the time it was cached if not NULL. */ -int +STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, time_t *as_of_out) { @@ -2176,7 +2176,7 @@ dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out, } /** Predicate wrapper for dirserv_query_measured_bw_cache() */ -int +STATIC int dirserv_has_measured_bw(const char *node_id) { return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL); @@ -2754,7 +2754,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs) * into a measured_bw_line_t output structure. Returns -1 on failure * or 0 on success. */ -int +STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) { char *line = tor_strdup(orig_line); @@ -2835,7 +2835,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line) * of bandwidth statuses. Returns true if a line is found, * false otherwise. */ -int +STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line, smartlist_t *routerstatuses) { @@ -3093,7 +3093,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, else last_consensus_interval = options->TestingV3AuthInitialVotingInterval; v3_out->valid_after = - dirvote_get_start_of_next_interval(now, (int)last_consensus_interval); + dirvote_get_start_of_next_interval(now, (int)last_consensus_interval, + options->TestingV3AuthVotingStartOffset); format_iso_time(tbuf, v3_out->valid_after); log_notice(LD_DIR,"Choosing valid-after time in vote as %s: " "consensus_set=%d, last_interval=%d", @@ -3167,7 +3168,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /** For v2 authoritative directories only: Replace the contents of * <b>the_v2_networkstatus</b> with a newly generated network status * object. */ -cached_dir_t * +STATIC cached_dir_t * generate_v2_networkstatus_opinion(void) { cached_dir_t *r = NULL; diff --git a/src/or/dirserv.h b/src/or/dirserv.h index f9d36d760f..7221fc9957 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -12,6 +12,8 @@ #ifndef TOR_DIRSERV_H #define TOR_DIRSERV_H +#include "testsupport.h" + /** What fraction (1 over this number) of the relay ID space do we * (as a directory authority) launch connections to at each reachability * test? */ @@ -119,20 +121,21 @@ cached_dir_t *new_cached_dir(char *s, time_t published); /* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ #define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ -int measured_bw_line_parse(measured_bw_line_t *out, const char *line); +STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *line); -int measured_bw_line_apply(measured_bw_line_t *parsed_line, +STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line, smartlist_t *routerstatuses); -void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, +STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, time_t as_of); -void dirserv_clear_measured_bw_cache(void); -void dirserv_expire_measured_bw_cache(time_t now); -int dirserv_get_measured_bw_cache_size(void); -int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out, - time_t *as_of_out); -int dirserv_has_measured_bw(const char *node_id); -cached_dir_t *generate_v2_networkstatus_opinion(void); +STATIC void dirserv_clear_measured_bw_cache(void); +STATIC void dirserv_expire_measured_bw_cache(time_t now); +STATIC int dirserv_get_measured_bw_cache_size(void); +STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id, + long *bw_out, + time_t *as_of_out); +STATIC int dirserv_has_measured_bw(const char *node_id); +STATIC cached_dir_t *generate_v2_networkstatus_opinion(void); #endif int dirserv_read_measured_bandwidths(const char *from_file, diff --git a/src/or/dirvote.c b/src/or/dirvote.c index e0af66e22d..12ceba8549 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -60,7 +60,7 @@ static char *make_consensus_method_list(int low, int high, const char *sep); /** Return a new string containing the string representation of the vote in * <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>. * For v3 authorities. */ -char * +STATIC char * format_networkstatus_vote(crypto_pk_t *private_signing_key, networkstatus_t *v3_ns) { @@ -587,7 +587,7 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning) /** Helper: given a list of valid networkstatus_t, return a new string * containing the contents of the consensus network parameter set. */ -/* private */ char * +STATIC char * dirvote_compute_params(smartlist_t *votes, int method, int total_authorities) { int i; @@ -2533,12 +2533,13 @@ dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out) timing_out->dist_delay = options->V3AuthDistDelay; } -/** Return the start of the next interval of size <b>interval</b> (in seconds) - * after <b>now</b>. Midnight always starts a fresh interval, and if the last - * interval of a day would be truncated to less than half its size, it is - * rolled into the previous interval. */ +/** Return the start of the next interval of size <b>interval</b> (in + * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always + * starts a fresh interval, and if the last interval of a day would be + * truncated to less than half its size, it is rolled into the + * previous interval. */ time_t -dirvote_get_start_of_next_interval(time_t now, int interval) +dirvote_get_start_of_next_interval(time_t now, int interval, int offset) { struct tm tm; time_t midnight_today=0; @@ -2566,6 +2567,10 @@ dirvote_get_start_of_next_interval(time_t now, int interval) if (next + interval/2 > midnight_tomorrow) next = midnight_tomorrow; + next += offset; + if (next - interval > now) + next -= interval; + return next; } @@ -2629,8 +2634,10 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now) vote_delay = dist_delay = interval / 4; start = voting_schedule.interval_starts = - dirvote_get_start_of_next_interval(now,interval); - end = dirvote_get_start_of_next_interval(start+1, interval); + dirvote_get_start_of_next_interval(now,interval, + options->TestingV3AuthVotingStartOffset); + end = dirvote_get_start_of_next_interval(start+1, interval, + options->TestingV3AuthVotingStartOffset); tor_assert(end > start); diff --git a/src/or/dirvote.h b/src/or/dirvote.h index b236452122..3a4951a95f 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -12,10 +12,12 @@ #ifndef TOR_DIRVOTE_H #define TOR_DIRVOTE_H +#include "testsupport.h" + /** Lowest allowable value for VoteSeconds. */ -#define MIN_VOTE_SECONDS 20 +#define MIN_VOTE_SECONDS 2 /** Lowest allowable value for DistSeconds. */ -#define MIN_DIST_SECONDS 20 +#define MIN_DIST_SECONDS 2 /** Smallest allowable voting interval. */ #define MIN_VOTE_INTERVAL 300 @@ -86,7 +88,9 @@ authority_cert_t *authority_cert_dup(authority_cert_t *cert); /* vote scheduling */ void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out); -time_t dirvote_get_start_of_next_interval(time_t now, int interval); +time_t dirvote_get_start_of_next_interval(time_t now, + int interval, + int offset); void dirvote_recalculate_timing(const or_options_t *options, time_t now); void dirvote_act(const or_options_t *options, time_t now); @@ -134,9 +138,9 @@ document_signature_t *voter_get_sig_by_algorithm( digest_algorithm_t alg); #ifdef DIRVOTE_PRIVATE -char *format_networkstatus_vote(crypto_pk_t *private_key, +STATIC char *format_networkstatus_vote(crypto_pk_t *private_key, networkstatus_t *v3_ns); -char *dirvote_compute_params(smartlist_t *votes, int method, +STATIC char *dirvote_compute_params(smartlist_t *votes, int method, int total_authorities); #endif diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index f1af75aefb..cadc70ec7a 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -54,6 +54,10 @@ typedef struct { /** When should we next try to fetch a descriptor for this bridge? */ download_status_t fetch_status; + + /** A smartlist of k=v values to be passed to the SOCKS proxy, if + transports are used for this bridge. */ + smartlist_t *socks_args; } bridge_info_t; /** A list of our chosen entry guards. */ @@ -1583,6 +1587,11 @@ bridge_free(bridge_info_t *bridge) return; tor_free(bridge->transport_name); + if (bridge->socks_args) { + SMARTLIST_FOREACH(bridge->socks_args, char*, s, tor_free(s)); + smartlist_free(bridge->socks_args); + } + tor_free(bridge); } @@ -1761,30 +1770,51 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port, } SMARTLIST_FOREACH_END(bridge); } -/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b> - * is set, it tells us the identity key too. If we already had the - * bridge in our list, unmark it, and don't actually add anything new. - * If <b>transport_name</b> is non-NULL - the bridge is associated with a - * pluggable transport - we assign the transport to the bridge. */ +/** Register the bridge information in <b>bridge_line</b> to the + * bridge subsystem. Steals reference of <b>bridge_line</b>. */ void -bridge_add_from_config(const tor_addr_t *addr, uint16_t port, - const char *digest, const char *transport_name) +bridge_add_from_config(bridge_line_t *bridge_line) { bridge_info_t *b; - bridge_resolve_conflicts(addr, port, digest, transport_name); + { /* Log the bridge we are about to register: */ + log_debug(LD_GENERAL, "Registering bridge at %s (transport: %s) (%s)", + fmt_addrport(&bridge_line->addr, bridge_line->port), + bridge_line->transport_name ? + bridge_line->transport_name : "no transport", + tor_digest_is_zero(bridge_line->digest) ? + "no key listed" : hex_str(bridge_line->digest, DIGEST_LEN)); + + if (bridge_line->socks_args) { /* print socks arguments */ + int i = 0; + + tor_assert(smartlist_len(bridge_line->socks_args) > 0); + + log_debug(LD_GENERAL, "Bridge uses %d SOCKS arguments:", + smartlist_len(bridge_line->socks_args)); + SMARTLIST_FOREACH(bridge_line->socks_args, const char *, arg, + log_debug(LD_CONFIG, "%d: %s", ++i, arg)); + } + } + + bridge_resolve_conflicts(&bridge_line->addr, + bridge_line->port, + bridge_line->digest, + bridge_line->transport_name); b = tor_malloc_zero(sizeof(bridge_info_t)); - tor_addr_copy(&b->addr, addr); - b->port = port; - if (digest) - memcpy(b->identity, digest, DIGEST_LEN); - if (transport_name) - b->transport_name = tor_strdup(transport_name); + tor_addr_copy(&b->addr, &bridge_line->addr); + b->port = bridge_line->port; + memcpy(b->identity, bridge_line->digest, DIGEST_LEN); + if (bridge_line->transport_name) + b->transport_name = bridge_line->transport_name; b->fetch_status.schedule = DL_SCHED_BRIDGE; + b->socks_args = bridge_line->socks_args; if (!bridge_list) bridge_list = smartlist_new(); + tor_free(bridge_line); /* Deallocate bridge_line now. */ + smartlist_add(bridge_list, b); } @@ -1845,7 +1875,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) * transport, but the transport could not be found. */ int -find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, +get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const transport_t **transport) { *transport = NULL; @@ -1872,6 +1902,17 @@ find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, return 0; } +/** Return a smartlist containing all the SOCKS arguments that we + * should pass to the SOCKS proxy. */ +const smartlist_t * +get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port) +{ + bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr, + port, + NULL); + return bridge ? bridge->socks_args : NULL; +} + /** We need to ask <b>bridge</b> for its server descriptor. */ static void launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge) diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 52b8dc00e4..533f2027aa 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -97,9 +97,8 @@ int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); int node_is_a_configured_bridge(const node_t *node); void learned_router_identity(const tor_addr_t *addr, uint16_t port, const char *digest); -void bridge_add_from_config(const tor_addr_t *addr, uint16_t port, - const char *digest, - const char *transport_name); +struct bridge_line_t; +void bridge_add_from_config(struct bridge_line_t *bridge_line); void retry_bridge_descriptor_fetch_directly(const char *digest); void fetch_bridge_descriptors(const or_options_t *options, time_t now); void learned_bridge_descriptor(routerinfo_t *ri, int from_cache); @@ -109,13 +108,17 @@ int entries_known_but_down(const or_options_t *options); void entries_retry_all(const or_options_t *options); int any_bridge_supports_microdescriptors(void); +const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr, + uint16_t port); + +int any_bridges_dont_support_microdescriptors(void); void entry_guards_free_all(void); const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port); struct transport_t; -int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, +int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const struct transport_t **transport); int validate_pluggable_transports_config(void); diff --git a/src/or/geoip.c b/src/or/geoip.c index e2e98e8ec4..020075f80f 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -120,7 +120,7 @@ geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high, /** Add an entry to the GeoIP table indicated by <b>family</b>, * parsing it from <b>line</b>. The format is as for geoip_load_file(). */ -/*private*/ int +STATIC int geoip_parse_entry(const char *line, sa_family_t family) { tor_addr_t low_addr, high_addr; @@ -363,7 +363,7 @@ geoip_load_file(sa_family_t family, const char *filename) * be less than geoip_get_n_countries(). To decode it, call * geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr) { geoip_ipv4_entry_t *ent; @@ -379,7 +379,7 @@ geoip_get_country_by_ipv4(uint32_t ipaddr) * 0 for the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr) { geoip_ipv6_entry_t *ent; @@ -1132,7 +1132,7 @@ geoip_format_dirreq_stats(time_t now) time_t geoip_dirreq_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_dirreq_stats_interval) return 0; /* Not initialized. */ @@ -1146,21 +1146,13 @@ geoip_dirreq_stats_write(time_t now) 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) { - log_warn(LD_HIST, "Unable to create stats/ directory!"); - goto done; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "dirreq-stats", str, "dirreq statistics"); + /* Reset measurement interval start. */ + geoip_reset_dirreq_stats(now); } - filename = get_datadir_fname2("stats", "dirreq-stats"); - if (write_str_to_file(filename, str, 0) < 0) - log_warn(LD_HIST, "Unable to write dirreq statistics to disk!"); - - /* Reset measurement interval start. */ - geoip_reset_dirreq_stats(now); done: - tor_free(statsdir); - tor_free(filename); tor_free(str); return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL; } @@ -1297,7 +1289,7 @@ format_bridge_stats_controller(time_t now) time_t geoip_bridge_stats_write(time_t now) { - char *filename = NULL, *val = NULL, *statsdir = NULL; + char *val = NULL; /* Check if 24 hours have passed since starting measurements. */ if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL) @@ -1317,24 +1309,20 @@ geoip_bridge_stats_write(time_t now) start_of_bridge_stats_interval = now; /* Write it to disk. */ - statsdir = get_datadir_fname("stats"); - if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) - goto done; - filename = get_datadir_fname2("stats", "bridge-stats"); - - write_str_to_file(filename, bridge_stats_extrainfo, 0); - - /* Tell the controller, "hey, there are clients!" */ - { - char *controller_str = format_bridge_stats_controller(now); - if (controller_str) - control_event_clients_seen(controller_str); - tor_free(controller_str); + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "bridge-stats", + bridge_stats_extrainfo, "bridge statistics"); + + /* Tell the controller, "hey, there are clients!" */ + { + char *controller_str = format_bridge_stats_controller(now); + if (controller_str) + control_event_clients_seen(controller_str); + tor_free(controller_str); + } } - done: - tor_free(filename); - tor_free(statsdir); + done: return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL; } @@ -1436,7 +1424,7 @@ geoip_format_entry_stats(time_t now) time_t geoip_entry_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_entry_stats_interval) return 0; /* Not initialized. */ @@ -1450,21 +1438,14 @@ geoip_entry_stats_write(time_t now) 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) { - log_warn(LD_HIST, "Unable to create stats/ directory!"); - goto done; - } - filename = get_datadir_fname2("stats", "entry-stats"); - if (write_str_to_file(filename, str, 0) < 0) - log_warn(LD_HIST, "Unable to write entry statistics to disk!"); + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "entry-stats", str, "entry statistics"); - /* Reset measurement interval start. */ - geoip_reset_entry_stats(now); + /* Reset measurement interval start. */ + geoip_reset_entry_stats(now); + } done: - tor_free(statsdir); - tor_free(filename); tor_free(str); return start_of_entry_stats_interval + WRITE_STATS_INTERVAL; } diff --git a/src/or/geoip.h b/src/or/geoip.h index ebefee5f4e..d67007298e 100644 --- a/src/or/geoip.h +++ b/src/or/geoip.h @@ -12,10 +12,12 @@ #ifndef TOR_GEOIP_H #define TOR_GEOIP_H +#include "testsupport.h" + #ifdef GEOIP_PRIVATE -int geoip_parse_entry(const char *line, sa_family_t family); -int geoip_get_country_by_ipv4(uint32_t ipaddr); -int geoip_get_country_by_ipv6(const struct in6_addr *addr); +STATIC int geoip_parse_entry(const char *line, sa_family_t family); +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr); +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr); #endif int should_record_bridge_info(const or_options_t *options); int geoip_load_file(sa_family_t family, const char *filename); diff --git a/src/or/hibernate.c b/src/or/hibernate.c index a412571331..22c0f253da 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -1010,6 +1010,7 @@ getinfo_helper_accounting(control_connection_t *conn, return 0; } +#ifdef TOR_UNIT_TESTS /** * Manually change the hibernation state. Private; used only by the unit * tests. @@ -1019,4 +1020,5 @@ hibernate_set_state_for_testing_(hibernate_state_t newstate) { hibernate_state = newstate; } +#endif diff --git a/src/or/hibernate.h b/src/or/hibernate.h index d2d6989e10..18832fbc6c 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -45,8 +45,10 @@ typedef enum { HIBERNATE_STATE_INITIAL=5 } hibernate_state_t; +#ifdef TOR_UNIT_TESTS void hibernate_set_state_for_testing_(hibernate_state_t newstate); #endif +#endif #endif diff --git a/src/or/include.am b/src/or/include.am index 65dbeff53e..f5002e6986 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -1,5 +1,13 @@ bin_PROGRAMS+= src/or/tor -noinst_LIBRARIES+= src/or/libtor.a +noinst_LIBRARIES += \ + src/or/libtor.a +if UNITTESTS_ENABLED +noinst_LIBRARIES += \ + src/or/libtor-testing.a +endif +if COVERAGE_ENABLED +noinst_PROGRAMS+= src/or/tor-cov +endif if BUILD_NT_SERVICES tor_platform_source=src/or/ntmain.c @@ -21,7 +29,7 @@ else onion_ntor_source= endif -src_or_libtor_a_SOURCES = \ +LIBTOR_A_SOURCES = \ src/or/addressmap.c \ src/or/buffers.c \ src/or/channel.c \ @@ -77,6 +85,9 @@ src_or_libtor_a_SOURCES = \ $(onion_ntor_source) \ src/or/config_codedigest.c +src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) +src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES) + #libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \ # ../common/libor-event.a @@ -90,6 +101,9 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" +src_or_libtor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS) +src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on windows, but I assure you that it # matters a lot there, and is quite hard to debug if you forget to do it. @@ -102,6 +116,18 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ +if COVERAGE_ENABLED +src_or_tor_cov_SOURCES = src/or/tor_main.c +src_or_tor_cov_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS) +src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ +src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \ + src/common/libor-crypto-testing.a $(LIBDONNA) \ + src/common/libor-event-testing.a \ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ +endif + ORHEADERS = \ src/or/addressmap.h \ src/or/buffers.h \ diff --git a/src/or/main.c b/src/or/main.c index bd23141b97..d1728250a4 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -10,7 +10,6 @@ * connections, implements main loop, and drives scheduled events. **/ -#define MAIN_PRIVATE #include "or.h" #include "addressmap.h" #include "buffers.h" @@ -57,6 +56,7 @@ #include <openssl/crypto.h> #endif #include "memarea.h" +#include "../common/sandbox.h" #ifdef HAVE_EVENT2_EVENT_H #include <event2/event.h> @@ -155,8 +155,6 @@ int can_complete_circuit=0; /** How often do we 'forgive' undownloadable router descriptors and attempt * to download them again? */ #define DESCRIPTOR_FAILURE_RESET_INTERVAL (60*60) -/** How long do we let a directory connection stall before expiring it? */ -#define DIR_CONN_MAX_STALL (5*60) /** Decides our behavior when no logs are configured/before any * logs have been configured. For 0, we log notice to stdout as normal. @@ -1028,9 +1026,11 @@ run_connection_housekeeping(int i, time_t now) * if a server or received if a client) for 5 min */ if (conn->type == CONN_TYPE_DIR && ((DIR_CONN_IS_SERVER(conn) && - conn->timestamp_lastwritten + DIR_CONN_MAX_STALL < now) || + conn->timestamp_lastwritten + + options->TestingDirConnectionMaxStall < now) || (!DIR_CONN_IS_SERVER(conn) && - conn->timestamp_lastread + DIR_CONN_MAX_STALL < now))) { + conn->timestamp_lastread + + options->TestingDirConnectionMaxStall < now))) { log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)", (int)conn->s, conn->purpose); /* This check is temporary; it's to let us know whether we should consider @@ -1153,6 +1153,7 @@ run_scheduled_events(time_t now) static time_t time_to_check_v3_certificate = 0; static time_t time_to_check_listeners = 0; static time_t time_to_check_descriptor = 0; + static time_t time_to_download_networkstatus = 0; static time_t time_to_shrink_memory = 0; static time_t time_to_try_getting_descriptors = 0; static time_t time_to_reset_descriptor_failures = 0; @@ -1442,10 +1443,18 @@ run_scheduled_events(time_t now) networkstatus_v2_list_clean(now); /* Remove dead routers. */ routerlist_remove_old_routers(); + } - /* Also, once per minute, check whether we want to download any - * networkstatus documents. - */ + /* 2c. Every minute (or every second if TestingTorNetwork), check + * whether we want to download any networkstatus documents. */ + +/* How often do we check whether we should download network status + * documents? */ +#define networkstatus_dl_check_interval(o) ((o)->TestingTorNetwork ? 1 : 60) + + if (time_to_download_networkstatus < now && !options->DisableNetwork) { + time_to_download_networkstatus = + now + networkstatus_dl_check_interval(options); update_networkstatus_downloads(now); } @@ -1865,7 +1874,7 @@ do_hup(void) } /** Tor main loop. */ -/* static */ int +int do_main_loop(void) { int loop_result; @@ -2292,7 +2301,7 @@ handle_signals(int is_parent) /** Main entry point for the Tor command-line client. */ -/* static */ int +int tor_init(int argc, char *argv[]) { char buf[256]; @@ -2558,7 +2567,7 @@ tor_cleanup(void) } /** Read/create keys as needed, and echo our fingerprint to stdout. */ -/* static */ int +static int do_list_fingerprint(void) { char buf[FINGERPRINT_LEN+1]; @@ -2588,7 +2597,7 @@ do_list_fingerprint(void) /** Entry point for password hashing: take the desired password from * the command line, and print its salted hash to stdout. **/ -/* static */ void +static void do_hash_password(void) { @@ -2695,6 +2704,14 @@ tor_main(int argc, char *argv[]) #endif if (tor_init(argc, argv)<0) return -1; + + if (get_options()->Sandbox) { + if (tor_global_sandbox()) { + log_err(LD_BUG,"Failed to create syscall sandbox filter"); + return -1; + } + } + switch (get_options()->command) { case CMD_RUN_TOR: #ifdef NT_SERVICE diff --git a/src/or/main.h b/src/or/main.h index 338449b6a6..85621a32bf 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -66,12 +66,8 @@ void tor_free_all(int postfork); int tor_main(int argc, char *argv[]); -#ifdef MAIN_PRIVATE int do_main_loop(void); -int do_list_fingerprint(void); -void do_hash_password(void); int tor_init(int argc, char **argv); -#endif #endif diff --git a/src/or/microdesc.c b/src/or/microdesc.c index b93bd83af5..8c763c6729 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -139,7 +139,7 @@ get_microdesc_cache(void) * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>, * mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE, * leave their bodies as pointers to the mmap'd cache. If where is - * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is positive, + * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is not -1, * set the last_listed field of every microdesc to listed_at. If * requested_digests is non-null, then it contains a list of digests we mean * to allow, so we should reject any non-requested microdesc with a different @@ -159,7 +159,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache, descriptors = microdescs_parse_from_string(s, eos, allow_annotations, copy_body); - if (listed_at > 0) { + if (listed_at != (time_t)-1) { SMARTLIST_FOREACH(descriptors, microdesc_t *, md, md->last_listed = listed_at); } @@ -687,7 +687,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache, continue; if (downloadable_only && !download_status_is_ready(&rs->dl_status, now, - MAX_MICRODESC_DOWNLOAD_FAILURES)) + get_options()->TestingMicrodescMaxDownloadTries)) continue; if (skip && digestmap_get(skip, rs->descriptor_digest)) continue; diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 8715841544..3f995a9f6c 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1203,8 +1203,6 @@ we_want_to_fetch_flavor(const or_options_t *options, int flavor) return flavor == usable_consensus_flavor(); } -/** How many times will we try to fetch a consensus before we give up? */ -#define CONSENSUS_NETWORKSTATUS_MAX_DL_TRIES 8 /** How long will we hang onto a possibly live consensus for which we're * fetching certs before we check whether there is a better one? */ #define DELAY_WHILE_FETCHING_CERTS (20*60) @@ -1238,7 +1236,7 @@ update_consensus_networkstatus_downloads(time_t now) resource = networkstatus_get_flavor_name(i); if (!download_status_is_ready(&consensus_dl_status[i], now, - CONSENSUS_NETWORKSTATUS_MAX_DL_TRIES)) + options->TestingConsensusMaxDownloadTries)) continue; /* We failed downloading a consensus too recently. */ if (connection_dir_get_by_purpose_and_resource( DIR_PURPOSE_FETCH_CONSENSUS, resource)) diff --git a/src/or/ntmain.c b/src/or/ntmain.c index 8b67b86822..2fa074d0be 100644 --- a/src/or/ntmain.c +++ b/src/or/ntmain.c @@ -3,7 +3,6 @@ * Copyright (c) 2007-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#define MAIN_PRIVATE #include "or.h" #include "config.h" #include "main.h" diff --git a/src/or/or.h b/src/or/or.h index 3dc96b9a9d..a6a4bcc1ba 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -99,6 +99,7 @@ #include "ht.h" #include "replaycache.h" #include "crypto_curve25519.h" +#include "tor_queue.h" /* These signals are defined to help handle_control_signal work. */ @@ -238,7 +239,9 @@ typedef enum { #define PROXY_SOCKS5 3 /* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type * field in or_connection_t */ -/* pluggable transports proxy type */ + +/* Pluggable transport proxy type. Don't use this in or_connection_t, + * instead use the actual underlying proxy type (see above). */ #define PROXY_PLUGGABLE 4 /* Proxy client handshake states */ @@ -823,9 +826,15 @@ typedef enum { /** Maximum number of queued cells on a circuit for which we are the * midpoint before we give up and kill it. This must be >= circwindow * to avoid killing innocent circuits, and >= circwindow*2 to give - * leaky-pipe a chance for being useful someday. + * leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH + * ratio controls the margin of error between emitting a warning and + * killing the circuit. + */ +#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2) +/** Ratio of hard (circuit kill) to soft (warning) thresholds for the + * ORCIRC_MAX_MIDDLE_CELLS tests. */ -#define ORCIRC_MAX_MIDDLE_CELLS (21*(CIRCWINDOW_START_MAX)/10) +#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f) /* Cell commands. These values are defined in tor-spec.txt. */ #define CELL_PADDING 0 @@ -1075,7 +1084,8 @@ typedef struct var_cell_t { /** A cell as packed for writing to the network. */ typedef struct packed_cell_t { - struct packed_cell_t *next; /**< Next cell queued on this circuit. */ + /** Next cell queued on this circuit. */ + TOR_SIMPLEQ_ENTRY(packed_cell_t) next; char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ } packed_cell_t; @@ -1097,8 +1107,8 @@ typedef struct insertion_time_queue_t { /** A queue of cells on a circuit, waiting to be added to the * or_connection_t's outbuf. */ typedef struct cell_queue_t { - packed_cell_t *head; /**< The first cell, or NULL if the queue is empty. */ - packed_cell_t *tail; /**< The last cell, or NULL if the queue is empty. */ + /** Linked list of packed_cell_t*/ + TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; int n; /**< The number of cells in the queue. */ insertion_time_queue_t *insertion_times; /**< Insertion times of cells. */ } cell_queue_t; @@ -2286,14 +2296,6 @@ typedef struct node_t { } node_t; -/** How many times will we try to download a router's descriptor before giving - * up? */ -#define MAX_ROUTERDESC_DOWNLOAD_FAILURES 8 - -/** How many times will we try to download a microdescriptor before giving - * up? */ -#define MAX_MICRODESC_DOWNLOAD_FAILURES 8 - /** Contents of a v2 (non-consensus, non-vote) network status object. */ typedef struct networkstatus_v2_t { /** When did we receive the network-status document? */ @@ -2503,10 +2505,6 @@ typedef struct desc_store_t { * filename for a temporary file when rebuilding the store, and .new to this * filename for the journal. */ const char *fname_base; - /** Alternative (obsolete) value for fname_base: if the file named by - * fname_base isn't present, we read from here instead, but we never write - * here. */ - const char *fname_alt_base; /** Human-readable description of what this store contains. */ const char *description; @@ -2796,6 +2794,13 @@ typedef struct circuit_t { * allowing n_streams to add any more cells. (OR circuit only.) */ unsigned int streams_blocked_on_p_chan : 1; + /** True iff we have queued a delete backwards on this circuit, but not put + * it on the output buffer. */ + unsigned int p_delete_pending : 1; + /** True iff we have queued a delete forwards on this circuit, but not put + * it on the output buffer. */ + unsigned int n_delete_pending : 1; + uint8_t state; /**< Current status of this circuit. */ uint8_t purpose; /**< Why are we creating this circuit? */ @@ -3176,6 +3181,12 @@ typedef struct or_circuit_t { * exit-ward queues of this circuit; reset every time when writing * buffer stats to disk. */ uint64_t total_cell_waiting_time; + + /** Maximum cell queue size for a middle relay; this is stored per circuit + * so append_cell_to_circuit_queue() can adjust it if it changes. If set + * to zero, it is initialized to the default value. + */ + uint32_t max_middle_cells; } or_circuit_t; /** Convert a circuit subtype to a circuit_t. */ @@ -3491,6 +3502,9 @@ typedef struct { /** List of TCP/IP addresses that transports should listen at. */ config_line_t *ServerTransportListenAddr; + /** List of options that must be passed to pluggable transports. */ + config_line_t *ServerTransportOptions; + int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make * this explicit so we can change how we behave in the * future. */ @@ -3750,6 +3764,7 @@ typedef struct { SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE } SafeLogging_; + int Sandbox; /**< Boolean: should sandboxing be enabled? */ int SafeSocks; /**< Boolean: should we outright refuse application * connections that use socks4 or socks5-with-local-dns? */ #define LOG_PROTOCOL_WARN (get_options()->ProtocolWarnings ? \ @@ -3921,6 +3936,10 @@ typedef struct { * signatures. Only altered on testing networks.*/ int TestingV3AuthInitialDistDelay; + /** Offset in seconds added to the starting time for consensus + voting. Only altered on testing networks. */ + int TestingV3AuthVotingStartOffset; + /** If an authority has been around for less than this amount of time, it * does not believe its reachability information is accurate. Only * altered on testing networks. */ @@ -3931,6 +3950,51 @@ typedef struct { * networks. */ int TestingEstimatedDescriptorPropagationTime; + /** Schedule for when servers should download things in general. Only + * altered on testing networks. */ + smartlist_t *TestingServerDownloadSchedule; + + /** Schedule for when clients should download things in general. Only + * altered on testing networks. */ + smartlist_t *TestingClientDownloadSchedule; + + /** Schedule for when servers should download consensuses. Only altered + * on testing networks. */ + smartlist_t *TestingServerConsensusDownloadSchedule; + + /** Schedule for when clients should download consensuses. Only altered + * on testing networks. */ + smartlist_t *TestingClientConsensusDownloadSchedule; + + /** Schedule for when clients should download bridge descriptors. Only + * altered on testing networks. */ + smartlist_t *TestingBridgeDownloadSchedule; + + /** When directory clients have only a few descriptors to request, they + * batch them until they have more, or until this amount of time has + * passed. Only altered on testing networks. */ + int TestingClientMaxIntervalWithoutRequest; + + /** How long do we let a directory connection stall before expiring + * it? Only altered on testing networks. */ + int TestingDirConnectionMaxStall; + + /** How many times will we try to fetch a consensus before we give + * up? Only altered on testing networks. */ + int TestingConsensusMaxDownloadTries; + + /** How many times will we try to download a router's descriptor before + * giving up? Only altered on testing networks. */ + int TestingDescriptorMaxDownloadTries; + + /** How many times will we try to download a microdescriptor before + * giving up? Only altered on testing networks. */ + int TestingMicrodescMaxDownloadTries; + + /** How many times will we try to fetch a certificate before giving + * up? Only altered on testing networks. */ + int TestingCertMaxDownloadTries; + /** If true, we take part in a testing network. Change the defaults of a * couple of other configuration options and allow to change the values * of certain configuration options. */ diff --git a/src/or/relay.c b/src/or/relay.c index 3138c5e8d1..297f0f69e0 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -58,6 +58,9 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, entry_connection_t *conn, node_t *node, const tor_addr_t *addr); +#if 0 +static int get_max_middle_cells(void); +#endif /** Stop reading on edge connections when we have this many cells * waiting on the appropriate queue. */ @@ -966,7 +969,7 @@ remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr) * <b>addr_out</b> to the address we're connected to, and <b>ttl_out</b> to * the ttl of that address, in seconds, and return 0. On failure, return * -1. */ -int +STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, tor_addr_t *addr_out, int *ttl_out) { @@ -1494,7 +1497,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if (layer_hint) { if (layer_hint->package_window + CIRCWINDOW_INCREMENT > CIRCWINDOW_START_MAX) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL, "Unexpected sendme cell from exit relay. " "Closing circ."); return -END_CIRC_REASON_TORPROTOCOL; @@ -1506,7 +1510,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } else { if (circ->package_window + CIRCWINDOW_INCREMENT > CIRCWINDOW_START_MAX) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600); + log_fn_ratelim(&client_warn_ratelim, LOG_WARN, LD_PROTOCOL, "Unexpected sendme cell from client. " "Closing circ (window %d).", circ->package_window); @@ -2084,7 +2089,7 @@ packed_cell_free_unchecked(packed_cell_t *cell) } /** Allocate and return a new packed_cell_t. */ -static INLINE packed_cell_t * +STATIC packed_cell_t * packed_cell_new(void) { ++total_cells_allocated; @@ -2095,6 +2100,8 @@ packed_cell_new(void) void packed_cell_free(packed_cell_t *cell) { + if (!cell) + return; packed_cell_free_unchecked(cell); } @@ -2124,7 +2131,6 @@ packed_cell_copy(const cell_t *cell, int wide_circ_ids) { packed_cell_t *c = packed_cell_new(); cell_pack(c, cell, wide_circ_ids); - c->next = NULL; return c; } @@ -2132,25 +2138,18 @@ packed_cell_copy(const cell_t *cell, int wide_circ_ids) void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell) { - if (queue->tail) { - tor_assert(!queue->tail->next); - queue->tail->next = cell; - } else { - queue->head = cell; - } - queue->tail = cell; - cell->next = NULL; + TOR_SIMPLEQ_INSERT_TAIL(&queue->head, cell, next); ++queue->n; } /** Append a newly allocated copy of <b>cell</b> to the end of <b>queue</b> */ void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell, - int wide_circ_ids) + int wide_circ_ids, int use_stats) { packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids); /* Remember the time when this cell was put in the queue. */ - if (get_options()->CellStatistics) { + if (get_options()->CellStatistics && use_stats) { struct timeval now; uint32_t added; insertion_time_queue_t *it_queue = queue->insertion_times; @@ -2182,18 +2181,24 @@ cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell, cell_queue_append(queue, copy); } +/** Initialize <b>queue</b> as an empty cell queue. */ +void +cell_queue_init(cell_queue_t *queue) +{ + memset(queue, 0, sizeof(cell_queue_t)); + TOR_SIMPLEQ_INIT(&queue->head); +} + /** Remove and free every cell in <b>queue</b>. */ void cell_queue_clear(cell_queue_t *queue) { - packed_cell_t *cell, *next; - cell = queue->head; - while (cell) { - next = cell->next; + packed_cell_t *cell; + while ((cell = TOR_SIMPLEQ_FIRST(&queue->head))) { + TOR_SIMPLEQ_REMOVE_HEAD(&queue->head, next); packed_cell_free_unchecked(cell); - cell = next; } - queue->head = queue->tail = NULL; + TOR_SIMPLEQ_INIT(&queue->head); queue->n = 0; if (queue->insertion_times) { while (queue->insertion_times->first) { @@ -2207,17 +2212,13 @@ cell_queue_clear(cell_queue_t *queue) /** Extract and return the cell at the head of <b>queue</b>; return NULL if * <b>queue</b> is empty. */ -static INLINE packed_cell_t * +STATIC packed_cell_t * cell_queue_pop(cell_queue_t *queue) { - packed_cell_t *cell = queue->head; + packed_cell_t *cell = TOR_SIMPLEQ_FIRST(&queue->head); if (!cell) return NULL; - queue->head = cell->next; - if (cell == queue->tail) { - tor_assert(!queue->head); - queue->tail = NULL; - } + TOR_SIMPLEQ_REMOVE_HEAD(&queue->head, next); --queue->n; return cell; } @@ -2368,7 +2369,7 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) { circuitmux_t *cmux = NULL; int n_flushed = 0; - cell_queue_t *queue; + cell_queue_t *queue, *destroy_queue=NULL; circuit_t *circ; or_circuit_t *or_circ; int streams_blocked; @@ -2381,7 +2382,18 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) /* Main loop: pick a circuit, send a cell, update the cmux */ while (n_flushed < max) { - circ = circuitmux_get_first_active_circuit(cmux); + circ = circuitmux_get_first_active_circuit(cmux, &destroy_queue); + if (destroy_queue) { + /* this code is duplicated from some of the logic below. Ugly! XXXX */ + tor_assert(destroy_queue->n > 0); + cell = cell_queue_pop(destroy_queue); + channel_write_packed_cell(chan, cell); + /* Update the cmux destroy counter */ + circuitmux_notify_xmit_destroy(cmux); + cell = NULL; + ++n_flushed; + continue; + } /* If it returns NULL, no cells left to send */ if (!circ) break; assert_cmux_ok_paranoid(chan); @@ -2482,6 +2494,20 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max) return n_flushed; } +#if 0 +/** Indicate the current preferred cap for middle circuits; zero disables + * the cap. Right now it's just a constant, ORCIRC_MAX_MIDDLE_CELLS, but + * the logic in append_cell_to_circuit_queue() is written to be correct + * if we want to base it on a consensus param or something that might change + * in the future. + */ +static int +get_max_middle_cells(void) +{ + return ORCIRC_MAX_MIDDLE_CELLS; +} +#endif + /** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b> * transmitting in <b>direction</b>. */ void @@ -2492,6 +2518,9 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, or_circuit_t *orcirc = NULL; cell_queue_t *queue; int streams_blocked; +#if 0 + uint32_t tgt_max_middle_cells, p_len, n_len, tmp, hard_max_middle_cells; +#endif if (circ->marked_for_close) return; @@ -2513,28 +2542,81 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) { orcirc = TO_OR_CIRCUIT(circ); if (orcirc->p_chan) { - if (queue->n + 1 >= ORCIRC_MAX_MIDDLE_CELLS) { - /* Queueing this cell would put queue over the cap */ - log_warn(LD_CIRC, - "Got a cell exceeding the cap of %u in the %s direction " - "on middle circ ID %u on chan ID " U64_FORMAT - "; killing the circuit.", - ORCIRC_MAX_MIDDLE_CELLS, - (direction == CELL_DIRECTION_OUT) ? "n" : "p", - (direction == CELL_DIRECTION_OUT) ? - circ->n_circ_id : orcirc->p_circ_id, - U64_PRINTF_ARG( + /* We are a middle circuit if we have both n_chan and p_chan */ + /* We'll need to know the current preferred maximum */ + tgt_max_middle_cells = get_max_middle_cells(); + if (tgt_max_middle_cells > 0) { + /* Do we need to initialize middle_max_cells? */ + if (orcirc->max_middle_cells == 0) { + orcirc->max_middle_cells = tgt_max_middle_cells; + } else { + if (tgt_max_middle_cells > orcirc->max_middle_cells) { + /* If we want to increase the cap, we can do so right away */ + orcirc->max_middle_cells = tgt_max_middle_cells; + } else if (tgt_max_middle_cells < orcirc->max_middle_cells) { + /* + * If we're shrinking the cap, we can't shrink past either queue; + * compare tgt_max_middle_cells rather than tgt_max_middle_cells * + * ORCIRC_MAX_MIDDLE_KILL_THRESH so the queues don't shrink enough + * to generate spurious warnings, either. + */ + n_len = circ->n_chan_cells.n; + p_len = orcirc->p_chan_cells.n; + tmp = tgt_max_middle_cells; + if (tmp < n_len) tmp = n_len; + if (tmp < p_len) tmp = p_len; + orcirc->max_middle_cells = tmp; + } + /* else no change */ + } + } else { + /* tgt_max_middle_cells == 0 indicates we should disable the cap */ + orcirc->max_middle_cells = 0; + } + + /* Now we know orcirc->max_middle_cells is set correctly */ + if (orcirc->max_middle_cells > 0) { + hard_max_middle_cells = + (uint32_t)(((double)orcirc->max_middle_cells) * + ORCIRC_MAX_MIDDLE_KILL_THRESH); + + if ((unsigned)queue->n + 1 >= hard_max_middle_cells) { + /* Queueing this cell would put queue over the kill theshold */ + log_warn(LD_CIRC, + "Got a cell exceeding the hard cap of %u in the " + "%s direction on middle circ ID %u on chan ID " + U64_FORMAT "; killing the circuit.", + hard_max_middle_cells, + (direction == CELL_DIRECTION_OUT) ? "n" : "p", (direction == CELL_DIRECTION_OUT) ? - circ->n_chan->global_identifier : - orcirc->p_chan->global_identifier)); - circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); - return; + circ->n_circ_id : orcirc->p_circ_id, + U64_PRINTF_ARG( + (direction == CELL_DIRECTION_OUT) ? + circ->n_chan->global_identifier : + orcirc->p_chan->global_identifier)); + circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT); + return; + } else if ((unsigned)queue->n + 1 == orcirc->max_middle_cells) { + /* Only use ==, not >= for this test so we don't spam the log */ + log_warn(LD_CIRC, + "While trying to queue a cell, reached the soft cap of %u " + "in the %s direction on middle circ ID %u " + "on chan ID " U64_FORMAT ".", + orcirc->max_middle_cells, + (direction == CELL_DIRECTION_OUT) ? "n" : "p", + (direction == CELL_DIRECTION_OUT) ? + circ->n_circ_id : orcirc->p_circ_id, + U64_PRINTF_ARG( + (direction == CELL_DIRECTION_OUT) ? + circ->n_chan->global_identifier : + orcirc->p_chan->global_identifier)); + } } } } #endif - cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids); + cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids, 1); if (PREDICT_UNLIKELY(cell_queues_check_size())) { /* We ran the OOM handler */ diff --git a/src/or/relay.h b/src/or/relay.h index 1fef10a7da..e1b5e381ed 100644 --- a/src/or/relay.h +++ b/src/or/relay.h @@ -51,10 +51,11 @@ size_t packed_cell_mem_cost(void); /* For channeltls.c */ void packed_cell_free(packed_cell_t *cell); +void cell_queue_init(cell_queue_t *queue); void cell_queue_clear(cell_queue_t *queue); void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell); void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell, - int wide_circ_ids); + int wide_circ_ids, int use_stats); void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, @@ -75,11 +76,14 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); void stream_choice_seed_weak_rng(void); -#ifdef RELAY_PRIVATE int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t **layer_hint, char *recognized); -int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, + +#ifdef RELAY_PRIVATE +STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell, tor_addr_t *addr_out, int *ttl_out); +STATIC packed_cell_t *packed_cell_new(void); +STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue); #endif #endif diff --git a/src/or/rephist.c b/src/or/rephist.c index 55f321d5ff..c84322a679 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -2313,7 +2313,7 @@ rep_hist_format_exit_stats(time_t now) time_t rep_hist_exit_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_exit_stats_interval) return 0; /* Not initialized. */ @@ -2329,19 +2329,12 @@ rep_hist_exit_stats_write(time_t now) rep_hist_reset_exit_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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "exit-stats", str, "exit port statistics"); } - filename = get_datadir_fname2("stats", "exit-stats"); - if (write_str_to_file(filename, str, 0) < 0) - log_warn(LD_HIST, "Unable to write exit port statistics to disk!"); done: tor_free(str); - tor_free(statsdir); - tor_free(filename); return start_of_exit_stats_interval + WRITE_STATS_INTERVAL; } @@ -2598,7 +2591,7 @@ time_t rep_hist_buffer_stats_write(time_t now) { circuit_t *circ; - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_buffer_stats_interval) return 0; /* Not initialized. */ @@ -2617,19 +2610,12 @@ rep_hist_buffer_stats_write(time_t now) 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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "buffer-stats", str, "buffer statistics"); } - 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: tor_free(str); - tor_free(filename); - tor_free(statsdir); return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL; } @@ -2741,7 +2727,7 @@ rep_hist_format_desc_stats(time_t now) time_t rep_hist_desc_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *filename = NULL, *str = NULL; if (!start_of_served_descs_stats_interval) return 0; /* We're not collecting stats. */ @@ -2751,10 +2737,8 @@ rep_hist_desc_stats_write(time_t now) str = rep_hist_format_desc_stats(now); tor_assert(str != NULL); - 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; + if (check_or_create_data_subdir("stats") < 0) { + goto done; } filename = get_datadir_fname2("stats", "served-desc-stats"); if (append_bytes_to_file(filename, str, strlen(str), 0) < 0) @@ -2763,7 +2747,6 @@ rep_hist_desc_stats_write(time_t now) rep_hist_reset_desc_stats(now); done: - tor_free(statsdir); tor_free(filename); tor_free(str); return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL; @@ -2981,7 +2964,7 @@ rep_hist_format_conn_stats(time_t now) time_t rep_hist_conn_stats_write(time_t now) { - char *statsdir = NULL, *filename = NULL, *str = NULL; + char *str = NULL; if (!start_of_conn_stats_interval) return 0; /* Not initialized. */ @@ -2995,19 +2978,12 @@ rep_hist_conn_stats_write(time_t now) rep_hist_reset_conn_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; + if (!check_or_create_data_subdir("stats")) { + write_to_data_subdir("stats", "conn-stats", str, "connection statistics"); } - filename = get_datadir_fname2("stats", "conn-stats"); - if (write_str_to_file(filename, str, 0) < 0) - log_warn(LD_HIST, "Unable to write conn stats to disk!"); done: tor_free(str); - tor_free(filename); - tor_free(statsdir); return start_of_conn_stats_interval + WRITE_STATS_INTERVAL; } diff --git a/src/or/replaycache.c b/src/or/replaycache.c index 59b98489b7..122efb7030 100644 --- a/src/or/replaycache.c +++ b/src/or/replaycache.c @@ -63,7 +63,7 @@ replaycache_new(time_t horizon, time_t interval) /** See documentation for replaycache_add_and_test() */ -int +STATIC int replaycache_add_and_test_internal( time_t present, replaycache_t *r, const void *data, int len, time_t *elapsed) @@ -127,14 +127,13 @@ replaycache_add_and_test_internal( /** See documentation for replaycache_scrub_if_needed() */ -void +STATIC void replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r) { digestmap_iter_t *itr = NULL; const char *digest; void *valp; time_t *access_time; - char scrub_this; /* sanity check */ if (!r || !(r->digests_seen)) { @@ -152,20 +151,10 @@ replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r) /* okay, scrub time */ itr = digestmap_iter_init(r->digests_seen); while (!digestmap_iter_done(itr)) { - scrub_this = 0; digestmap_iter_get(itr, &digest, &valp); access_time = (time_t *)valp; - if (access_time) { - /* aged out yet? */ - if (*access_time < present - r->horizon) scrub_this = 1; - } else { - /* Buh? Get rid of it, anyway */ - log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL" - " entry in the digestmap."); - scrub_this = 1; - } - - if (scrub_this) { + /* aged out yet? */ + if (*access_time < present - r->horizon) { /* Advance the iterator and remove this one */ itr = digestmap_iter_next_rmv(r->digests_seen, itr); /* Free the value removed */ diff --git a/src/or/replaycache.h b/src/or/replaycache.h index de20cab627..c60c408103 100644 --- a/src/or/replaycache.h +++ b/src/or/replaycache.h @@ -45,10 +45,10 @@ replaycache_t * replaycache_new(time_t horizon, time_t interval); * testing. For everything else, use the wrappers below instead. */ -int replaycache_add_and_test_internal( +STATIC int replaycache_add_and_test_internal( time_t present, replaycache_t *r, const void *data, int len, time_t *elapsed); -void replaycache_scrub_if_needed_internal( +STATIC void replaycache_scrub_if_needed_internal( time_t present, replaycache_t *r); #endif /* REPLAYCACHE_PRIVATE */ diff --git a/src/or/router.c b/src/or/router.c index 6069da8f09..1063eda044 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -2249,7 +2249,7 @@ router_guess_address_from_dir_headers(uint32_t *guess) * string describing the version of Tor and the operating system we're * currently running on. */ -void +STATIC void get_platform_str(char *platform, size_t len) { tor_snprintf(platform, len, "Tor %s on %s", diff --git a/src/or/router.h b/src/or/router.h index 60095d087b..1079ec78c2 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -12,6 +12,8 @@ #ifndef TOR_ROUTER_H #define TOR_ROUTER_H +#include "testsupport.h" + crypto_pk_t *get_onion_key(void); time_t get_onion_key_set_at(void); void set_server_identity_key(crypto_pk_t *k); @@ -146,7 +148,7 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri); #ifdef ROUTER_PRIVATE /* Used only by router.c and test.c */ -void get_platform_str(char *platform, size_t len); +STATIC void get_platform_str(char *platform, size_t len); #endif #endif diff --git a/src/or/routerlist.c b/src/or/routerlist.c index c2220f4ca9..46da17e03b 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -629,9 +629,6 @@ authority_cert_dl_looks_uncertain(const char *id_digest) return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER; } -/** How many times will we try to fetch a certificate before giving up? */ -#define MAX_CERT_DL_FAILURES 8 - /** Try to download any v3 authority certificates that we may be missing. If * <b>status</b> is provided, try to get all the ones that were used to sign * <b>status</b>. Additionally, try to have a non-expired certificate for @@ -703,7 +700,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now) } SMARTLIST_FOREACH_END(cert); if (!found && download_status_is_ready(&(cl->dl_status_by_id), now, - MAX_CERT_DL_FAILURES) && + get_options()->TestingCertMaxDownloadTries) && !digestmap_get(pending_id, ds->v3_identity_digest)) { log_info(LD_DIR, "No current certificate known for authority %s " @@ -765,7 +762,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now) } if (download_status_is_ready_by_sk_in_cl( cl, sig->signing_key_digest, - now, MAX_CERT_DL_FAILURES) && + now, get_options()->TestingCertMaxDownloadTries) && !fp_pair_map_get_by_digests(pending_cert, voter->identity_digest, sig->signing_key_digest)) { @@ -1126,32 +1123,18 @@ router_rebuild_store(int flags, desc_store_t *store) static int router_reload_router_list_impl(desc_store_t *store) { - char *fname = NULL, *altname = NULL, *contents = NULL; + char *fname = NULL, *contents = NULL; struct stat st; - int read_from_old_location = 0; int extrainfo = (store->type == EXTRAINFO_STORE); - time_t now = time(NULL); store->journal_len = store->store_len = 0; fname = get_datadir_fname(store->fname_base); - if (store->fname_alt_base) - altname = get_datadir_fname(store->fname_alt_base); if (store->mmap) /* get rid of it first */ tor_munmap_file(store->mmap); store->mmap = NULL; store->mmap = tor_mmap_file(fname); - if (!store->mmap && altname && file_status(altname) == FN_FILE) { - read_from_old_location = 1; - log_notice(LD_DIR, "Couldn't read %s; trying to load routers from old " - "location %s.", fname, altname); - if ((store->mmap = tor_mmap_file(altname))) - read_from_old_location = 1; - } - if (altname && !read_from_old_location) { - remove_file_if_very_old(altname, now); - } if (store->mmap) { store->store_len = store->mmap->size; if (extrainfo) @@ -1168,14 +1151,6 @@ router_reload_router_list_impl(desc_store_t *store) fname = get_datadir_fname_suffix(store->fname_base, ".new"); if (file_status(fname) == FN_FILE) contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); - if (read_from_old_location) { - tor_free(altname); - altname = get_datadir_fname_suffix(store->fname_alt_base, ".new"); - if (!contents) - contents = read_file_to_str(altname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); - else - remove_file_if_very_old(altname, now); - } if (contents) { if (extrainfo) router_load_extrainfo_from_string(contents, NULL,SAVED_IN_JOURNAL, @@ -1188,9 +1163,8 @@ router_reload_router_list_impl(desc_store_t *store) } tor_free(fname); - tor_free(altname); - if (store->journal_len || read_from_old_location) { + if (store->journal_len) { /* Always clear the journal on startup.*/ router_rebuild_store(RRS_FORCE, store); } else if (!extrainfo) { @@ -1827,7 +1801,7 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router) * doubles, convert them to uint64_t, and try to scale them linearly so as to * much of the range of uint64_t. If <b>total_out</b> is provided, set it to * the sum of all elements in the array _before_ scaling. */ -/* private */ void +STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, uint64_t *total_out) { @@ -1870,7 +1844,7 @@ gt_i64_timei(uint64_t a, uint64_t b) * value, and return the index of that element. If all elements are 0, choose * an index at random. Return -1 on error. */ -/* private */ int +STATIC int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries) { int i, i_chosen=-1, n_chosen=0; @@ -2570,19 +2544,6 @@ router_is_named(const routerinfo_t *router) tor_memeq(digest, router->cache_info.identity_digest, DIGEST_LEN)); } -/** Return true iff the digest of <b>router</b>'s identity key, - * encoded in hexadecimal, matches <b>hexdigest</b> (which is - * optionally prefixed with a single dollar sign). Return false if - * <b>hexdigest</b> is malformed, or it doesn't match. */ -static INLINE int -router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest) -{ - return hex_digest_nickname_matches(hexdigest, - router->cache_info.identity_digest, - router->nickname, - router_is_named(router)); -} - /** Return true iff <b>digest</b> is the digest of the identity key of a * trusted directory matching at least one bit of <b>type</b>. If <b>type</b> * is zero, any authority is okay. */ @@ -2777,7 +2738,6 @@ router_get_routerlist(void) routerlist->extra_info_map = eimap_new(); routerlist->desc_store.fname_base = "cached-descriptors"; - routerlist->desc_store.fname_alt_base = "cached-routers"; routerlist->extrainfo_store.fname_base = "cached-extrainfo"; routerlist->desc_store.type = ROUTER_STORE; @@ -4487,12 +4447,8 @@ initiate_descriptor_downloads(const routerstatus_t *source, * try to split our requests into at least this many requests. */ #define MIN_REQUESTS 3 /** If we want fewer than this many descriptors, wait until we - * want more, or until MAX_CLIENT_INTERVAL_WITHOUT_REQUEST has - * passed. */ + * want more, or until TestingClientMaxIntervalWithoutRequest has passed. */ #define MAX_DL_TO_DELAY 16 -/** When directory clients have only a few servers to request, they batch - * them until they have more, or until this amount of time has passed. */ -#define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60) /** Given a <b>purpose</b> (FETCH_MICRODESC or FETCH_SERVERDESC) and a list of * router descriptor digests or microdescriptor digest256s in @@ -4524,7 +4480,7 @@ launch_descriptor_downloads(int purpose, should_delay = 0; } else { should_delay = (last_descriptor_download_attempted + - MAX_CLIENT_INTERVAL_WITHOUT_REQUEST) > now; + options->TestingClientMaxIntervalWithoutRequest) > now; if (!should_delay && n_downloadable) { if (last_descriptor_download_attempted) { log_info(LD_DIR, @@ -4797,7 +4753,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, continue; /* We have an in-progress download. */ } if (!download_status_is_ready(&rs->dl_status, now, - MAX_ROUTERDESC_DOWNLOAD_FAILURES)) { + options->TestingDescriptorMaxDownloadTries)) { ++n_delayed; /* Not ready for retry. */ continue; } @@ -4957,7 +4913,7 @@ update_extrainfo_downloads(time_t now) continue; } if (!download_status_is_ready(&sd->ei_dl_status, now, - MAX_ROUTERDESC_DOWNLOAD_FAILURES)) { + options->TestingDescriptorMaxDownloadTries)) { ++n_delay; continue; } diff --git a/src/or/routerlist.h b/src/or/routerlist.h index ce0f0f2e34..0162297ca7 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -11,6 +11,8 @@ #ifndef TOR_ROUTERLIST_H #define TOR_ROUTERLIST_H +#include "testsupport.h" + int get_n_authorities(dirinfo_type_t type); int trusted_dirs_reload_certs(void); @@ -206,9 +208,10 @@ typedef union u64_dbl_t { double dbl; } u64_dbl_t; -int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries); -void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, - uint64_t *total_out); +STATIC int choose_array_element_by_weight(const u64_dbl_t *entries, + int n_entries); +STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries, + uint64_t *total_out); #endif #endif diff --git a/src/or/statefile.c b/src/or/statefile.c index bcb7b07417..aac8850b16 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -117,8 +117,8 @@ static const config_format_t state_format = { static or_state_t *global_state = NULL; /** Return the persistent state struct for this Tor. */ -or_state_t * -get_or_state(void) +MOCK_IMPL(or_state_t *, +get_or_state, (void)) { tor_assert(global_state); return global_state; diff --git a/src/or/statefile.h b/src/or/statefile.h index dcdee6c604..762b0f5ee1 100644 --- a/src/or/statefile.h +++ b/src/or/statefile.h @@ -7,7 +7,7 @@ #ifndef TOR_STATEFILE_H #define TOR_STATEFILE_H -or_state_t *get_or_state(void); +MOCK_DECL(or_state_t *,get_or_state,(void)); int did_last_state_file_write_fail(void); int or_state_save(time_t now); diff --git a/src/or/transports.c b/src/or/transports.c index 3749d6bb21..62cc1a864f 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -95,18 +95,14 @@ #include "util.h" #include "router.h" #include "statefile.h" +#include "entrynodes.h" static process_environment_t * create_managed_proxy_environment(const managed_proxy_t *mp); static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); -static void managed_proxy_destroy(managed_proxy_t *mp, - int also_terminate_process); - static void handle_finished_proxy(managed_proxy_t *mp); -static int configure_proxy(managed_proxy_t *mp); - static void parse_method_error(const char *line, int is_server_method); #define parse_server_method_error(l) parse_method_error(l, 1) #define parse_client_method_error(l) parse_method_error(l, 0) @@ -136,7 +132,8 @@ static smartlist_t *transport_list = NULL; SOCKS version <b>socks_ver</b>. */ static transport_t * transport_new(const tor_addr_t *addr, uint16_t port, - const char *name, int socks_ver) + const char *name, int socks_ver, + const char *extra_info_args) { transport_t *t = tor_malloc_zero(sizeof(transport_t)); @@ -144,6 +141,8 @@ transport_new(const tor_addr_t *addr, uint16_t port, t->port = port; t->name = tor_strdup(name); t->socks_version = socks_ver; + if (extra_info_args) + t->extra_info_args = tor_strdup(extra_info_args); return t; } @@ -156,6 +155,7 @@ transport_free(transport_t *transport) return; tor_free(transport->name); + tor_free(transport->extra_info_args); tor_free(transport); } @@ -323,7 +323,7 @@ int transport_add_from_config(const tor_addr_t *addr, uint16_t port, const char *name, int socks_ver) { - transport_t *t = transport_new(addr, port, name, socks_ver); + transport_t *t = transport_new(addr, port, name, socks_ver, NULL); int r = transport_add(t); @@ -589,7 +589,7 @@ pt_configure_remaining_proxies(void) * Return 1 if the transport configuration finished, and return 0 * otherwise (if we still have more configuring to do for this * proxy). */ -static int +STATIC int configure_proxy(managed_proxy_t *mp) { int configuration_finished = 0; @@ -699,7 +699,7 @@ register_proxy(const managed_proxy_t *mp) } /** Free memory allocated by managed proxy <b>mp</b>. */ -static void +STATIC void managed_proxy_destroy(managed_proxy_t *mp, int also_terminate_process) { @@ -713,7 +713,8 @@ managed_proxy_destroy(managed_proxy_t *mp, smartlist_free(mp->transports_to_launch); /* remove it from the list of managed proxies */ - smartlist_remove(managed_proxy_list, mp); + if (managed_proxy_list) + smartlist_remove(managed_proxy_list, mp); /* free the argv */ free_execve_args(mp->argv); @@ -750,7 +751,6 @@ handle_finished_proxy(managed_proxy_t *mp) } unconfigured_proxies_n--; - tor_assert(unconfigured_proxies_n >= 0); } /** Return true if the configuration of the managed proxy <b>mp</b> is @@ -781,7 +781,7 @@ handle_methods_done(const managed_proxy_t *mp) /** Handle a configuration protocol <b>line</b> received from a * managed proxy <b>mp</b>. */ -void +STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp) { log_info(LD_GENERAL, "Got a line from managed proxy '%s': (%s)", @@ -882,7 +882,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp) } /** Parses an ENV-ERROR <b>line</b> and warns the user accordingly. */ -void +STATIC void parse_env_error(const char *line) { /* (Length of the protocol string) plus (a space) and (the first char of @@ -898,7 +898,7 @@ parse_env_error(const char *line) /** Handles a VERSION <b>line</b>. Updates the configuration protocol * version in <b>mp</b>. */ -int +STATIC int parse_version(const char *line, managed_proxy_t *mp) { if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) { @@ -939,14 +939,14 @@ parse_method_error(const char *line, int is_server) /** Parses an SMETHOD <b>line</b> and if well-formed it registers the * new transport in <b>mp</b>. */ -int +STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp) { int r; smartlist_t *items = NULL; char *method_name=NULL; - + char *args_string=NULL; char *addrport=NULL; tor_addr_t tor_addr; char *address=NULL; @@ -963,6 +963,9 @@ parse_smethod_line(const char *line, managed_proxy_t *mp) goto err; } + /* Example of legit SMETHOD line: + SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */ + tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD)); method_name = smartlist_get(items,1); @@ -990,7 +993,19 @@ parse_smethod_line(const char *line, managed_proxy_t *mp) goto err; } - transport = transport_new(&tor_addr, port, method_name, PROXY_NONE); + if (smartlist_len(items) > 3) { + /* Seems like there are also some [options] in the SMETHOD line. + Let's see if we can parse them. */ + char *options_string = smartlist_get(items, 3); + log_debug(LD_CONFIG, "Got options_string: %s", options_string); + if (!strcmpstart(options_string, "ARGS:")) { + args_string = options_string+strlen("ARGS:"); + log_debug(LD_CONFIG, "Got ARGS: %s", args_string); + } + } + + transport = transport_new(&tor_addr, port, method_name, + PROXY_NONE, args_string); if (!transport) goto err; @@ -1016,7 +1031,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp) /** Parses a CMETHOD <b>line</b>, and if well-formed it registers * the new transport in <b>mp</b>. */ -int +STATIC int parse_cmethod_line(const char *line, managed_proxy_t *mp) { int r; @@ -1082,7 +1097,7 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp) goto err; } - transport = transport_new(&tor_addr, port, method_name, socks_ver); + transport = transport_new(&tor_addr, port, method_name, socks_ver, NULL); if (!transport) goto err; @@ -1105,6 +1120,50 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp) return r; } +/** Return a newly allocated string that tor should place in + * TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server + * manged proxy in <b>mp</b>. Return NULL if no such options are found. */ +STATIC char * +get_transport_options_for_server_proxy(const managed_proxy_t *mp) +{ + char *options_string = NULL; + smartlist_t *string_sl = smartlist_new(); + + tor_assert(mp->is_server); + + /** Loop over the transports of the proxy. If we have options for + any of them, format them appropriately and place them in our + smartlist. Finally, join our smartlist to get the final + string. */ + SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, const char *, transport) { + smartlist_t *options_tmp_sl = NULL; + options_tmp_sl = get_options_for_server_transport(transport); + if (!options_tmp_sl) + continue; + + /** Loop over the options of this transport, escape them, and + place them in the smartlist. */ + SMARTLIST_FOREACH_BEGIN(options_tmp_sl, const char *, options) { + char *escaped_opts = tor_escape_str_for_pt_args(options, ":;\\"); + smartlist_add_asprintf(string_sl, "%s:%s", + transport, escaped_opts); + tor_free(escaped_opts); + } SMARTLIST_FOREACH_END(options); + + SMARTLIST_FOREACH(options_tmp_sl, char *, c, tor_free(c)); + smartlist_free(options_tmp_sl); + } SMARTLIST_FOREACH_END(transport); + + if (smartlist_len(string_sl)) { + options_string = smartlist_join_strings(string_sl, ";", 0, NULL); + } + + SMARTLIST_FOREACH(string_sl, char *, t, tor_free(t)); + smartlist_free(string_sl); + + return options_string; +} + /** Return the string that tor should place in TOR_PT_SERVER_BINDADDR * while configuring the server managed proxy in <b>mp</b>. The * string is stored in the heap, and it's the the responsibility of @@ -1186,6 +1245,16 @@ create_managed_proxy_environment(const managed_proxy_t *mp) tor_free(bindaddr_tmp); } + { + char *server_transport_options = + get_transport_options_for_server_proxy(mp); + if (server_transport_options) { + smartlist_add_asprintf(envs, "TOR_PT_SERVER_TRANSPORT_OPTIONS=%s", + server_transport_options); + tor_free(server_transport_options); + } + } + /* XXX024 Remove the '=' here once versions of obfsproxy which * assert that this env var exists are sufficiently dead. * @@ -1216,7 +1285,7 @@ create_managed_proxy_environment(const managed_proxy_t *mp) * <b>proxy_argv</b>. * * Requires that proxy_argv have at least one element. */ -static managed_proxy_t * +STATIC managed_proxy_t * managed_proxy_create(const smartlist_t *transport_list, char **proxy_argv, int is_server) { @@ -1390,6 +1459,8 @@ pt_get_extra_info_descriptor_string(void) tor_assert(mp->transports); SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) { + char *transport_args = NULL; + /* If the transport proxy returned "0.0.0.0" as its address, and * we know our external IP address, use it. Otherwise, use the * returned address. */ @@ -1405,9 +1476,16 @@ pt_get_extra_info_descriptor_string(void) addrport = fmt_addrport(&t->addr, t->port); } + /* If this transport has any arguments with it, prepend a space + to them so that we can add them to the transport line. */ + if (t->extra_info_args) + tor_asprintf(&transport_args, " %s", t->extra_info_args); + smartlist_add_asprintf(string_chunks, - "transport %s %s", - t->name, addrport); + "transport %s %s%s", + t->name, addrport, + transport_args ? transport_args : ""); + tor_free(transport_args); } SMARTLIST_FOREACH_END(t); } SMARTLIST_FOREACH_END(mp); @@ -1426,6 +1504,57 @@ pt_get_extra_info_descriptor_string(void) return the_string; } +/** Stringify the SOCKS arguments in <b>socks_args</b> according to + * 180_pluggable_transport.txt. The string is allocated on the heap + * and it's the responsibility of the caller to free it after use. */ +char * +pt_stringify_socks_args(const smartlist_t *socks_args) +{ + /* tmp place to store escaped socks arguments, so that we can + concatenate them up afterwards */ + smartlist_t *sl_tmp = NULL; + char *escaped_string = NULL; + char *new_string = NULL; + + tor_assert(socks_args); + tor_assert(smartlist_len(socks_args) > 0); + + sl_tmp = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(socks_args, const char *, s) { + /* Escape ';' and '\'. */ + escaped_string = tor_escape_str_for_pt_args(s, ";\\"); + if (!escaped_string) + goto done; + + smartlist_add(sl_tmp, escaped_string); + } SMARTLIST_FOREACH_END(s); + + new_string = smartlist_join_strings(sl_tmp, ";", 0, NULL); + + done: + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + + return new_string; +} + +/** Return a string of the SOCKS arguments that we should pass to the + * pluggable transports proxy in <b>addr</b>:<b>port</b> according to + * 180_pluggable_transport.txt. The string is allocated on the heap + * and it's the responsibility of the caller to free it after use. */ +char * +pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, uint16_t port) +{ + const smartlist_t *socks_args = NULL; + + socks_args = get_socks_args_by_bridge_addrport(addr, port); + if (!socks_args) + return NULL; + + return pt_stringify_socks_args(socks_args); +} + /** The tor config was read. * Destroy all managed proxies that were marked by a previous call to * prepare_proxy_list_for_config_read() and are not used by the new diff --git a/src/or/transports.h b/src/or/transports.h index 6ee82f4556..7b524f2073 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -25,6 +25,9 @@ typedef struct transport_t { /** Boolean: We are re-parsing our transport list, and we are going to remove * this one if we don't find it in the list of configured transports. */ unsigned marked_for_removal : 1; + /** Arguments for this transport that must be written to the + extra-info descriptor. */ + char *extra_info_args; } transport_t; void mark_transport_list(void); @@ -55,6 +58,10 @@ void pt_prepare_proxy_list_for_config_read(void); void sweep_proxy_list(void); smartlist_t *get_transport_proxy_ports(void); +char *pt_stringify_socks_args(const smartlist_t *socks_args); + +char *pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, + uint16_t port); #ifdef PT_PRIVATE /** State of the managed proxy configuration protocol. */ @@ -100,12 +107,21 @@ typedef struct { smartlist_t *transports; } managed_proxy_t; -int parse_cmethod_line(const char *line, managed_proxy_t *mp); -int parse_smethod_line(const char *line, managed_proxy_t *mp); +STATIC int parse_cmethod_line(const char *line, managed_proxy_t *mp); +STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp); + +STATIC int parse_version(const char *line, managed_proxy_t *mp); +STATIC void parse_env_error(const char *line); +STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp); +STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp); + +STATIC void managed_proxy_destroy(managed_proxy_t *mp, + int also_terminate_process); + +STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list, + char **proxy_argv, int is_server); -int parse_version(const char *line, managed_proxy_t *mp); -void parse_env_error(const char *line); -void handle_proxy_line(const char *line, managed_proxy_t *mp); +STATIC int configure_proxy(managed_proxy_t *mp); #endif diff --git a/src/test/bench.c b/src/test/bench.c index 5a8d21d173..ca01d3c3e6 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -15,7 +15,6 @@ const char tor_git_revision[] = ""; #include "orconfig.h" #define RELAY_PRIVATE -#define CONFIG_PRIVATE #include "or.h" #include "onion_tap.h" @@ -204,6 +203,7 @@ bench_onion_ntor(void) for (i = 0; i < iters; ++i) { onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os); ntor_handshake_state_free(state); + state = NULL; } end = perftime(); printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); diff --git a/src/test/include.am b/src/test/include.am index 112d1a79d8..fb704d7185 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -1,11 +1,15 @@ TESTS+= src/test/test -noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench +noinst_PROGRAMS+= src/test/bench +if UNITTESTS_ENABLED +noinst_PROGRAMS+= src/test/test src/test/test-child +endif src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ -DLOCALSTATEDIR="\"$(localstatedir)\"" \ -DBINDIR="\"$(bindir)\"" \ - -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" + -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \ + -DTOR_UNIT_TESTS # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on Windows, but I assure you that it @@ -15,18 +19,24 @@ src_test_test_SOURCES = \ src/test/test.c \ src/test/test_addr.c \ src/test/test_cell_formats.c \ + src/test/test_circuitlist.c \ + src/test/test_circuitmux.c \ src/test/test_containers.c \ src/test/test_crypto.c \ + src/test/test_cell_queue.c \ src/test/test_data.c \ src/test/test_dir.c \ src/test/test_introduce.c \ src/test/test_microdesc.c \ + src/test/test_options.c \ src/test/test_pt.c \ src/test/test_replay.c \ src/test/test_util.c \ src/test/test_config.c \ src/ext/tinytest.c +src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_bench_SOURCES = \ @@ -36,9 +46,9 @@ src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ @TOR_LDFLAGS_libevent@ -src_test_test_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-crypto.a $(LIBDONNA) \ - src/common/libor-event.a \ +src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \ + src/common/libor-crypto-testing.a $(LIBDONNA) \ + src/common/libor-event-testing.a \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ diff --git a/src/test/test-network.sh b/src/test/test-network.sh new file mode 100755 index 0000000000..9146ae3ce4 --- /dev/null +++ b/src/test/test-network.sh @@ -0,0 +1,25 @@ +#! /bin/sh + +# NOTE: Requires Chutney in $CHUTNEY_PATH. + +TOR_DIR=$(pwd)/src/or +NETWORK_FLAVOUR=basic +CHUTNEY_NETWORK=networks/$NETWORK_FLAVOUR +myname=$(basename $0) + +[ -d "$CHUTNEY_PATH" ] && [ -x "$CHUTNEY_PATH/chutney" ] || { + echo "$myname: missing 'chutney' in CHUTNEY_PATH ($CHUTNEY_PATH)" + exit 1 +} +cd "$CHUTNEY_PATH" +PATH=$TOR_DIR:$PATH # For picking up the right tor binary. +./tools/bootstrap-network.sh $NETWORK_FLAVOUR || exit 2 + +# Sleep some, waiting for the network to bootstrap. +# TODO: Add chutney command 'bootstrap-status' and use that instead. +BOOTSTRAP_TIME=18 +echo -n "$myname: sleeping for $BOOTSTRAP_TIME seconds" +n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do + sleep 1; n=$(expr $n - 1); echo -n . +done; echo "" +./chutney verify $CHUTNEY_NETWORK diff --git a/src/test/test.c b/src/test/test.c index 3ff39e6293..60fbfb132c 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -29,7 +29,6 @@ const char tor_git_revision[] = ""; /* These macros pull in declarations for some functions and structures that * are typically file-private. */ #define BUFFERS_PRIVATE -#define CONFIG_PRIVATE #define GEOIP_PRIVATE #define ROUTER_PRIVATE #define CIRCUITSTATS_PRIVATE @@ -840,43 +839,130 @@ test_onion_handshake(void) crypto_dh_t *c_dh = NULL; char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char c_keys[40]; - /* server-side */ char s_buf[TAP_ONIONSKIN_REPLY_LEN]; char s_keys[40]; - + int i; /* shared */ - crypto_pk_t *pk = NULL; + crypto_pk_t *pk = NULL, *pk2 = NULL; pk = pk_generate(0); + pk2 = pk_generate(1); /* client handshake 1. */ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); - /* server handshake */ - memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); - memset(s_keys, 0, 40); - test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL, - s_buf, s_keys, 40)); + for (i = 1; i <= 3; ++i) { + crypto_pk_t *k1, *k2; + if (i==1) { + /* server handshake: only one key known. */ + k1 = pk; k2 = NULL; + } else if (i==2) { + /* server handshake: try the right key first. */ + k1 = pk; k2 = pk2; + } else { + /* server handshake: try the right key second. */ + k1 = pk2; k2 = pk; + } - /* client handshake 2 */ - memset(c_keys, 0, 40); - test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); + memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); + memset(s_keys, 0, 40); + test_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2, + s_buf, s_keys, 40)); - if (memcmp(c_keys, s_keys, 40)) { - puts("Aiiiie"); - exit(1); + /* client handshake 2 */ + memset(c_keys, 0, 40); + test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); + + test_memeq(c_keys, s_keys, 40); + memset(s_buf, 0, 40); + test_memneq(c_keys, s_buf, 40); } - test_memeq(c_keys, s_keys, 40); - memset(s_buf, 0, 40); - test_memneq(c_keys, s_buf, 40); + done: + crypto_dh_free(c_dh); + crypto_pk_free(pk); + crypto_pk_free(pk2); +} + +static void +test_bad_onion_handshake(void *arg) +{ + char junk_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; + char junk_buf2[TAP_ONIONSKIN_CHALLENGE_LEN]; + /* client-side */ + crypto_dh_t *c_dh = NULL; + char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; + char c_keys[40]; + /* server-side */ + char s_buf[TAP_ONIONSKIN_REPLY_LEN]; + char s_keys[40]; + /* shared */ + crypto_pk_t *pk = NULL, *pk2 = NULL; + + (void)arg; + + pk = pk_generate(0); + pk2 = pk_generate(1); + + /* Server: Case 1: the encrypted data is degenerate. */ + memset(junk_buf, 0, sizeof(junk_buf)); + crypto_pk_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN, + junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1); + tt_int_op(-1, ==, + onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, + s_buf, s_keys, 40)); + + /* Server: Case 2: the encrypted data is not long enough. */ + memset(junk_buf, 0, sizeof(junk_buf)); + memset(junk_buf2, 0, sizeof(junk_buf2)); + crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2), + junk_buf, 48, PK_PKCS1_OAEP_PADDING); + tt_int_op(-1, ==, + onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, + s_buf, s_keys, 40)); + + /* client handshake 1: do it straight. */ + memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); + test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); + + /* Server: Case 3: we just don't have the right key. */ + tt_int_op(-1, ==, + onion_skin_TAP_server_handshake(c_buf, pk2, NULL, + s_buf, s_keys, 40)); + + /* Server: Case 4: The RSA-encrypted portion is corrupt. */ + c_buf[64] ^= 33; + tt_int_op(-1, ==, + onion_skin_TAP_server_handshake(c_buf, pk, NULL, + s_buf, s_keys, 40)); + c_buf[64] ^= 33; + + /* (Let the server procede) */ + tt_int_op(0, ==, + onion_skin_TAP_server_handshake(c_buf, pk, NULL, + s_buf, s_keys, 40)); + + /* Client: Case 1: The server sent back junk. */ + s_buf[64] ^= 33; + tt_int_op(-1, ==, + onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); + s_buf[64] ^= 33; + + /* Let the client finish; make sure it can. */ + tt_int_op(0, ==, + onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); + test_memeq(s_keys, c_keys, 40); + + /* Client: Case 2: The server sent back a degenerate DH. */ + memset(s_buf, 0, sizeof(s_buf)); + tt_int_op(-1, ==, + onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40)); done: - if (c_dh) - crypto_dh_free(c_dh); - if (pk) - crypto_pk_free(pk); + crypto_dh_free(c_dh); + crypto_pk_free(pk); + crypto_pk_free(pk2); } #ifdef CURVE25519_ENABLED @@ -2005,6 +2091,7 @@ static struct testcase_t test_array[] = { ENT(buffers), { "buffer_copy", test_buffer_copy, 0, NULL, NULL }, ENT(onion_handshake), + { "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL }, #ifdef CURVE25519_ENABLED { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, #endif @@ -2045,6 +2132,10 @@ extern struct testcase_t config_tests[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t replaycache_tests[]; extern struct testcase_t cell_format_tests[]; +extern struct testcase_t circuitlist_tests[]; +extern struct testcase_t circuitmux_tests[]; +extern struct testcase_t cell_queue_tests[]; +extern struct testcase_t options_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -2054,12 +2145,16 @@ static struct testgroup_t testgroups[] = { { "container/", container_tests }, { "util/", util_tests }, { "cellfmt/", cell_format_tests }, + { "cellqueue/", cell_queue_tests }, { "dir/", dir_tests }, { "dir/md/", microdesc_tests }, { "pt/", pt_tests }, { "config/", config_tests }, { "replaycache/", replaycache_tests }, { "introduce/", introduce_tests }, + { "circuitlist/", circuitlist_tests }, + { "circuitmux/", circuitmux_tests }, + { "options/", options_tests }, END_OF_GROUPS }; diff --git a/src/test/test_addr.c b/src/test/test_addr.c index fec85a4696..4bc602df84 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -44,6 +44,10 @@ test_addr_basic(void) test_eq(u32, 0x7f000001u); test_eq(u16, 0); tor_free(cp); + + test_assert(addr_port_lookup(LOG_WARN, "localhost:3", &cp, &u32, NULL)); + tor_free(cp); + test_eq(0, addr_mask_get_bits(0x0u)); test_eq(32, addr_mask_get_bits(0xFFFFFFFFu)); test_eq(16, addr_mask_get_bits(0xFFFF0000u)); @@ -217,11 +221,12 @@ test_addr_ip6_helpers(void) /* ==== Converting to and from sockaddr_t. */ sin = (struct sockaddr_in *)&sa_storage; sin->sin_family = AF_INET; - sin->sin_port = 9090; + sin->sin_port = htons(9090); sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/ - tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL); + tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, &port1); test_eq(tor_addr_family(&t1), AF_INET); test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102); + tt_int_op(port1, ==, 9090); memset(&sa_storage, 0, sizeof(sa_storage)); test_eq(sizeof(struct sockaddr_in), @@ -235,8 +240,9 @@ test_addr_ip6_helpers(void) sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(7070); sin6->sin6_addr.s6_addr[0] = 128; - tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL); + tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, &port1); test_eq(tor_addr_family(&t1), AF_INET6); + tt_int_op(port1, ==, 7070); p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0); test_streq(p1, "8000::"); @@ -464,6 +470,9 @@ test_addr_ip6_helpers(void) test_eq(0, i); i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1); test_eq(0, i); + i = tor_addr_parse_PTR_name(&t1, "9999999999999999999999999999.in-addr.arpa", + AF_UNSPEC, 1); + test_eq(-1, i); i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa", AF_UNSPEC, 1); test_eq(1, i); @@ -844,6 +853,90 @@ test_virtaddrmap(void *data) } static void +test_addr_localname(void *arg) +{ + (void)arg; + tt_assert(tor_addr_hostname_is_local("localhost")); + tt_assert(tor_addr_hostname_is_local("LOCALHOST")); + tt_assert(tor_addr_hostname_is_local("LocalHost")); + tt_assert(tor_addr_hostname_is_local("local")); + tt_assert(tor_addr_hostname_is_local("LOCAL")); + tt_assert(tor_addr_hostname_is_local("here.now.local")); + tt_assert(tor_addr_hostname_is_local("here.now.LOCAL")); + + tt_assert(!tor_addr_hostname_is_local(" localhost")); + tt_assert(!tor_addr_hostname_is_local("www.torproject.org")); + done: + ; +} + +static void +test_addr_dup_ip(void *arg) +{ + char *v = NULL; + (void)arg; +#define CHECK(ip, s) do { \ + v = tor_dup_ip(ip); \ + tt_str_op(v,==,(s)); \ + tor_free(v); \ + } while (0) + + CHECK(0xffffffff, "255.255.255.255"); + CHECK(0x00000000, "0.0.0.0"); + CHECK(0x7f000001, "127.0.0.1"); + CHECK(0x01020304, "1.2.3.4"); + +#undef CHECK + done: + tor_free(v); +} + +static void +test_addr_sockaddr_to_str(void *arg) +{ + char *v = NULL; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr_storage ss; +#ifdef HAVE_SYS_UN_H + struct sockaddr_un sun; +#endif +#define CHECK(sa, s) do { \ + v = tor_sockaddr_to_str((const struct sockaddr*) &(sa)); \ + tt_str_op(v,==,(s)); \ + tor_free(v); \ + } while (0) + (void)arg; + + memset(&ss,0,sizeof(ss)); + ss.ss_family = AF_UNSPEC; + CHECK(ss, "unspec"); + + memset(&sin,0,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(0x7f808001); + sin.sin_port = htons(1234); + CHECK(sin, "127.128.128.1:1234"); + +#ifdef HAVE_SYS_UN_H + memset(&sun,0,sizeof(sun)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, "/here/is/a/path", sizeof(sun.sun_path)); + CHECK(sun, "unix:/here/is/a/path"); +#endif + + memset(&sin6,0,sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, "\x20\x00\x00\x00\x00\x00\x00\x00" + "\x00\x1a\x2b\x3c\x4d\x5e\x00\x01", 16); + sin6.sin6_port = htons(1234); + CHECK(sin6, "[2000::1a:2b3c:4d5e:1]:1234"); + + done: + tor_free(v); +} + +static void test_addr_is_loopback(void *data) { static const struct loopback_item { @@ -886,6 +979,9 @@ struct testcase_t addr_tests[] = { ADDR_LEGACY(ip6_helpers), ADDR_LEGACY(parse), { "virtaddr", test_virtaddrmap, 0, NULL, NULL }, + { "localname", test_addr_localname, 0, NULL, NULL }, + { "dup_ip", test_addr_dup_ip, 0, NULL, NULL }, + { "sockaddr_to_str", test_addr_sockaddr_to_str, 0, NULL, NULL }, { "is_loopback", test_addr_is_loopback, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c new file mode 100644 index 0000000000..cf2d11ad5d --- /dev/null +++ b/src/test/test_cell_queue.c @@ -0,0 +1,146 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CIRCUITLIST_PRIVATE +#define RELAY_PRIVATE +#include "or.h" +#include "circuitlist.h" +#include "relay.h" +#include "test.h" + +static void +test_cq_manip(void *arg) +{ + packed_cell_t *pc1=NULL, *pc2=NULL, *pc3=NULL, *pc4=NULL, *pc_tmp=NULL; + cell_queue_t cq; + cell_t cell; + (void) arg; + + init_cell_pool(); + cell_queue_init(&cq); + tt_int_op(cq.n, ==, 0); + + pc1 = packed_cell_new(); + pc2 = packed_cell_new(); + pc3 = packed_cell_new(); + pc4 = packed_cell_new(); + tt_assert(pc1 && pc2 && pc3 && pc4); + + tt_ptr_op(NULL, ==, cell_queue_pop(&cq)); + + /* Add and remove a singleton. */ + cell_queue_append(&cq, pc1); + tt_int_op(cq.n, ==, 1); + tt_ptr_op(pc1, ==, cell_queue_pop(&cq)); + tt_int_op(cq.n, ==, 0); + + /* Add and remove four items */ + cell_queue_append(&cq, pc4); + cell_queue_append(&cq, pc3); + cell_queue_append(&cq, pc2); + cell_queue_append(&cq, pc1); + tt_int_op(cq.n, ==, 4); + tt_ptr_op(pc4, ==, cell_queue_pop(&cq)); + tt_ptr_op(pc3, ==, cell_queue_pop(&cq)); + tt_ptr_op(pc2, ==, cell_queue_pop(&cq)); + tt_ptr_op(pc1, ==, cell_queue_pop(&cq)); + tt_int_op(cq.n, ==, 0); + tt_ptr_op(NULL, ==, cell_queue_pop(&cq)); + + /* Try a packed copy (wide, then narrow, which is a bit of a cheat, since a + * real cell queue has only one type.) */ + memset(&cell, 0, sizeof(cell)); + cell.circ_id = 0x12345678; + cell.command = 10; + strlcpy((char*)cell.payload, "Lorax ipsum gruvvulus thneed amet, snergelly " + "once-ler lerkim, sed do barbaloot tempor gluppitus ut labore et " + "truffula magna aliqua.", + sizeof(cell.payload)); + cell_queue_append_packed_copy(&cq, &cell, 1 /*wide*/, 0 /*stats*/); + cell.circ_id = 0x2013; + cell_queue_append_packed_copy(&cq, &cell, 0 /*wide*/, 0 /*stats*/); + tt_int_op(cq.n, ==, 2); + + pc_tmp = cell_queue_pop(&cq); + tt_int_op(cq.n, ==, 1); + tt_ptr_op(pc_tmp, !=, NULL); + test_mem_op(pc_tmp->body, ==, "\x12\x34\x56\x78\x0a", 5); + test_mem_op(pc_tmp->body+5, ==, cell.payload, sizeof(cell.payload)); + packed_cell_free(pc_tmp); + + pc_tmp = cell_queue_pop(&cq); + tt_int_op(cq.n, ==, 0); + tt_ptr_op(pc_tmp, !=, NULL); + test_mem_op(pc_tmp->body, ==, "\x20\x13\x0a", 3); + test_mem_op(pc_tmp->body+3, ==, cell.payload, sizeof(cell.payload)); + packed_cell_free(pc_tmp); + pc_tmp = NULL; + + tt_ptr_op(NULL, ==, cell_queue_pop(&cq)); + + /* Now make sure cell_queue_clear works. */ + cell_queue_append(&cq, pc2); + cell_queue_append(&cq, pc1); + tt_int_op(cq.n, ==, 2); + cell_queue_clear(&cq); + pc2 = pc1 = NULL; /* prevent double-free */ + tt_int_op(cq.n, ==, 0); + + done: + packed_cell_free(pc1); + packed_cell_free(pc2); + packed_cell_free(pc3); + packed_cell_free(pc4); + packed_cell_free(pc_tmp); + + cell_queue_clear(&cq); + free_cell_pool(); +} + +static void +test_circuit_n_cells(void *arg) +{ + packed_cell_t *pc1=NULL, *pc2=NULL, *pc3=NULL, *pc4=NULL, *pc5=NULL; + origin_circuit_t *origin_c=NULL; + or_circuit_t *or_c=NULL; + + (void)arg; + + init_cell_pool(); + + pc1 = packed_cell_new(); + pc2 = packed_cell_new(); + pc3 = packed_cell_new(); + pc4 = packed_cell_new(); + pc5 = packed_cell_new(); + tt_assert(pc1 && pc2 && pc3 && pc4 && pc5); + + or_c = or_circuit_new(0, NULL); + origin_c = origin_circuit_new(); + origin_c->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL; + + tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 0); + cell_queue_append(&or_c->p_chan_cells, pc1); + tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 1); + cell_queue_append(&or_c->base_.n_chan_cells, pc2); + cell_queue_append(&or_c->base_.n_chan_cells, pc3); + tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 3); + + tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 0); + cell_queue_append(&origin_c->base_.n_chan_cells, pc4); + cell_queue_append(&origin_c->base_.n_chan_cells, pc5); + tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 2); + + done: + circuit_free(TO_CIRCUIT(or_c)); + circuit_free(TO_CIRCUIT(origin_c)); + + free_cell_pool(); +} + +struct testcase_t cell_queue_tests[] = { + { "basic", test_cq_manip, TT_FORK, NULL, NULL, }, + { "circ_n_cells", test_circuit_n_cells, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c new file mode 100644 index 0000000000..720b407659 --- /dev/null +++ b/src/test/test_circuitlist.c @@ -0,0 +1,168 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define TOR_CHANNEL_INTERNAL_ +#define CIRCUITLIST_PRIVATE +#include "or.h" +#include "channel.h" +#include "circuitlist.h" +#include "test.h" + +static channel_t * +new_fake_channel(void) +{ + channel_t *chan = tor_malloc_zero(sizeof(channel_t)); + channel_init(chan); + return chan; +} + +static struct { + int ncalls; + void *cmux; + void *circ; + cell_direction_t dir; +} cam; + +static void +circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ, + cell_direction_t dir) +{ + ++cam.ncalls; + cam.cmux = cmux; + cam.circ = circ; + cam.dir = dir; +} + +static struct { + int ncalls; + void *cmux; + void *circ; +} cdm; + +static void +circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ) +{ + ++cdm.ncalls; + cdm.cmux = cmux; + cdm.circ = circ; +} + +#define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \ + tt_int_op(cam.ncalls, ==, 1); \ + tt_ptr_op(cam.cmux, ==, (mux_)); \ + tt_ptr_op(cam.circ, ==, (circ_)); \ + tt_ptr_op(cam.dir, ==, (dir_)); \ + memset(&cam, 0, sizeof(cam)); \ + } while (0) + +#define GOT_CMUX_DETACH(mux_, circ_) do { \ + tt_int_op(cdm.ncalls, ==, 1); \ + tt_ptr_op(cdm.cmux, ==, (mux_)); \ + tt_ptr_op(cdm.circ, ==, (circ_)); \ + memset(&cdm, 0, sizeof(cdm)); \ + } while (0) + +static void +test_clist_maps(void *arg) +{ + channel_t *ch1 = new_fake_channel(); + channel_t *ch2 = new_fake_channel(); + channel_t *ch3 = new_fake_channel(); + or_circuit_t *or_c1=NULL, *or_c2=NULL; + + (void) arg; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_mock); + MOCK(circuitmux_detach_circuit, circuitmux_detach_mock); + memset(&cam, 0, sizeof(cam)); + memset(&cdm, 0, sizeof(cdm)); + + ch1->cmux = (void*)0x1001; + ch2->cmux = (void*)0x1002; + ch3->cmux = (void*)0x1003; + + or_c1 = or_circuit_new(100, ch2); + tt_assert(or_c1); + GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN); + tt_int_op(or_c1->p_circ_id, ==, 100); + tt_ptr_op(or_c1->p_chan, ==, ch2); + + or_c2 = or_circuit_new(100, ch1); + tt_assert(or_c2); + GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN); + tt_int_op(or_c2->p_circ_id, ==, 100); + tt_ptr_op(or_c2->p_chan, ==, ch1); + + circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1); + GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT); + + circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2); + GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT); + + tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1)); + tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2)); + tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1)); + /* Try the same thing again, to test the "fast" path. */ + tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1)); + tt_assert(circuit_id_in_use_on_channel(100, ch2)); + tt_assert(! circuit_id_in_use_on_channel(101, ch2)); + + /* Try changing the circuitid and channel of that circuit. */ + circuit_set_p_circid_chan(or_c1, 500, ch3); + GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1)); + GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN); + tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL); + tt_assert(! circuit_id_in_use_on_channel(100, ch2)); + tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1)); + + /* Now let's see about destroy handling. */ + tt_assert(! circuit_id_in_use_on_channel(205, ch2)); + tt_assert(circuit_id_in_use_on_channel(200, ch2)); + channel_note_destroy_pending(ch2, 200); + channel_note_destroy_pending(ch2, 205); + channel_note_destroy_pending(ch1, 100); + tt_assert(circuit_id_in_use_on_channel(205, ch2)) + tt_assert(circuit_id_in_use_on_channel(200, ch2)); + tt_assert(circuit_id_in_use_on_channel(100, ch1)); + + tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0); + tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2)); + tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2)); + + /* Okay, now free ch2 and make sure that the circuit ID is STILL not + * usable, because we haven't declared the destroy to be nonpending */ + tt_int_op(cdm.ncalls, ==, 0); + circuit_free(TO_CIRCUIT(or_c2)); + or_c2 = NULL; /* prevent free */ + tt_int_op(cdm.ncalls, ==, 2); + memset(&cdm, 0, sizeof(cdm)); + tt_assert(circuit_id_in_use_on_channel(200, ch2)); + tt_assert(circuit_id_in_use_on_channel(100, ch1)); + tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL); + tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL); + + /* Now say that the destroy is nonpending */ + channel_note_destroy_not_pending(ch2, 200); + tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL); + channel_note_destroy_not_pending(ch1, 100); + tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL); + tt_assert(! circuit_id_in_use_on_channel(200, ch2)); + tt_assert(! circuit_id_in_use_on_channel(100, ch1)); + + done: + tor_free(ch1); + tor_free(ch2); + tor_free(ch3); + if (or_c1) + circuit_free(TO_CIRCUIT(or_c1)); + if (or_c2) + circuit_free(TO_CIRCUIT(or_c2)); + UNMOCK(circuitmux_attach_circuit); + UNMOCK(circuitmux_detach_circuit); +} + +struct testcase_t circuitlist_tests[] = { + { "maps", test_clist_maps, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c new file mode 100644 index 0000000000..0f592001cb --- /dev/null +++ b/src/test/test_circuitmux.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define TOR_CHANNEL_INTERNAL_ +#define CIRCUITMUX_PRIVATE +#define RELAY_PRIVATE +#include "or.h" +#include "channel.h" +#include "circuitmux.h" +#include "relay.h" +#include "test.h" + +/* XXXX duplicated function from test_circuitlist.c */ +static channel_t * +new_fake_channel(void) +{ + channel_t *chan = tor_malloc_zero(sizeof(channel_t)); + channel_init(chan); + return chan; +} + +static int +has_queued_writes(channel_t *c) +{ + (void) c; + return 1; +} + +/** Test destroy cell queue with no interference from other queues. */ +static void +test_cmux_destroy_cell_queue(void *arg) +{ + circuitmux_t *cmux = NULL; + channel_t *ch = NULL; + circuit_t *circ = NULL; + cell_queue_t *cq = NULL; + packed_cell_t *pc = NULL; + + init_cell_pool(); + (void) arg; + + cmux = circuitmux_alloc(); + tt_assert(cmux); + ch = new_fake_channel(); + ch->has_queued_writes = has_queued_writes; + ch->wide_circ_ids = 1; + + circ = circuitmux_get_first_active_circuit(cmux, &cq); + tt_assert(!circ); + tt_assert(!cq); + + circuitmux_append_destroy_cell(ch, cmux, 100, 10); + circuitmux_append_destroy_cell(ch, cmux, 190, 6); + circuitmux_append_destroy_cell(ch, cmux, 30, 1); + + tt_int_op(circuitmux_num_cells(cmux), ==, 3); + + circ = circuitmux_get_first_active_circuit(cmux, &cq); + tt_assert(!circ); + tt_assert(cq); + + tt_int_op(cq->n, ==, 3); + + pc = cell_queue_pop(cq); + tt_assert(pc); + test_mem_op(pc->body, ==, "\x00\x00\x00\x64\x04\x0a\x00\x00\x00", 9); + packed_cell_free(pc); + pc = NULL; + + tt_int_op(circuitmux_num_cells(cmux), ==, 2); + + done: + circuitmux_free(cmux); + channel_free(ch); + packed_cell_free(pc); + + free_cell_pool(); +} + +struct testcase_t circuitmux_tests[] = { + { "destroy_cell_queue", test_cmux_destroy_cell_queue, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_config.c b/src/test/test_config.c index e20fe73295..3848d352d5 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -10,6 +10,8 @@ #include "confparse.h" #include "connection_edge.h" #include "test.h" +#include "util.h" +#include "address.h" static void test_config_addressmap(void *arg) @@ -169,11 +171,353 @@ test_config_addressmap(void *arg) ; } +static int +is_private_dir(const char* path) +{ + struct stat st; + int r = stat(path, &st); + if (r) { + return 0; + } +#if !defined (_WIN32) || defined (WINCE) + if ((st.st_mode & (S_IFDIR | 0777)) != (S_IFDIR | 0700)) { + return 0; + } +#endif + return 1; +} + +static void +test_config_check_or_create_data_subdir(void *arg) +{ + or_options_t *options = get_options_mutable(); + char *datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0")); + const char *subdir = "test_stats"; + char *subpath = get_datadir_fname(subdir); + struct stat st; + int r; +#if !defined (_WIN32) || defined (WINCE) + unsigned group_permission; +#endif + (void)arg; + +#if defined (_WIN32) && !defined (WINCE) + tt_int_op(mkdir(options->DataDirectory), ==, 0); +#else + tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0); +#endif + + r = stat(subpath, &st); + + // The subdirectory shouldn't exist yet, + // but should be created by the call to check_or_create_data_subdir. + test_assert(r && (errno == ENOENT)); + test_assert(!check_or_create_data_subdir(subdir)); + test_assert(is_private_dir(subpath)); + + // The check should return 0, if the directory already exists + // and is private to the user. + test_assert(!check_or_create_data_subdir(subdir)); + +#if !defined (_WIN32) || defined (WINCE) + group_permission = st.st_mode | 0070; + r = chmod(subpath, group_permission); + + if (r) { + test_fail_msg("Changing permissions for the subdirectory failed."); + } + + // If the directory exists, but its mode is too permissive + // a call to check_or_create_data_subdir should reset the mode. + test_assert(!is_private_dir(subpath)); + test_assert(!check_or_create_data_subdir(subdir)); + test_assert(is_private_dir(subpath)); +#endif + + done: + rmdir(subpath); + tor_free(datadir); + tor_free(subpath); +} + +static void +test_config_write_to_data_subdir(void *arg) +{ + or_options_t* options = get_options_mutable(); + char *datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1")); + const char* subdir = "test_stats"; + const char* fname = "test_file"; + const char* str = + "Lorem ipsum dolor sit amet, consetetur sadipscing\n" + "elitr, sed diam nonumy eirmod\n" + "tempor invidunt ut labore et dolore magna aliquyam\n" + "erat, sed diam voluptua.\n" + "At vero eos et accusam et justo duo dolores et ea\n" + "rebum. Stet clita kasd gubergren,\n" + "no sea takimata sanctus est Lorem ipsum dolor sit amet.\n" + "Lorem ipsum dolor sit amet,\n" + "consetetur sadipscing elitr, sed diam nonumy eirmod\n" + "tempor invidunt ut labore et dolore\n" + "magna aliquyam erat, sed diam voluptua. At vero eos et\n" + "accusam et justo duo dolores et\n" + "ea rebum. Stet clita kasd gubergren, no sea takimata\n" + "sanctus est Lorem ipsum dolor sit amet."; + char* filepath = get_datadir_fname2(subdir, fname); + (void)arg; + +#if defined (_WIN32) && !defined (WINCE) + tt_int_op(mkdir(options->DataDirectory), ==, 0); +#else + tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0); +#endif + + // Write attempt shoudl fail, if subdirectory doesn't exist. + test_assert(write_to_data_subdir(subdir, fname, str, NULL)); + test_assert(! check_or_create_data_subdir(subdir)); + + // Content of file after write attempt should be + // equal to the original string. + test_assert(!write_to_data_subdir(subdir, fname, str, NULL)); + test_streq(read_file_to_str(filepath, 0, NULL), str); + + // A second write operation should overwrite the old content. + test_assert(!write_to_data_subdir(subdir, fname, str, NULL)); + test_streq(read_file_to_str(filepath, 0, NULL), str); + + done: + (void) unlink(filepath); + rmdir(options->DataDirectory); + tor_free(datadir); + tor_free(filepath); +} + +/* Test helper function: Make sure that a bridge line gets parsed + * properly. Also make sure that the resulting bridge_line_t structure + * has its fields set correctly. */ +static void +good_bridge_line_test(const char *string, const char *test_addrport, + const char *test_digest, const char *test_transport, + const smartlist_t *test_socks_args) +{ + char *tmp = NULL; + bridge_line_t *bridge_line = parse_bridge_line(string); + test_assert(bridge_line); + + /* test addrport */ + tmp = tor_strdup(fmt_addrport(&bridge_line->addr, bridge_line->port)); + test_streq(test_addrport, tmp); + tor_free(tmp); + + /* If we were asked to validate a digest, but we did not get a + digest after parsing, we failed. */ + if (test_digest && tor_digest_is_zero(bridge_line->digest)) + test_assert(0); + + /* If we were not asked to validate a digest, and we got a digest + after parsing, we failed again. */ + if (!test_digest && !tor_digest_is_zero(bridge_line->digest)) + test_assert(0); + + /* If we were asked to validate a digest, and we got a digest after + parsing, make sure it's correct. */ + if (test_digest) { + tmp = tor_strdup(hex_str(bridge_line->digest, DIGEST_LEN)); + tor_strlower(tmp); + test_streq(test_digest, tmp); + tor_free(tmp); + } + + /* If we were asked to validate a transport name, make sure tha it + matches with the transport name that was parsed. */ + if (test_transport && !bridge_line->transport_name) + test_assert(0); + if (!test_transport && bridge_line->transport_name) + test_assert(0); + if (test_transport) + test_streq(test_transport, bridge_line->transport_name); + + /* Validate the SOCKS argument smartlist. */ + if (test_socks_args && !bridge_line->socks_args) + test_assert(0); + if (!test_socks_args && bridge_line->socks_args) + test_assert(0); + if (test_socks_args) + test_assert(smartlist_strings_eq(test_socks_args, + bridge_line->socks_args)); + + done: + tor_free(tmp); + bridge_line_free(bridge_line); +} + +/* Test helper function: Make sure that a bridge line is + * unparseable. */ +static void +bad_bridge_line_test(const char *string) +{ + bridge_line_t *bridge_line = parse_bridge_line(string); + test_assert(!bridge_line); + + done: + bridge_line_free(bridge_line); +} + +static void +test_config_parse_bridge_line(void *arg) +{ + (void) arg; + good_bridge_line_test("192.0.2.1:4123", + "192.0.2.1:4123", NULL, NULL, NULL); + + good_bridge_line_test("192.0.2.1", + "192.0.2.1:443", NULL, NULL, NULL); + + good_bridge_line_test("transport [::1]", + "[::1]:443", NULL, "transport", NULL); + + good_bridge_line_test("transport 192.0.2.1:12 " + "4352e58420e68f5e40bf7c74faddccd9d1349413", + "192.0.2.1:12", + "4352e58420e68f5e40bf7c74faddccd9d1349413", + "transport", NULL); + + { + smartlist_t *sl_tmp = smartlist_new(); + smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); + + good_bridge_line_test("transport 192.0.2.1:12 " + "4352e58420e68f5e40bf7c74faddccd9d1349413 twoandtwo=five", + "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413", + "transport", sl_tmp); + + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + } + + { + smartlist_t *sl_tmp = smartlist_new(); + smartlist_add_asprintf(sl_tmp, "twoandtwo=five"); + smartlist_add_asprintf(sl_tmp, "z=z"); + + good_bridge_line_test("transport 192.0.2.1:12 twoandtwo=five z=z", + "192.0.2.1:12", NULL, "transport", sl_tmp); + + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + } + + good_bridge_line_test("192.0.2.1:1231 " + "4352e58420e68f5e40bf7c74faddccd9d1349413", + "192.0.2.1:1231", + "4352e58420e68f5e40bf7c74faddccd9d1349413", + NULL, NULL); + + /* Empty line */ + bad_bridge_line_test(""); + /* bad transport name */ + bad_bridge_line_test("tr$n_sp0r7 190.20.2.2"); + /* weird ip address */ + bad_bridge_line_test("a.b.c.d"); + /* invalid fpr */ + bad_bridge_line_test("2.2.2.2:1231 4352e58420e68f5e40bf7c74faddccd9d1349"); + /* no k=v in the end */ + bad_bridge_line_test("obfs2 2.2.2.2:1231 " + "4352e58420e68f5e40bf7c74faddccd9d1349413 what"); + /* no addrport */ + bad_bridge_line_test("asdw"); + /* huge k=v value that can't fit in SOCKS fields */ + bad_bridge_line_test( + "obfs2 2.2.2.2:1231 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aa=b"); +} + +static void +test_config_parse_transport_options_line(void *arg) +{ + smartlist_t *options_sl = NULL, *sl_tmp = NULL; + + (void) arg; + + { /* too small line */ + options_sl = get_options_from_transport_options_line("valley", NULL); + test_assert(!options_sl); + } + + { /* no k=v values */ + options_sl = get_options_from_transport_options_line("hit it!", NULL); + test_assert(!options_sl); + } + + { /* correct line, but wrong transport specified */ + options_sl = + get_options_from_transport_options_line("trebuchet k=v", "rook"); + test_assert(!options_sl); + } + + { /* correct -- no transport specified */ + sl_tmp = smartlist_new(); + smartlist_add_asprintf(sl_tmp, "ladi=dadi"); + smartlist_add_asprintf(sl_tmp, "weliketo=party"); + + options_sl = + get_options_from_transport_options_line("rook ladi=dadi weliketo=party", + NULL); + test_assert(options_sl); + test_assert(smartlist_strings_eq(options_sl, sl_tmp)); + + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + sl_tmp = NULL; + SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); + smartlist_free(options_sl); + options_sl = NULL; + } + + { /* correct -- correct transport specified */ + sl_tmp = smartlist_new(); + smartlist_add_asprintf(sl_tmp, "ladi=dadi"); + smartlist_add_asprintf(sl_tmp, "weliketo=party"); + + options_sl = + get_options_from_transport_options_line("rook ladi=dadi weliketo=party", + "rook"); + test_assert(options_sl); + test_assert(smartlist_strings_eq(options_sl, sl_tmp)); + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + sl_tmp = NULL; + SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); + smartlist_free(options_sl); + options_sl = NULL; + } + + done: + if (options_sl) { + SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s)); + smartlist_free(options_sl); + } + if (sl_tmp) { + SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s)); + smartlist_free(sl_tmp); + } +} + #define CONFIG_TEST(name, flags) \ { #name, test_config_ ## name, flags, NULL, NULL } struct testcase_t config_tests[] = { CONFIG_TEST(addressmap, 0), + CONFIG_TEST(parse_bridge_line, 0), + CONFIG_TEST(parse_transport_options_line, 0), + CONFIG_TEST(check_or_create_data_subdir, TT_FORK), + CONFIG_TEST(write_to_data_subdir, TT_FORK), END_OF_TESTCASES }; diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index f92bfd673e..9dc43b1d27 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -4,7 +4,6 @@ /* See LICENSE for licensing information */ #include "orconfig.h" -#define CRYPTO_PRIVATE #define CRYPTO_CURVE25519_PRIVATE #include "or.h" #include "test.h" @@ -14,6 +13,10 @@ #include "crypto_curve25519.h" #endif +extern const char AUTHORITY_SIGNKEY_1[]; +extern const char AUTHORITY_SIGNKEY_1_DIGEST[]; +extern const char AUTHORITY_SIGNKEY_1_DIGEST256[]; + /** Run unit tests for Diffie-Hellman functionality. */ static void test_crypto_dh(void) @@ -269,34 +272,6 @@ test_crypto_sha(void) "96177A9CB410FF61F20015AD"); tt_int_op(i, ==, 0); - /* Test HMAC-SHA-1 with test cases from RFC2202. */ - - /* Case 1. */ - memset(key, 0x0b, 20); - crypto_hmac_sha1(digest, key, 20, "Hi There", 8); - test_streq(hex_str(digest, 20), - "B617318655057264E28BC0B6FB378C8EF146BE00"); - /* Case 2. */ - crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28); - test_streq(hex_str(digest, 20), - "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79"); - - /* Case 4. */ - base16_decode(key, 25, - "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); - memset(data, 0xcd, 50); - crypto_hmac_sha1(digest, key, 25, data, 50); - test_streq(hex_str(digest, 20), - "4C9007F4026250C6BC8414F9BF50C86C2D7235DA"); - - /* Case 5. */ - memset(key, 0xaa, 80); - crypto_hmac_sha1(digest, key, 80, - "Test Using Larger Than Block-Size Key - Hash Key First", - 54); - test_streq(hex_str(digest, 20), - "AA4AE5E15272D00E95705637CE8A3B55ED402112"); - /* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */ /* Case empty (wikipedia) */ @@ -422,7 +397,7 @@ test_crypto_pk(void) char *encoded = NULL; char data1[1024], data2[1024], data3[1024]; size_t size; - int i, j, p, len; + int i, len; /* Public-key ciphers */ pk1 = pk_generate(0); @@ -506,19 +481,16 @@ test_crypto_pk(void) /* Try with hybrid encryption wrappers. */ crypto_rand(data1, 1024); - for (i = 0; i < 2; ++i) { - for (j = 85; j < 140; ++j) { - memset(data2,0,1024); - memset(data3,0,1024); - p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING; - len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2), - data1,j,p,0); - test_assert(len>=0); - len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3), - data2,len,p,1); - test_eq(len,j); - test_memeq(data1,data3,j); - } + for (i = 85; i < 140; ++i) { + memset(data2,0,1024); + memset(data3,0,1024); + len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2), + data1,i,PK_PKCS1_OAEP_PADDING,0); + test_assert(len>=0); + len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3), + data2,len,PK_PKCS1_OAEP_PADDING,1); + test_eq(len,i); + test_memeq(data1,data3,i); } /* Try copy_full */ @@ -536,6 +508,35 @@ test_crypto_pk(void) tor_free(encoded); } +/** Sanity check for crypto pk digests */ +static void +test_crypto_digests(void) +{ + crypto_pk_t *k = NULL; + ssize_t r; + digests_t pkey_digests; + char digest[DIGEST_LEN]; + + k = crypto_pk_new(); + test_assert(k); + r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1); + test_assert(!r); + + r = crypto_pk_get_digest(k, digest); + test_assert(r == 0); + test_memeq(hex_str(digest, DIGEST_LEN), + AUTHORITY_SIGNKEY_1_DIGEST, HEX_DIGEST_LEN); + + r = crypto_pk_get_all_digests(k, &pkey_digests); + + test_memeq(hex_str(pkey_digests.d[DIGEST_SHA1], DIGEST_LEN), + AUTHORITY_SIGNKEY_1_DIGEST, HEX_DIGEST_LEN); + test_memeq(hex_str(pkey_digests.d[DIGEST_SHA256], DIGEST256_LEN), + AUTHORITY_SIGNKEY_1_DIGEST256, HEX_DIGEST256_LEN); + done: + crypto_pk_free(k); +} + /** Run unit tests for misc crypto formatting functionality (base64, base32, * fingerprints, etc) */ static void @@ -630,7 +631,7 @@ test_crypto_formats(void) data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000"); test_eq(strlen(data1), 40); data2 = tor_malloc(FINGERPRINT_LEN+1); - add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1); + crypto_add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1); test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000"); tor_free(data1); tor_free(data2); @@ -1134,6 +1135,7 @@ struct testcase_t crypto_tests[] = { { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" }, CRYPTO_LEGACY(sha), CRYPTO_LEGACY(pk), + CRYPTO_LEGACY(digests), CRYPTO_LEGACY(dh), CRYPTO_LEGACY(s2k), { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" }, diff --git a/src/test/test_data.c b/src/test/test_data.c index 5f0f7cba01..3c68b1294b 100644 --- a/src/test/test_data.c +++ b/src/test/test_data.c @@ -63,6 +63,11 @@ const char AUTHORITY_SIGNKEY_1[] = "Yx4lqK0ca5IkTp3HevwnlWaJgbaOTUspCVshzJBhDA==\n" "-----END RSA PRIVATE KEY-----\n"; +const char AUTHORITY_SIGNKEY_1_DIGEST[] = + "CBF56A83368A5150F1A9AAADAFB4D77F8C4170E2"; +const char AUTHORITY_SIGNKEY_1_DIGEST256[] = + "AF7C5468DBE3BA54A052726038D7F15F3C4CA511B1952645B3D96D83A8DFB51C"; + /** Second of 3 example authority certificates for unit testing. */ const char AUTHORITY_CERT_2[] = "dir-key-certificate-version 3\n" diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 56ac3b34c7..6c2915d094 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -2317,9 +2317,9 @@ test_dir_v2_dir(void *arg) /* Make a directory so there's somewhere to store the thing */ #ifdef _WIN32 - mkdir(get_fname("cached-status")); + tt_int_op(mkdir(get_fname("cached-status")), ==, 0); #else - mkdir(get_fname("cached-status"), 0700); + tt_int_op(mkdir(get_fname("cached-status"), 0700), ==, 0); #endif v2 = generate_v2_networkstatus_opinion(); diff --git a/src/test/test_options.c b/src/test/test_options.c new file mode 100644 index 0000000000..6beff2567e --- /dev/null +++ b/src/test/test_options.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define CONFIG_PRIVATE +#include "or.h" +#include "confparse.h" +#include "config.h" +#include "test.h" + +typedef struct { + int severity; + uint32_t domain; + char *msg; +} logmsg_t; + +static smartlist_t *messages = NULL; + +static void +log_cback(int severity, uint32_t domain, const char *msg) +{ + logmsg_t *x = tor_malloc(sizeof(*x)); + x->severity = severity; + x->domain = domain; + x->msg = tor_strdup(msg); + if (!messages) + messages = smartlist_new(); + smartlist_add(messages, x); +} + +static void +setup_log_callback(void) +{ + log_severity_list_t lst; + memset(&lst, 0, sizeof(lst)); + lst.masks[LOG_ERR - LOG_ERR] = ~0; + lst.masks[LOG_WARN - LOG_ERR] = ~0; + lst.masks[LOG_NOTICE - LOG_ERR] = ~0; + add_callback_log(&lst, log_cback); +} + +static char * +dump_logs(void) +{ + smartlist_t *msgs; + char *out; + if (! messages) + return tor_strdup(""); + msgs = smartlist_new(); + SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, x) { + smartlist_add_asprintf(msgs, "[%s] %s", + log_level_to_string(x->severity), x->msg); + } SMARTLIST_FOREACH_END(x); + out = smartlist_join_strings(msgs, "", 0, NULL); + SMARTLIST_FOREACH(msgs, char *, cp, tor_free(cp)); + smartlist_free(msgs); + return out; +} + +static void +clear_log_messages(void) +{ + if (!messages) + return; + SMARTLIST_FOREACH(messages, logmsg_t *, m, + { tor_free(m->msg); tor_free(m); }); + smartlist_free(messages); + messages = NULL; +} + +static void +test_options_validate_impl(const char *configuration, + const char *expect_errmsg, + int expect_log_severity, + const char *expect_log) +{ + or_options_t *opt = options_new(); + or_options_t *dflt; + config_line_t *cl=NULL; + char *msg=NULL; + int r; + opt->command = CMD_RUN_TOR; + options_init(opt); + + dflt = config_dup(&options_format, opt); + clear_log_messages(); + + r = config_get_lines(configuration, &cl, 1); + tt_int_op(r, ==, 0); + + r = config_assign(&options_format, opt, cl, 0, 0, &msg); + tt_int_op(r, ==, 0); + + r = options_validate(NULL, opt, dflt, 0, &msg); + if (expect_errmsg && !msg) { + TT_DIE(("Expected error message <%s> from <%s>, but got none.", + expect_errmsg, configuration)); + } else if (expect_errmsg && !strstr(msg, expect_errmsg)) { + TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.", + expect_errmsg, configuration, msg)); + } else if (!expect_errmsg && msg) { + TT_DIE(("Expected no error message from <%s> but got <%s>.", + configuration, msg)); + } + tt_int_op((r == 0), ==, (msg == NULL)); + + if (expect_log) { + int found = 0; + if (messages) { + SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, m) { + if (m->severity == expect_log_severity && + strstr(m->msg, expect_log)) { + found = 1; + break; + } + } SMARTLIST_FOREACH_END(m); + } + if (!found) { + tor_free(msg); + msg = dump_logs(); + TT_DIE(("Expected log message [%s] %s from <%s>, but got <%s>.", + log_level_to_string(expect_log_severity), expect_log, + configuration, msg)); + } + } + + done: + config_free_lines(cl); + or_options_free(opt); + or_options_free(dflt); + tor_free(msg); + clear_log_messages(); +} + +#define WANT_ERR(config, msg) \ + test_options_validate_impl((config), (msg), 0, NULL) +#define WANT_LOG(config, severity, msg) \ + test_options_validate_impl((config), NULL, (severity), (msg)) +#define WANT_ERR_LOG(config, msg, severity, logmsg) \ + test_options_validate_impl((config), (msg), (severity), (logmsg)) +#define OK(config) \ + test_options_validate_impl((config), NULL, 0, NULL) + +static void +test_options_validate(void *arg) +{ + (void)arg; + setup_log_callback(); + + WANT_ERR_LOG("ServerTransportOptions trebuchet", + "ServerTransportOptions did not parse", + LOG_WARN, "Too few arguments"); + OK("ServerTransportOptions trebuchet sling=snappy"); + OK("ServerTransportOptions trebuchet sling="); + WANT_ERR_LOG("ServerTransportOptions trebuchet slingsnappy", + "ServerTransportOptions did not parse", + LOG_WARN, "\"slingsnappy\" is not a k=v"); + +// done: + clear_log_messages(); + return; +} + +struct testcase_t options_tests[] = { + { "validate", test_options_validate, TT_FORK, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 80707f4379..f969457d0e 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -5,9 +5,14 @@ #include "orconfig.h" #define PT_PRIVATE +#define UTIL_PRIVATE #include "or.h" +#include "config.h" +#include "confparse.h" #include "transports.h" #include "circuitbuild.h" +#include "util.h" +#include "statefile.h" #include "test.h" static void @@ -22,64 +27,102 @@ static void test_pt_parsing(void) { char line[200]; + transport_t *transport = NULL; + tor_addr_t test_addr; managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_INFANT; mp->transports = smartlist_new(); /* incomplete cmethod */ - strcpy(line,"CMETHOD trebuchet"); + strlcpy(line,"CMETHOD trebuchet",sizeof(line)); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* wrong proxy type */ - strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999"); + strlcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999",sizeof(line)); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* wrong addrport */ - strcpy(line,"CMETHOD trebuchet socks4 abcd"); + strlcpy(line,"CMETHOD trebuchet socks4 abcd",sizeof(line)); test_assert(parse_cmethod_line(line, mp) < 0); reset_mp(mp); /* correct line */ - strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); test_assert(parse_cmethod_line(line, mp) == 0); - test_assert(smartlist_len(mp->transports)); + test_assert(smartlist_len(mp->transports) == 1); + transport = smartlist_get(mp->transports, 0); + /* test registered address of transport */ + tor_addr_parse(&test_addr, "127.0.0.1"); + test_assert(tor_addr_eq(&test_addr, &transport->addr)); + /* test registered port of transport */ + test_assert(transport->port == 1999); + /* test registered SOCKS version of transport */ + test_assert(transport->socks_version == PROXY_SOCKS5); + /* test registered name of transport */ + test_streq(transport->name, "trebuchet"); reset_mp(mp); /* incomplete smethod */ - strcpy(line,"SMETHOD trebuchet"); + strlcpy(line,"SMETHOD trebuchet",sizeof(line)); test_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* wrong addr type */ - strcpy(line,"SMETHOD trebuchet abcd"); + strlcpy(line,"SMETHOD trebuchet abcd",sizeof(line)); test_assert(parse_smethod_line(line, mp) < 0); reset_mp(mp); /* cowwect */ - strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999"); + strlcpy(line,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line)); test_assert(parse_smethod_line(line, mp) == 0); + test_assert(smartlist_len(mp->transports) == 1); + transport = smartlist_get(mp->transports, 0); + /* test registered address of transport */ + tor_addr_parse(&test_addr, "127.0.0.2"); + test_assert(tor_addr_eq(&test_addr, &transport->addr)); + /* test registered port of transport */ + test_assert(transport->port == 2999); + /* test registered name of transport */ + test_streq(transport->name, "trebuchy"); reset_mp(mp); + /* Include some arguments. Good ones. */ + strlcpy(line,"SMETHOD trebuchet 127.0.0.1:9999 " + "ARGS:counterweight=3,sling=snappy", + sizeof(line)); + test_assert(parse_smethod_line(line, mp) == 0); + tt_int_op(1, ==, smartlist_len(mp->transports)); + { + const transport_t *transport = smartlist_get(mp->transports, 0); + tt_assert(transport); + tt_str_op(transport->name, ==, "trebuchet"); + tt_int_op(transport->port, ==, 9999); + tt_str_op(fmt_addr(&transport->addr), ==, "127.0.0.1"); + tt_str_op(transport->extra_info_args, ==, + "counterweight=3,sling=snappy"); + } + reset_mp(mp); + /* unsupported version */ - strcpy(line,"VERSION 666"); + strlcpy(line,"VERSION 666",sizeof(line)); test_assert(parse_version(line, mp) < 0); /* incomplete VERSION */ - strcpy(line,"VERSION "); + strlcpy(line,"VERSION ",sizeof(line)); test_assert(parse_version(line, mp) < 0); /* correct VERSION */ - strcpy(line,"VERSION 1"); + strlcpy(line,"VERSION 1",sizeof(line)); test_assert(parse_version(line, mp) == 0); done: @@ -87,6 +130,58 @@ test_pt_parsing(void) } static void +test_pt_get_transport_options(void *arg) +{ + char **execve_args; + smartlist_t *transport_list = smartlist_new(); + managed_proxy_t *mp; + or_options_t *options = get_options_mutable(); + char *opt_str = NULL; + config_line_t *cl = NULL; + (void)arg; + + execve_args = tor_malloc(sizeof(char*)*2); + execve_args[0] = tor_strdup("cheeseshop"); + execve_args[1] = NULL; + + mp = managed_proxy_create(transport_list, execve_args, 1); + tt_ptr_op(mp, !=, NULL); + opt_str = get_transport_options_for_server_proxy(mp); + tt_ptr_op(opt_str, ==, NULL); + + smartlist_add(mp->transports_to_launch, tor_strdup("gruyere")); + smartlist_add(mp->transports_to_launch, tor_strdup("roquefort")); + smartlist_add(mp->transports_to_launch, tor_strdup("stnectaire")); + + tt_assert(options); + + cl = tor_malloc_zero(sizeof(config_line_t)); + cl->value = tor_strdup("gruyere melty=10 hardness=se;ven"); + options->ServerTransportOptions = cl; + + cl = tor_malloc_zero(sizeof(config_line_t)); + cl->value = tor_strdup("stnectaire melty=4 hardness=three"); + cl->next = options->ServerTransportOptions; + options->ServerTransportOptions = cl; + + cl = tor_malloc_zero(sizeof(config_line_t)); + cl->value = tor_strdup("pepperjack melty=12 hardness=five"); + cl->next = options->ServerTransportOptions; + options->ServerTransportOptions = cl; + + opt_str = get_transport_options_for_server_proxy(mp); + tt_str_op(opt_str, ==, + "gruyere:melty=10;gruyere:hardness=se\\;ven;" + "stnectaire:melty=4;stnectaire:hardness=three"); + + done: + tor_free(opt_str); + config_free_lines(cl); + managed_proxy_destroy(mp, 0); + smartlist_free(transport_list); +} + +static void test_pt_protocol(void) { char line[200]; @@ -99,32 +194,32 @@ test_pt_protocol(void) /* various wrong protocol runs: */ - strcpy(line,"VERSION 1"); + strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); - strcpy(line,"VERSION 1"); + strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); - strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_BROKEN); reset_mp(mp); /* correct protocol run: */ - strcpy(line,"VERSION 1"); + strlcpy(line,"VERSION 1",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); - strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); - strcpy(line,"CMETHODS DONE"); + strlcpy(line,"CMETHODS DONE",sizeof(line)); handle_proxy_line(line, mp); test_assert(mp->conf_state == PT_PROTO_CONFIGURED); @@ -132,12 +227,147 @@ test_pt_protocol(void) tor_free(mp); } +static void +test_pt_get_extrainfo_string(void *arg) +{ + managed_proxy_t *mp1 = NULL, *mp2 = NULL; + char **argv1, **argv2; + smartlist_t *t1 = smartlist_new(), *t2 = smartlist_new(); + int r; + char *s = NULL; + (void) arg; + + argv1 = tor_malloc_zero(sizeof(char*)*3); + argv1[0] = tor_strdup("ewige"); + argv1[1] = tor_strdup("Blumenkraft"); + argv1[2] = NULL; + argv2 = tor_malloc_zero(sizeof(char*)*4); + argv2[0] = tor_strdup("und"); + argv2[1] = tor_strdup("ewige"); + argv2[2] = tor_strdup("Schlangenkraft"); + argv2[3] = NULL; + + mp1 = managed_proxy_create(t1, argv1, 1); + mp2 = managed_proxy_create(t2, argv2, 1); + + r = parse_smethod_line("SMETHOD hagbard 127.0.0.1:5555", mp1); + tt_int_op(r, ==, 0); + r = parse_smethod_line("SMETHOD celine 127.0.0.1:1723 ARGS:card=no-enemy", + mp2); + tt_int_op(r, ==, 0); + + /* Force these proxies to look "completed" or they won't generate output. */ + mp1->conf_state = mp2->conf_state = PT_PROTO_COMPLETED; + + s = pt_get_extra_info_descriptor_string(); + tt_assert(s); + tt_str_op(s, ==, + "transport hagbard 127.0.0.1:5555\n" + "transport celine 127.0.0.1:1723 card=no-enemy\n"); + + done: + /* XXXX clean up better */ + smartlist_free(t1); + smartlist_free(t2); + tor_free(s); +} + +#ifdef _WIN32 +#define STDIN_HANDLE HANDLE +#else +#define STDIN_HANDLE FILE +#endif + +static smartlist_t * +tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle, + enum stream_status *stream_status_out) +{ + static int times_called = 0; + smartlist_t *retval_sl = smartlist_new(); + + (void) handle; + (void) stream_status_out; + + /* Generate some dummy CMETHOD lines the first 5 times. The 6th + time, send 'CMETHODS DONE' to finish configuring the proxy. */ + if (times_called++ != 5) { + smartlist_add_asprintf(retval_sl, "CMETHOD mock%d socks5 127.0.0.1:555%d", + times_called, times_called); + } else { + smartlist_add(retval_sl, tor_strdup("CMETHODS DONE")); + } + + return retval_sl; +} + +/* NOP mock */ +static void +tor_process_handle_destroy_replacement(process_handle_t *process_handle, + int also_terminate_process) +{ + (void) process_handle; + (void) also_terminate_process; +} + +static or_state_t *dummy_state = NULL; + +static or_state_t * +get_or_state_replacement(void) +{ + return dummy_state; +} + +/* Test the configure_proxy() function. */ +static void +test_pt_configure_proxy(void *arg) +{ + int i; + managed_proxy_t *mp = NULL; + (void) arg; + + dummy_state = tor_malloc_zero(sizeof(or_state_t)); + + MOCK(tor_get_lines_from_handle, + tor_get_lines_from_handle_replacement); + MOCK(tor_process_handle_destroy, + tor_process_handle_destroy_replacement); + MOCK(get_or_state, + get_or_state_replacement); + + mp = tor_malloc(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_ACCEPTING_METHODS; + mp->transports = smartlist_new(); + mp->transports_to_launch = smartlist_new(); + mp->process_handle = tor_malloc_zero(sizeof(process_handle_t)); + mp->argv = tor_malloc_zero(sizeof(char*)*2); + mp->argv[0] = tor_strdup("<testcase>"); + + /* Test the return value of configure_proxy() by calling it some + times while it is uninitialized and then finally finalizing its + configuration. */ + for (i = 0 ; i < 5 ; i++) { + test_assert(configure_proxy(mp) == 0); + } + test_assert(configure_proxy(mp) == 1); + + done: + tor_free(dummy_state); + UNMOCK(tor_get_lines_from_handle); + UNMOCK(tor_process_handle_destroy); +} + #define PT_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name } struct testcase_t pt_tests[] = { PT_LEGACY(parsing), PT_LEGACY(protocol), + { "get_transport_options", test_pt_get_transport_options, TT_FORK, + NULL, NULL }, + { "get_extrainfo_string", test_pt_get_extrainfo_string, TT_FORK, + NULL, NULL }, + { "configure_proxy",test_pt_configure_proxy, TT_FORK, + NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_replay.c b/src/test/test_replay.c index de841ad594..200bf4dd3e 100644 --- a/src/test/test_replay.c +++ b/src/test/test_replay.c @@ -32,6 +32,40 @@ test_replaycache_alloc(void) } static void +test_replaycache_badalloc(void) +{ + replaycache_t *r = NULL; + + /* Negative horizon should fail */ + r = replaycache_new(-600, 300); + test_assert(r == NULL); + /* Negative interval should get adjusted to zero */ + r = replaycache_new(600, -300); + test_assert(r != NULL); + test_eq(r->scrub_interval, 0); + replaycache_free(r); + /* Negative horizon and negative interval should still fail */ + r = replaycache_new(-600, -300); + test_assert(r == NULL); + + done: + if (r) replaycache_free(r); + + return; +} + +static void +test_replaycache_free_null(void) +{ + replaycache_free(NULL); + /* Assert that we're here without horrible death */ + test_assert(1); + + done: + return; +} + +static void test_replaycache_miss(void) { replaycache_t *r = NULL; @@ -45,6 +79,12 @@ test_replaycache_miss(void) (int)strlen(test_buffer), NULL); test_eq(result, 0); + /* poke the bad-parameter error case too */ + result = + replaycache_add_and_test_internal(1200, NULL, test_buffer, + (int)strlen(test_buffer), NULL); + test_eq(result, 0); + done: if (r) replaycache_free(r); @@ -163,16 +203,146 @@ test_replaycache_noexpire(void) return; } +static void +test_replaycache_scrub(void) +{ + replaycache_t *r = NULL; + int result; + + r = replaycache_new(600, 300); + test_assert(r != NULL); + + /* Set up like in test_replaycache_hit() */ + result = + replaycache_add_and_test_internal(100, r, test_buffer, + (int)strlen(test_buffer), NULL); + test_eq(result, 0); + + result = + replaycache_add_and_test_internal(200, r, test_buffer, + (int)strlen(test_buffer), NULL); + test_eq(result, 1); + + /* + * Poke a few replaycache_scrub_if_needed_internal() error cases that + * can't happen through replaycache_add_and_test_internal() + */ + + /* Null cache */ + replaycache_scrub_if_needed_internal(300, NULL); + /* Assert we're still here */ + test_assert(1); + + /* Make sure we hit the aging-out case too */ + replaycache_scrub_if_needed_internal(1500, r); + /* Assert that we aged it */ + test_eq(digestmap_size(r->digests_seen), 0); + + done: + if (r) replaycache_free(r); + + return; +} + +static void +test_replaycache_future(void) +{ + replaycache_t *r = NULL; + int result; + time_t elapsed = 0; + + r = replaycache_new(600, 300); + test_assert(r != NULL); + + /* Set up like in test_replaycache_hit() */ + result = + replaycache_add_and_test_internal(100, r, test_buffer, + (int)strlen(test_buffer), &elapsed); + test_eq(result, 0); + /* elapsed should still be 0, since it wasn't written */ + test_eq(elapsed, 0); + + result = + replaycache_add_and_test_internal(200, r, test_buffer, + (int)strlen(test_buffer), &elapsed); + test_eq(result, 1); + /* elapsed should be the time since the last hit */ + test_eq(elapsed, 100); + + /* + * Now let's turn the clock back to get coverage on the cache entry from the + * future not-supposed-to-happen case. + */ + result = + replaycache_add_and_test_internal(150, r, test_buffer, + (int)strlen(test_buffer), &elapsed); + /* We should still get a hit */ + test_eq(result, 1); + /* ...but it shouldn't let us see a negative elapsed time */ + test_eq(elapsed, 0); + + done: + if (r) replaycache_free(r); + + return; +} + +static void +test_replaycache_realtime(void) +{ + replaycache_t *r = NULL; + /* + * Negative so we fail if replaycache_add_test_and_elapsed() doesn't + * write to elapsed. + */ + time_t elapsed = -1; + int result; + + /* Test the realtime as well as *_internal() entry points */ + r = replaycache_new(600, 300); + test_assert(r != NULL); + + /* This should miss */ + result = + replaycache_add_and_test(r, test_buffer, (int)strlen(test_buffer)); + test_eq(result, 0); + + /* This should hit */ + result = + replaycache_add_and_test(r, test_buffer, (int)strlen(test_buffer)); + test_eq(result, 1); + + /* This should hit and return a small elapsed time */ + result = + replaycache_add_test_and_elapsed(r, test_buffer, + (int)strlen(test_buffer), &elapsed); + test_eq(result, 1); + test_assert(elapsed >= 0); + test_assert(elapsed <= 5); + + /* Scrub it to exercise that entry point too */ + replaycache_scrub_if_needed(r); + + done: + if (r) replaycache_free(r); + return; +} + #define REPLAYCACHE_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name } struct testcase_t replaycache_tests[] = { REPLAYCACHE_LEGACY(alloc), + REPLAYCACHE_LEGACY(badalloc), + REPLAYCACHE_LEGACY(free_null), REPLAYCACHE_LEGACY(miss), REPLAYCACHE_LEGACY(hit), REPLAYCACHE_LEGACY(age), REPLAYCACHE_LEGACY(elapsed), REPLAYCACHE_LEGACY(noexpire), + REPLAYCACHE_LEGACY(scrub), + REPLAYCACHE_LEGACY(future), + REPLAYCACHE_LEGACY(realtime), END_OF_TESTCASES }; diff --git a/src/test/test_util.c b/src/test/test_util.c index 6e1ee713d8..f7513c0f31 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -796,6 +796,64 @@ test_util_expand_filename(void) } #endif +/** Test tor_escape_str_for_pt_args(). */ +static void +test_util_escape_string_socks(void) +{ + char *escaped_string = NULL; + + /** Simple backslash escape. */ + escaped_string = tor_escape_str_for_pt_args("This is a backslash: \\",";\\"); + test_assert(escaped_string); + test_streq(escaped_string, "This is a backslash: \\\\"); + tor_free(escaped_string); + + /** Simple semicolon escape. */ + escaped_string = tor_escape_str_for_pt_args("First rule:Do not use ;",";\\"); + test_assert(escaped_string); + test_streq(escaped_string, "First rule:Do not use \\;"); + tor_free(escaped_string); + + /** Empty string. */ + escaped_string = tor_escape_str_for_pt_args("", ";\\"); + test_assert(escaped_string); + test_streq(escaped_string, ""); + tor_free(escaped_string); + + /** Escape all characters. */ + escaped_string = tor_escape_str_for_pt_args(";\\;\\", ";\\"); + test_assert(escaped_string); + test_streq(escaped_string, "\\;\\\\\\;\\\\"); + tor_free(escaped_string); + + escaped_string = tor_escape_str_for_pt_args(";", ";\\"); + test_assert(escaped_string); + test_streq(escaped_string, "\\;"); + tor_free(escaped_string); + + done: + tor_free(escaped_string); +} + +static void +test_util_string_is_key_value(void *ptr) +{ + (void)ptr; + test_assert(string_is_key_value(LOG_WARN, "key=value")); + test_assert(string_is_key_value(LOG_WARN, "k=v")); + test_assert(string_is_key_value(LOG_WARN, "key=")); + test_assert(string_is_key_value(LOG_WARN, "x=")); + test_assert(string_is_key_value(LOG_WARN, "xx=")); + test_assert(!string_is_key_value(LOG_WARN, "=value")); + test_assert(!string_is_key_value(LOG_WARN, "=x")); + test_assert(!string_is_key_value(LOG_WARN, "=")); + + /* ??? */ + /* test_assert(!string_is_key_value(LOG_WARN, "===")); */ + done: + ; +} + /** Test basic string functionality. */ static void test_util_strmisc(void) @@ -2223,6 +2281,7 @@ test_util_load_win_lib(void *ptr) } #endif +#ifndef _WIN32 static void clear_hex_errno(char *hex_errno) { @@ -2266,6 +2325,7 @@ test_util_exit_status(void *ptr) done: ; } +#endif #ifndef _WIN32 /** Check that fgets waits until a full line, and not return a partial line, on @@ -2567,14 +2627,14 @@ test_util_spawn_background_partial_read(void *ptr) } /** - * Test for format_hex_number_for_helper_exit_status() + * Test for format_hex_number_sigsafe() */ static void test_util_format_hex_number(void *ptr) { int i, len; - char buf[HEX_ERRNO_SIZE + 1]; + char buf[33]; const struct { const char *str; unsigned int x; @@ -2583,6 +2643,8 @@ test_util_format_hex_number(void *ptr) {"1", 1}, {"273A", 0x273a}, {"FFFF", 0xffff}, + {"7FFFFFFF", 0x7fffffff}, + {"FFFFFFFF", 0xffffffff}, #if UINT_MAX >= 0xffffffff {"31BC421D", 0x31bc421d}, {"FFFFFFFF", 0xffffffff}, @@ -2593,19 +2655,23 @@ test_util_format_hex_number(void *ptr) (void)ptr; for (i = 0; test_data[i].str != NULL; ++i) { - len = format_hex_number_for_helper_exit_status(test_data[i].x, - buf, HEX_ERRNO_SIZE); + len = format_hex_number_sigsafe(test_data[i].x, buf, sizeof(buf)); test_neq(len, 0); - buf[len] = '\0'; + test_eq(len, strlen(buf)); test_streq(buf, test_data[i].str); } + test_eq(4, format_hex_number_sigsafe(0xffff, buf, 5)); + test_streq(buf, "FFFF"); + test_eq(0, format_hex_number_sigsafe(0xffff, buf, 4)); + test_eq(0, format_hex_number_sigsafe(0, buf, 1)); + done: return; } /** - * Test that we can properly format q Windows command line + * Test that we can properly format a Windows command line */ static void test_util_join_win_cmdline(void *ptr) @@ -2816,7 +2882,7 @@ test_util_eat_whitespace(void *ptr) (void)ptr; /* Try one leading ws */ - strcpy(str, "fuubaar"); + strlcpy(str, "fuubaar", sizeof(str)); for (i = 0; i < sizeof(ws); ++i) { str[0] = ws[i]; test_eq_ptr(str + 1, eat_whitespace(str)); @@ -2831,14 +2897,14 @@ test_util_eat_whitespace(void *ptr) test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Empty string */ - strcpy(str, ""); + strlcpy(str, "", sizeof(str)); test_eq_ptr(str, eat_whitespace(str)); test_eq_ptr(str, eat_whitespace_eos(str, str)); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str)); /* Only ws */ - strcpy(str, " \t\r\n"); + strlcpy(str, " \t\r\n", sizeof(str)); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + strlen(str) - 1, @@ -2846,7 +2912,7 @@ test_util_eat_whitespace(void *ptr) test_eq_ptr(str + strlen(str) - 1, eat_whitespace_eos_no_nl(str, str + strlen(str))); - strcpy(str, " \t\r "); + strlcpy(str, " \t\r ", sizeof(str)); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); @@ -2855,7 +2921,7 @@ test_util_eat_whitespace(void *ptr) eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Multiple ws */ - strcpy(str, "fuubaar"); + strlcpy(str, "fuubaar", sizeof(str)); for (i = 0; i < sizeof(ws); ++i) str[i] = ws[i]; test_eq_ptr(str + sizeof(ws), eat_whitespace(str)); @@ -2865,28 +2931,28 @@ test_util_eat_whitespace(void *ptr) eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat comment */ - strcpy(str, "# Comment \n No Comment"); + strlcpy(str, "# Comment \n No Comment", sizeof(str)); test_streq("No Comment", eat_whitespace(str)); test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat comment & ws mix */ - strcpy(str, " # \t Comment \n\t\nNo Comment"); + strlcpy(str, " # \t Comment \n\t\nNo Comment", sizeof(str)); test_streq("No Comment", eat_whitespace(str)); test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + 1, eat_whitespace_no_nl(str)); test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Eat entire comment */ - strcpy(str, "#Comment"); + strlcpy(str, "#Comment", sizeof(str)); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str, eat_whitespace_no_nl(str)); test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str))); /* Blank line, then comment */ - strcpy(str, " \t\n # Comment"); + strlcpy(str, " \t\n # Comment", sizeof(str)); test_eq_ptr(str + strlen(str), eat_whitespace(str)); test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str))); test_eq_ptr(str + 2, eat_whitespace_no_nl(str)); @@ -3211,6 +3277,42 @@ test_util_mathlog(void *arg) ; } +static void +test_util_round_to_next_multiple_of(void *arg) +{ + (void)arg; + + test_assert(round_uint64_to_next_multiple_of(0,1) == 0); + test_assert(round_uint64_to_next_multiple_of(0,7) == 0); + + test_assert(round_uint64_to_next_multiple_of(99,1) == 99); + test_assert(round_uint64_to_next_multiple_of(99,7) == 105); + test_assert(round_uint64_to_next_multiple_of(99,9) == 99); + + done: + ; +} + +static void +test_util_strclear(void *arg) +{ + static const char *vals[] = { "", "a", "abcdef", "abcdefgh", NULL }; + int i; + char *v = NULL; + (void)arg; + + for (i = 0; vals[i]; ++i) { + size_t n; + v = tor_strdup(vals[i]); + n = strlen(v); + tor_strclear(v); + tt_assert(tor_mem_is_zero(v, n+1)); + tor_free(v); + } + done: + tor_free(v); +} + #define UTIL_LEGACY(name) \ { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name } @@ -3227,6 +3329,8 @@ struct testcase_t util_tests[] = { #ifndef _WIN32 UTIL_LEGACY(expand_filename), #endif + UTIL_LEGACY(escape_string_socks), + UTIL_LEGACY(string_is_key_value), UTIL_LEGACY(strmisc), UTIL_LEGACY(pow2), UTIL_LEGACY(gzip), @@ -3240,6 +3344,8 @@ struct testcase_t util_tests[] = { UTIL_LEGACY(path_is_relative), UTIL_LEGACY(strtok), UTIL_LEGACY(di_ops), + UTIL_TEST(round_to_next_multiple_of, 0), + UTIL_TEST(strclear, 0), UTIL_TEST(find_str_at_start_of_line, 0), UTIL_TEST(string_is_C_identifier, 0), UTIL_TEST(asprintf, 0), @@ -3248,8 +3354,8 @@ struct testcase_t util_tests[] = { #ifdef _WIN32 UTIL_TEST(load_win_lib, 0), #endif - UTIL_TEST(exit_status, 0), #ifndef _WIN32 + UTIL_TEST(exit_status, 0), UTIL_TEST(fgets_eagain, TT_SKIP), #endif UTIL_TEST(spawn_background_ok, 0), diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c index a3860ca4b7..d50f12ed2a 100644 --- a/src/tools/tor-checkkey.c +++ b/src/tools/tor-checkkey.c @@ -1,8 +1,6 @@ /* Copyright (c) 2008-2013, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#define CRYPTO_PRIVATE - #include "orconfig.h" #include <stdio.h> diff --git a/src/tools/tor-fw-helper/tor-fw-helper.c b/src/tools/tor-fw-helper/tor-fw-helper.c index bb6e70aaa3..84cc21e346 100644 --- a/src/tools/tor-fw-helper/tor-fw-helper.c +++ b/src/tools/tor-fw-helper/tor-fw-helper.c @@ -496,6 +496,6 @@ main(int argc, char **argv) smartlist_free(tor_fw_options.ports_to_forward); } - exit(r); + exit(0); } diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index 3809b22d43..25beb2aae1 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -27,8 +27,6 @@ #include <assert.h> #endif -#define CRYPTO_PRIVATE - #include "compat.h" #include "../common/util.h" #include "../common/torlog.h" diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index f5d5cf4460..43f68c3b08 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -241,7 +241,7 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.2.4.10-alpha-dev" +#define VERSION "0.2.5.0-alpha-dev" |