diff options
88 files changed, 2818 insertions, 742 deletions
@@ -1,3 +1,148 @@ +Changes in version 0.2.5.4-alpha - 2014-04-?? + + o Deprecated versions: + - Tor 0.2.2.x has reached end-of-life; it has received no patches or + attention for some while. Directory authorities no longer accept + descriptors from Tor relays running any version of Tor prior to Tor + 0.2.3.16-alpha. Resolves ticket 11149. + + o Major features (relay performance): + - Faster server-side lookups of rendezvous and introduction point + circuits by using hashtables instead of linear searches over all + the circuits. These functions previously accounted between 3 and + 7% of CPU usage on some busy relays. + + o Major bugfixes (undefined behavior): + - Fix two instances of possible undefined behavior in channeltls.c + that could, under unlucky circumstances, have led to a pointer + overflow. Fixes bug #10363; bugfixes on 0.2.0.10-alpha and + 0.2.3.6-alpha. Reported by "bobnomnom". + - Fix another possibly undefined pointer operations in tor_memmem + fallback implementation. Another case of bug #10363; bugfix on + 0.1.1.1-alpha. + - Fix another possibly undefined pointer operations in the eventdns + fallback implementation. Another case of bug #10363; bugfix on + 0.1.2.1-alpha. + - Use AddressSanitizer and Ubsan sanitizers (in clang-3.4) to fix some + miscellaneous errors in our tests and codebase. Fix for bug 11232. + Bugfixes on versions back as far as 0.2.1.11-alpha. + + o Minor bugfixes (logging): + - Log only one message when we start logging in an unsafe + way. Previously, we would log as many messages as we had + problems. Fix for #9870; bugfix on 0.2.5.1-alpha. + + o Minor bugfixes (tor-fw-helper): + - Allow tor-fw-helper to build again by adding src/ext to its + CPPFLAGS. Fixes bug 11296; bugfix on 0.2.5.3-alpha. + + o Minor bugfixes (bridges): + - Avoid potential crashes or bad behavior when launching a + server-side managed proxy with ORPort or ExtORPort temporarily + disabled. Fixes bug 9650; bugfix on 0.2.3.16-alpha. + + o Minor bugfixes (misc): + - Don't re-initialize a second set of openssl mutexes when starting + up. Fixes bug 11726; bugfix on 0.2.5.3-alpha. + + o Minor bugfixes (memory leaks): + - Fix a minor memory leak that occurred when signing a directory + object. Fixes bug 11275; bugfix on 0.2.4.13-alpha. + + o Minor bugfixes (platform-specific): + - Fix compilation on Solaris, which does not have <endian.h>. + Fixes bug 11426; bugfix on 0.2.5.3-alpha. + - When dumping a malformed directory object to disk, save it in binary + mode on windows, not text mode. Fixes bug 11342; bugfix on + 0.2.2.1-alpha. + - When reporting a failure from make_socket_reuseable(), don't + report a warning when we get a failure from an incoming socket + on OSX. Fix for bug 10081. + + o Minor bugfixes (trivial memory leaks): + - Free placeholder entries in our circuit table at exit; fixes + a harmless memory leak. Fixes bug 11278; bugfix on 0.2.5.1-alpha. + - Resolve some memory leaks found by coverity in the unit tests, + on exit in tor-gencert, and on a failure to compute digests + for our own keys when generating a v3 networkstatus vote. + These leaks should never have affected anyone in practice. + + o Minor bugfixes (hidden service): + - Only retry attempts to connect to a chosen rendezvous point 8 times, + not 30. Fixes bug #4241; bugfix on 0.1.0.1-rc. + + o Minor bugfixes (bridge client): + - Stop accepting bridge lines containing hostnames. Doing so allowed + clients to perform DNS requests on the hostnames, which was not + sensible behavior. Fixes bug 10801; bugfix on 0.2.0.1-alpha. + + o Minor bugfixes (exit): + - Stop leaking memory when we successfully resolve a PTR record. + Fixes bug 11437; bugfix on 0.2.4.7-alpha. + + o Minor bugfixes (windows): + + o Minor bugfixes (IPv6): + - When using DNSPort and AutomapHostsOnResolve, respond to AAAA + requests with AAAA automapped answers. Fixes bug 10468; bugfix + on 0.2.4.7-alpha. + + o Minor features (relay): + - If a circuit timed out for at least 3 minutes check if we have a new + external IP address the next time we run our routine checks. If our + IP address has changed, then publish a new descriptor with the new + IP address. Resolves ticket 2454. + - Warn less verbosely when receiving a misformed ESTABLISH_RENDEZVOUS + cell. Fixes ticket 11279. + + o Minor features (controller): + - Make the entire exit policy available from the control port via + GETINFO exit-policy/*. Implements enhancement #7952. Patch from + "rl1987". + + o Minor features (misc): + - Always check return values for unlink, munmap, UnmapViewOfFile; + check strftime return values more often. In some cases all we + can do is report a warning, but this may help prevent deeper + bugs from going unnoticed. Closes ticket 8787. + + o Minor features (bridge client): + - Report a failure to connect to a bridge because its transport + type has no configured pluggable transport as a new type of bootstrap + failure. Resolves ticket 9665. Patch from Fábio J. Bertinatto. + + o Minor features (diagnostic): + - Try harder to diagnose a possible cause of bug 7164, which causes + intermittent "microdesc_free() called but md was still referenced" + warnings. We now log more information about the likely error case, + to try to figure out why we might be cleaning a microdescriptor + as old if it's still referenced by a live node. + + o Documentation: + - Build the torify.1 manpage again. Previously, we were only + trying to build it when also building tor-fw-helper. That's why + we didn't notice that we'd broken the ability to build it. + Fixes bug 11321; bugfix on 0.2.5.1-alpha. + - Fix the layout of the SOCKSPort flags in the manpage. Fixes bug + 11061; bugfix on 0.2.4.7-alpha. + - Correctly document that we search for a system torrc file before + looking in ~/.torrc. Fixes documentation side of 9213; bugfix + on 0.2.3.18-rc. + - Resolve warnings from Doxygen. + + o Code simplifications and refactoring: + - Removing is_internal_IP() function. Resolves ticket 4645. + - Remove unused function circuit_dump_by_chan from circuitlist.c. Closes + issue #9107; patch from "marek". + - Change our use of the ENUM_BF macro to avoid declarations that + confuse Doxygen. + + o Removed code: + - Remove all code for the long unused v1 directory protocol. Resolves + ticket 11070. + + + Changes in version 0.2.5.3-alpha - 2014-03-22 Tor 0.2.5.3-alpha includes all the fixes from 0.2.4.21. It contains two new anti-DoS features for Tor relays, resolves a bug that kept diff --git a/changes/11507 b/changes/11507 new file mode 100644 index 0000000000..f656d90802 --- /dev/null +++ b/changes/11507 @@ -0,0 +1,7 @@ + o Testing support: + - New macros in test.h to simplify writting mock-functions for unit + tests. Part of ticket 11507. Patch from Dana Koch. + + o Testing: + - Complete tests for the status.c module. Resolves ticket 11507. + Patch from Dana Koch. diff --git a/changes/bug10081 b/changes/bug10081 deleted file mode 100644 index 654b83c0b7..0000000000 --- a/changes/bug10081 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features: - - When reporting a failure from make_socket_reuseable(), don't - report a warning when we get a failure from an incoming socket - on OSX. Fix for bug 10081. - diff --git a/changes/bug10431 b/changes/bug10431 new file mode 100644 index 0000000000..39353a2749 --- /dev/null +++ b/changes/bug10431 @@ -0,0 +1,5 @@ + o Minor bugfixes: + - Only report the first fatal boostrap error on a given OR + connection. This prevents controllers from declaring that a + connection has failed because of "DONE" or other junk reasons. + Fixes bug 10431; bugfix on 0.2.1.1-alpha. diff --git a/changes/bug10468 b/changes/bug10468 deleted file mode 100644 index 128eb3ac65..0000000000 --- a/changes/bug10468 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - When using DNSPort and AutomapHostsOnResolve, respond to AAAA - requests with AAAA automapped answers. Fixes bug 10468; bugfix - on 0.2.4.7-alpha. diff --git a/changes/bug11061 b/changes/bug11061 deleted file mode 100644 index 5035e876af..0000000000 --- a/changes/bug11061 +++ /dev/null @@ -1,3 +0,0 @@ - o Documentation fixes: - - Fix the layout of the SOCKSPort flags in the manpage. Fixes bug - 11061; bugfix on 0.2.4.7-alpha. diff --git a/changes/bug11070 b/changes/bug11070 deleted file mode 100644 index 88fecf9793..0000000000 --- a/changes/bug11070 +++ /dev/null @@ -1,4 +0,0 @@ - o Removed code: - - Remove all code for the long unused v1 directory protocol. Resolves - ticket 11070. - diff --git a/changes/bug11232 b/changes/bug11232 deleted file mode 100644 index c1a8780838..0000000000 --- a/changes/bug11232 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - Use AddressSanitizer and Ubsan sanitizers (in clang-3.4) to fix some - miscellaneous errors in our tests and codebase. Fix for bug 11232. - Bugfixes on versions back as far as 0.2.1.11-alpha. diff --git a/changes/bug11275 b/changes/bug11275 deleted file mode 100644 index b9b019ff49..0000000000 --- a/changes/bug11275 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Fix a minor memory leak that occurred when signing a directory - object. Fixes bug 11275; bugfix on 0.2.4.13-alpha. diff --git a/changes/bug11276 b/changes/bug11276 deleted file mode 100644 index be37534351..0000000000 --- a/changes/bug11276 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Don't re-initialize a second set of openssl mutexes when starting - up. Fixes bug 11726; bugfix on 0.2.5.3-alpha. diff --git a/changes/bug11278 b/changes/bug11278 deleted file mode 100644 index 4fa59fc690..0000000000 --- a/changes/bug11278 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Free placeholder entries in our circuit table at exit; fixes - a harmless memory leak. Fixes bug 11278; bugfix on 0.2.5.1-alpha. diff --git a/changes/bug11279 b/changes/bug11279 deleted file mode 100644 index 1e9da41180..0000000000 --- a/changes/bug11279 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor features: - - Warn less verbosely when receiving a misformed ESTABLISH_RENDEZVOUS - cell. Fixes ticket 11279. diff --git a/changes/bug11296 b/changes/bug11296 deleted file mode 100644 index 156749761d..0000000000 --- a/changes/bug11296 +++ /dev/null @@ -1,3 +0,0 @@ - o Minor bugfixes: - - Allow tor-fw-helper to build again by adding src/ext to its - CPPFLAGS. Fixes bug 11296; bugfix on 0.2.5.3-alpha. diff --git a/changes/bug11321 b/changes/bug11321 deleted file mode 100644 index d737a1f37d..0000000000 --- a/changes/bug11321 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes (build): - - Build the torify.1 manpage again. Previously, we were only - trying to build it when also building tor-fw-helper. That's why - we didn't notice that we'd broken the ability to build it. - Fixes bug 11321; bugfix on 0.2.5.1-alpha. diff --git a/changes/bug11342 b/changes/bug11342 deleted file mode 100644 index a52a5515e7..0000000000 --- a/changes/bug11342 +++ /dev/null @@ -1,4 +0,0 @@ - o Minor bugfixes: - - When dumping a malformed directory object to disk, save it in binary - mode on windows, not text mode. Fixes bug 11342; bugfix on - 0.2.2.1-alpha. diff --git a/changes/bug11464_023 b/changes/bug11464_023 new file mode 100644 index 0000000000..80c04b21e6 --- /dev/null +++ b/changes/bug11464_023 @@ -0,0 +1,5 @@ + o Major features (security): + - Block authority signing keys that were used on an authorities + vulnerable to the "heartbleed" bug in openssl (CVE-2014-0160). + (We don't have any evidence that these keys _were_ compromised; + we're doing this to be prudent.) Resolves ticket 11464. diff --git a/changes/bug11465 b/changes/bug11465 new file mode 100644 index 0000000000..2425299ca8 --- /dev/null +++ b/changes/bug11465 @@ -0,0 +1,9 @@ + o Minor features: + - When the Linux syscall sandbox finds an illegal system call, it + now tries to log a stack trace before exiting. Resolves ticket + 11465. + + o Minor bugfixes: + - Using the Linux syscall sandbox no longer prevents stack-trace + logging on crashes or errors. Fixes part 11465; bugfix on + 0.2.5.1-alpha. diff --git a/changes/bug11513 b/changes/bug11513 new file mode 100644 index 0000000000..820c02605f --- /dev/null +++ b/changes/bug11513 @@ -0,0 +1,12 @@ + o Major bugfixes: + - Generate the server's preference list for ciphersuites + automatically based on uniform criteria, and considering all + OpenSSL ciphersuites with acceptable strength and forward + secrecy. (The sort order is: prefer AES to 3DES; break ties by + preferring ECDHE to DHE; break ties by preferring GCM to CBC; + break ties by preferring SHA384 to SHA256 to SHA1; and finally, + break ties by preferring AES256 to AES128.) This resolves bugs + #11513, #11492, #11498, #11499. Bugs reported by 'cypherpunks'. + Bugfix on 0.2.4.8-alpha. + + diff --git a/changes/bug11519 b/changes/bug11519 new file mode 100644 index 0000000000..5c1e6af7e4 --- /dev/null +++ b/changes/bug11519 @@ -0,0 +1,3 @@ + o Minor bugfixes: + - Avoid sending an garbage value to the controller when a circuit is + cannibalized. Fixes bug 11519; bugfix on 0.2.3.11-alpha. diff --git a/changes/bug5286 b/changes/bug5286 new file mode 100644 index 0000000000..de02a9ab69 --- /dev/null +++ b/changes/bug5286 @@ -0,0 +1,4 @@ + o Minor features: + - Demote the message that we give when a flushing connection times + out for too long from NOTICE to INFO. It was usually meaningless. + Resolves ticket 5286. diff --git a/changes/bug7164_diagnose_harder b/changes/bug7164_diagnose_harder deleted file mode 100644 index 28c36b658f..0000000000 --- a/changes/bug7164_diagnose_harder +++ /dev/null @@ -1,6 +0,0 @@ - o Minor features: - - Try harder to diagnose a possible cause of bug 7164, which causes - intermittent "microdesc_free() called but md was still referenced" - warnings. We now log more information about the likely error case, - to try to figure out why we might be cleaning a microdescriptor - as old if it's still referenced by a live node. diff --git a/changes/bug8787 b/changes/bug8787 deleted file mode 100644 index 212844ad2e..0000000000 --- a/changes/bug8787 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor features: - - Always check return values for unlink, munmap, UnmapViewOfFile; - check strftime return values more often. In some cases all we - can do is report a warning, but this may help prevent deeper - bugs from going unnoticed. Closes ticket 8787. diff --git a/changes/bug9107 b/changes/bug9107 deleted file mode 100644 index dba1669778..0000000000 --- a/changes/bug9107 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplifications and refactoring: - - Remove unused function circuit_dump_by_chan from circuitlist.c. Closes - issue #9107; patch from "marek". diff --git a/changes/bug9213_doc b/changes/bug9213_doc deleted file mode 100644 index 2f959dd831..0000000000 --- a/changes/bug9213_doc +++ /dev/null @@ -1,5 +0,0 @@ - o Documentation: - - Correctly document that we search for a system torrc file before - looking in ~/.torrc. Fixes documentation side of 9213; bugfix - on 0.2.3.18-rc. - diff --git a/changes/bug9870 b/changes/bug9870 deleted file mode 100644 index b4b2c2df2a..0000000000 --- a/changes/bug9870 +++ /dev/null @@ -1,5 +0,0 @@ - o Minor bugfixes: - - - Log only one message when we start logging in an unsafe - way. Previously, we would log as many messages as we had - problems. Fix for #9870; bugfix on 0.2.5.1-alpha. diff --git a/changes/doxygen_fixes b/changes/doxygen_fixes deleted file mode 100644 index a9add9d627..0000000000 --- a/changes/doxygen_fixes +++ /dev/null @@ -1,6 +0,0 @@ - o Documentation: - - Resolve warnings from Doxygen. - - o Code simplification and refactoring: - - Change our use of the ENUM_BF macro to avoid declarations that - confuse Doxygen. diff --git a/changes/ff28_ciphers b/changes/ff28_ciphers new file mode 100644 index 0000000000..05eb4e9bcc --- /dev/null +++ b/changes/ff28_ciphers @@ -0,0 +1,6 @@ + o Minor features (performance, compatibility): + - Update the list of TLS cipehrsuites that a client advertises + to match those advertised by Firefox 28. This enables selection of + (fast) GCM ciphersuites, disables some strange old ciphers, and + disables the ECDH (not to be confused with ECDHE) ciphersuites. + Resolves ticket 11438. diff --git a/changes/require_023 b/changes/require_023 deleted file mode 100644 index f3a5a1417c..0000000000 --- a/changes/require_023 +++ /dev/null @@ -1,6 +0,0 @@ - o Deprecated versions: - - Tor 0.2.2.x is no longer supported, and has not been for a while. - Directory authorities no longer accept descriptors from - Tor relays running any version of Tor prior to Tor 0.2.3.16-alpha. - Resolves ticket 11149. - diff --git a/changes/ticket4645 b/changes/ticket4645 deleted file mode 100644 index cc665ba1a1..0000000000 --- a/changes/ticket4645 +++ /dev/null @@ -1,3 +0,0 @@ - o Code simplifications and refactoring: - - Removing is_internal_IP() function. Resolves ticket 4645. - diff --git a/src/common/address.c b/src/common/address.c index cc3e31f65f..e5930dedca 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -1451,12 +1451,16 @@ get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr) * to the port. * * Don't do DNS lookups and don't allow domain names in the "ip" field. - * Don't accept <b>addrport</b> of the form "ip" or "ip:0". + * + * If <b>default_port</b> is less than 0, don't accept <b>addrport</b> of the + * form "ip" or "ip:0". Otherwise, accept those forms, and set + * *<b>port_out</b> to <b>default_port</b>. * * Return 0 on success, -1 on failure. */ int tor_addr_port_parse(int severity, const char *addrport, - tor_addr_t *address_out, uint16_t *port_out) + tor_addr_t *address_out, uint16_t *port_out, + int default_port) { int retval = -1; int r; @@ -1470,8 +1474,12 @@ tor_addr_port_parse(int severity, const char *addrport, if (r < 0) goto done; - if (!*port_out) - goto done; + if (!*port_out) { + if (default_port >= 0) + *port_out = default_port; + else + goto done; + } /* make sure that address_out is an IP address */ if (tor_addr_parse(address_out, addr_tmp) < 0) @@ -1492,9 +1500,18 @@ int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out) { + tor_addr_t a_tmp; tor_assert(addrport); tor_assert(address_out); tor_assert(port_out); + /* We need to check for IPv6 manually because addr_port_lookup() doesn't + * do a good job on IPv6 addresses that lack a port. */ + if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) { + *port_out = 0; + *address_out = tor_strdup(addrport); + return 0; + } + return addr_port_lookup(severity, addrport, address_out, NULL, port_out); } diff --git a/src/common/address.h b/src/common/address.h index 61de3d2d96..8dc63b71c1 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -210,7 +210,8 @@ int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out); int tor_addr_port_parse(int severity, const char *addrport, - tor_addr_t *address_out, uint16_t *port_out); + tor_addr_t *address_out, uint16_t *port_out, + int default_port); int tor_addr_hostname_is_local(const char *name); diff --git a/src/common/backtrace.c b/src/common/backtrace.c index 239c65782b..3a073a8ff5 100644 --- a/src/common/backtrace.c +++ b/src/common/backtrace.c @@ -5,7 +5,6 @@ #define _GNU_SOURCE 1 #include "orconfig.h" -#include "backtrace.h" #include "compat.h" #include "util.h" #include "torlog.h" @@ -31,6 +30,9 @@ #include <ucontext.h> #endif +#define EXPOSE_CLEAN_BACKTRACE +#include "backtrace.h" + #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) #define USE_BACKTRACE @@ -59,7 +61,7 @@ static tor_mutex_t cb_buf_mutex; * onto the stack. Fortunately, we usually have the program counter in the * ucontext_t structure. */ -static void +void clean_backtrace(void **stack, int depth, const ucontext_t *ctx) { #ifdef PC_FROM_UCONTEXT @@ -165,6 +167,18 @@ install_bt_handler(void) rv = -1; } } + + { + /* Now, generate (but do not log) a backtrace. This ensures that + * libc has pre-loaded the symbols we need to dump things, so that later + * reads won't be denied by the sandbox code */ + char **symbols; + int depth = backtrace(cb_buf, MAX_DEPTH); + symbols = backtrace_symbols(cb_buf, depth); + if (symbols) + free(symbols); + } + return rv; } diff --git a/src/common/backtrace.h b/src/common/backtrace.h index 765436fee3..1f4d73339f 100644 --- a/src/common/backtrace.h +++ b/src/common/backtrace.h @@ -4,9 +4,18 @@ #ifndef TOR_BACKTRACE_H #define TOR_BACKTRACE_H +#include "orconfig.h" + void log_backtrace(int severity, int domain, const char *msg); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); +#ifdef EXPOSE_CLEAN_BACKTRACE +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) +void clean_backtrace(void **stack, int depth, const ucontext_t *ctx); +#endif +#endif + #endif diff --git a/src/common/ciphers.inc b/src/common/ciphers.inc index 137d78b117..ab4ac40724 100644 --- a/src/common/ciphers.inc +++ b/src/common/ciphers.inc @@ -4,86 +4,51 @@ * * This file was automatically generated by get_mozilla_ciphers.py. */ -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA - CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#else - XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) -#else - XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA - CIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA) +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + CIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) #else - XCIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA) + XCIPHER(0xc02b, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) #endif -#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA - CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + CIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) #else - XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) + XCIPHER(0xc02f, TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256) #endif -#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA - CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) #else - XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) + XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) #endif -#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA - CIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA) +#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) #else - XCIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA) + XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) #endif -#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA - CIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA) +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA + CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) #else - XCIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA) + XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) #endif -#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA - CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA + CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) #else - XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) + XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA) #endif -#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA - CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) +#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA + CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) #else - XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) + XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) #endif #ifdef TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA CIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA) #else XCIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA) #endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) -#endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA CIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA) #else XCIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA) #endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA - CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) -#else - XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA - CIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA) -#else - XCIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA) -#endif #ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) #else @@ -94,89 +59,63 @@ #else XCIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA) #endif -#ifdef TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA - CIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA) -#else - XCIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA) -#endif -#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA - CIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA) -#else - XCIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA) -#endif -#ifdef TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA - CIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA) -#else - XCIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA) -#endif -#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA - CIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA) +#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) #else - XCIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA) + XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA) #endif -#ifdef TLS1_TXT_RSA_WITH_SEED_SHA - CIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA) +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA + CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) #else - XCIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA) + XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) #endif -#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA - CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) +#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA + CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) #else - XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) + XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA) #endif -#ifdef SSL3_TXT_RSA_RC4_128_MD5 - CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) +#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) #else - XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) + XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA) #endif -#ifdef SSL3_TXT_RSA_RC4_128_SHA - CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) +#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA + CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) #else - XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) + XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) #endif #ifdef TLS1_TXT_RSA_WITH_AES_128_SHA CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) #else XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA) #endif -#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA - CIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA) -#else - XCIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA) -#endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA - CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) -#else - XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA) -#endif -#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA - CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) +#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA + CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) #else - XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) + XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA) #endif -#ifdef SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA - CIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA) +#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA + CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) #else - XCIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA) + XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA) #endif -#ifdef TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA - CIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA) +#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA + CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) #else - XCIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA) + XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA) #endif -#ifdef TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA - CIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA) +#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA + CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) #else - XCIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA) + XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) #endif -/* No openssl macro found for 0xfeff */ -#ifdef SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA - CIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA) +#ifdef SSL3_TXT_RSA_RC4_128_SHA + CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) #else - XCIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA) + XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA) #endif -#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA - CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) +#ifdef SSL3_TXT_RSA_RC4_128_MD5 + CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) #else - XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA) + XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5) #endif diff --git a/src/common/compat.c b/src/common/compat.c index 135f2c9af6..04c9d59235 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -560,21 +560,29 @@ tor_memmem(const void *_haystack, size_t hlen, #else /* This isn't as fast as the GLIBC implementation, but it doesn't need to * be. */ - const char *p, *end; + const char *p, *last_possible_start; const char *haystack = (const char*)_haystack; const char *needle = (const char*)_needle; char first; tor_assert(nlen); + if (nlen > hlen) + return NULL; + p = haystack; - end = haystack + hlen; + /* Last position at which the needle could start. */ + last_possible_start = haystack + hlen - nlen; first = *(const char*)needle; - while ((p = memchr(p, first, end-p))) { - if (p+nlen > end) - return NULL; + while ((p = memchr(p, first, last_possible_start + 1 - p))) { if (fast_memeq(p, needle, nlen)) return p; - ++p; + if (++p > last_possible_start) { + /* This comparison shouldn't be necessary, since if p was previously + * equal to last_possible_start, the next memchr call would be + * "memchr(p, first, 0)", which will return NULL. But it clarifies the + * logic. */ + return NULL; + } } return NULL; #endif diff --git a/src/common/gen_server_ciphers.py b/src/common/gen_server_ciphers.py new file mode 100755 index 0000000000..97ed9d0469 --- /dev/null +++ b/src/common/gen_server_ciphers.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# Copyright 2014, The Tor Project, Inc +# See LICENSE for licensing information + +# This script parses openssl headers to find ciphersuite names, determines +# which ones we should be willing to use as a server, and sorts them according +# to preference rules. +# +# Run it on all the files in your openssl include directory. + +import re +import sys + +EPHEMERAL_INDICATORS = [ "_EDH_", "_DHE_", "_ECDHE_" ] +BAD_STUFF = [ "_DES_40_", "MD5", "_RC4_", "_DES_64_", + "_SEED_", "_CAMELLIA_", "_NULL" ] + +# these never get #ifdeffed. +MANDATORY = [ + "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA", + "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA", + "SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA", +] + +def find_ciphers(filename): + with open(filename) as f: + for line in f: + m = re.search(r'(?:SSL3|TLS1)_TXT_\w+', line) + if m: + yield m.group(0) + +def usable_cipher(ciph): + ephemeral = False + for e in EPHEMERAL_INDICATORS: + if e in ciph: + ephemeral = True + if not ephemeral: + return False + + if "_RSA_" not in ciph: + return False + + for b in BAD_STUFF: + if b in ciph: + return False + return True + +# All fields we sort on, in order of priority. +FIELDS = [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ] +# Map from sorted fields to recognized value in descending order of goodness +FIELD_VALS = { 'cipher' : [ 'AES', 'DES'], + 'fwsec' : [ 'ECDHE', 'DHE' ], + 'mode' : [ 'GCM', 'CBC' ], + 'digest' : [ 'SHA384', 'SHA256', 'SHA' ], + 'bitlength' : [ '256', '128', '192' ], +} + +class Ciphersuite(object): + def __init__(self, name, fwsec, cipher, bitlength, mode, digest): + self.name = name + self.fwsec = fwsec + self.cipher = cipher + self.bitlength = bitlength + self.mode = mode + self.digest = digest + + for f in FIELDS: + assert(getattr(self, f) in FIELD_VALS[f]) + + def sort_key(self): + return tuple(FIELD_VALS[f].index(getattr(self,f)) for f in FIELDS) + + +def parse_cipher(ciph): + m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph) + + if not m: + print "/* Couldn't parse %s ! */"%ciph + return None + + fwsec, cipher, bits, mode, digest = m.groups() + if fwsec == 'EDH': + fwsec = 'DHE' + + if mode in [ '_CBC3', '_CBC', '' ]: + mode = 'CBC' + elif mode == '_GCM': + mode = 'GCM' + + return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest) + +ALL_CIPHERS = [] + +for fname in sys.argv[1:]: + ALL_CIPHERS += (parse_cipher(c) + for c in find_ciphers(fname) + if usable_cipher(c) ) + +ALL_CIPHERS.sort(key=Ciphersuite.sort_key) + +for c in ALL_CIPHERS: + if c is ALL_CIPHERS[-1]: + colon = ';' + else: + colon = ' ":"' + + if c.name in MANDATORY: + print " /* Required */" + print ' %s%s'%(c.name,colon) + else: + print "#ifdef %s"%c.name + print ' %s%s'%(c.name,colon) + print "#endif" + + diff --git a/src/common/get_mozilla_ciphers.py b/src/common/get_mozilla_ciphers.py index c7e9a84a0e..0636eb3658 100644 --- a/src/common/get_mozilla_ciphers.py +++ b/src/common/get_mozilla_ciphers.py @@ -41,12 +41,12 @@ fileA = open(ff('security/manager/ssl/src/nsNSSComponent.cpp'),'r') inCipherSection = False cipherLines = [] for line in fileA: - if line.startswith('static CipherPref CipherPrefs'): + if line.startswith('static const CipherPref sCipherPrefs[]'): # Get the starting boundary of the Cipher Preferences inCipherSection = True elif inCipherSection: line = line.strip() - if line.startswith('{NULL, 0}'): + if line.startswith('{ nullptr, 0}'): # At the ending boundary of the Cipher Prefs break else: @@ -56,12 +56,30 @@ fileA.close() # Parse the lines and put them into a dict ciphers = {} cipher_pref = {} +key_pending = None for line in cipherLines: - m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S*)\s*}', line) + m = re.search(r'^{\s*\"([^\"]+)\",\s*(\S+)\s*(?:,\s*(true|false))?\s*}', line) if m: - key,value = m.groups() - ciphers[key] = value - cipher_pref[value] = key + assert not key_pending + key,value,enabled = m.groups() + if enabled == 'true': + ciphers[key] = value + cipher_pref[value] = key + continue + m = re.search(r'^{\s*\"([^\"]+)\",', line) + if m: + assert not key_pending + key_pending = m.group(1) + continue + m = re.search(r'^\s*(\S+)(?:,\s*(true|false))?\s*}', line) + if m: + assert key_pending + key = key_pending + value,enabled = m.groups() + key_pending = None + if enabled == 'true': + ciphers[key] = value + cipher_pref[value] = key #### # Now find the correct order for the ciphers diff --git a/src/common/log.c b/src/common/log.c index a837cf86a7..592dc2c5d4 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -147,9 +147,6 @@ static INLINE char *format_msg(char *buf, size_t buf_len, const char *suffix, const char *format, va_list ap, size_t *msg_len_out) CHECK_PRINTF(7,0); -static void logv(int severity, log_domain_mask_t domain, const char *funcname, - const char *suffix, const char *format, va_list ap) - CHECK_PRINTF(5,0); /** Name of the application: used to generate the message we write at the * start of each new log. */ @@ -336,9 +333,9 @@ format_msg(char *buf, size_t buf_len, * <b>severity</b>. If provided, <b>funcname</b> is prepended to the * message. The actual message is derived as from tor_snprintf(format,ap). */ -static void -logv(int severity, log_domain_mask_t domain, const char *funcname, - const char *suffix, const char *format, va_list ap) +MOCK_IMPL(STATIC void, +logv,(int severity, log_domain_mask_t domain, const char *funcname, + const char *suffix, const char *format, va_list ap)) { char buf[10024]; size_t msg_len = 0; diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 5775289882..0548f3edd4 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -56,6 +56,17 @@ #include <time.h> #include <poll.h> +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ + defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) +#define USE_BACKTRACE +#define EXPOSE_CLEAN_BACKTRACE +#include "backtrace.h" +#endif + +#ifdef USE_BACKTRACE +#include <execinfo.h> +#endif + /**Determines if at least one sandbox is active.*/ static int sandbox_active = 0; /** Holds the parameter list configuration for the sandbox.*/ @@ -119,6 +130,7 @@ static int filter_nopar_gen[] = { SCMP_SYS(stat), SCMP_SYS(uname), SCMP_SYS(write), + SCMP_SYS(writev), SCMP_SYS(exit_group), SCMP_SYS(exit), @@ -1307,6 +1319,11 @@ install_syscall_filter(sandbox_cfg_t* cfg) return (rc < 0 ? -rc : rc); } +#ifdef USE_BACKTRACE +#define MAX_DEPTH 256 +static void *syscall_cb_buf[MAX_DEPTH]; +#endif + /** * 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 @@ -1318,6 +1335,12 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) ucontext_t *ctx = (ucontext_t *) (void_context); char number[32]; int syscall; +#ifdef USE_BACKTRACE + int depth; + int n_fds, i; + const int *fds = NULL; +#endif + (void) nr; if (info->si_code != SYS_SECCOMP) @@ -1328,12 +1351,25 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) syscall = (int) ctx->uc_mcontext.gregs[REG_SYSCALL]; +#ifdef USE_BACKTRACE + depth = backtrace(syscall_cb_buf, MAX_DEPTH); + /* Clean up the top stack frame so we get the real function + * name for the most recently failing function. */ + clean_backtrace(syscall_cb_buf, depth, ctx); +#endif + format_dec_number_sigsafe(syscall, number, sizeof(number)); tor_log_err_sigsafe("(Sandbox) Caught a bad syscall attempt (syscall ", number, ")\n", NULL); +#ifdef USE_BACKTRACE + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i=0; i < n_fds; ++i) + backtrace_symbols_fd(syscall_cb_buf, depth, fds[i]); +#endif + #if defined(DEBUGGING_CLOSE) _exit(1); #endif // DEBUGGING_CLOSE diff --git a/src/common/torlog.h b/src/common/torlog.h index d210c8b249..4493b251d2 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -13,6 +13,7 @@ #ifndef TOR_TORLOG_H #include "compat.h" +#include "testsupport.h" #ifdef HAVE_SYSLOG_H #include <syslog.h> @@ -228,6 +229,12 @@ extern const char *log_fn_function_name_; #endif /* !GNUC */ +#ifdef LOG_PRIVATE +MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, + va_list ap) CHECK_PRINTF(5,0)); +#endif + # define TOR_TORLOG_H #endif diff --git a/src/common/tortls.c b/src/common/tortls.c index 9ba8fd683e..dbe8cdcef4 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -712,31 +712,47 @@ tor_tls_create_certificate(crypto_pk_t *rsa, /** List of ciphers that servers should select from when we actually have * our choice of what cipher to use. */ const char UNRESTRICTED_SERVER_CIPHER_LIST[] = -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CHC_SHA - TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" -#endif + /* This list is autogenerated with the gen_server_ciphers.py script; + * don't hand-edit it. */ #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ":" #endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ":" +#endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 + TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 ":" +#endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 ":" #endif +#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA + TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA ":" +#endif #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA ":" #endif -#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 + TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 ":" +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 + TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 ":" +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 ":" +#endif +#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 ":" #endif -//#if TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA -// TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA ":" -//#endif - /* These next two are mandatory. */ - TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" + /* Required */ + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" + /* Required */ + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" #ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":" #endif - SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA; + /* Required */ + SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA; /* Note: to set up your own private testing network with link crypto * disabled, set your Tors' cipher list to @@ -2563,8 +2579,8 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) /** Return a ratio of the bytes that TLS has sent to the bytes that we've told * it to send. Used to track whether our TLS records are getting too tiny. */ -double -tls_get_write_overhead_ratio(void) +MOCK_IMPL(double, +tls_get_write_overhead_ratio,(void)) { if (total_bytes_written_over_tls == 0) return 1.0; diff --git a/src/common/tortls.h b/src/common/tortls.h index 49c488b365..a76ba3bc7a 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -13,6 +13,7 @@ #include "crypto.h" #include "compat.h" +#include "testsupport.h" /* Opaque structure to hold a TLS connection. */ typedef struct tor_tls_t tor_tls_t; @@ -95,7 +96,7 @@ void tor_tls_get_buffer_sizes(tor_tls_t *tls, size_t *rbuf_capacity, size_t *rbuf_bytes, size_t *wbuf_capacity, size_t *wbuf_bytes); -double tls_get_write_overhead_ratio(void); +MOCK_DECL(double, tls_get_write_overhead_ratio, (void)); int tor_tls_used_v1_handshake(tor_tls_t *tls); int tor_tls_received_v3_certificate(tor_tls_t *tls); diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c index 2a96f28815..c247886038 100644 --- a/src/ext/csiphash.c +++ b/src/ext/csiphash.c @@ -46,6 +46,10 @@ #elif defined(__APPLE__) # include <libkern/OSByteOrder.h> # define _le64toh(x) OSSwapLittleToHostInt64(x) +#elif defined(sun) || defined(__sun) +# include <sys/byteorder.h> +# define _le64toh(x) LE_64(x) + #else /* See: http://sourceforge.net/p/predef/wiki/Endianness/ */ diff --git a/src/ext/eventdns.c b/src/ext/eventdns.c index 5ac9c1230c..2b2988f1ec 100644 --- a/src/ext/eventdns.c +++ b/src/ext/eventdns.c @@ -842,10 +842,11 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, size_t name_out_len } if (label_len > 63) return -1; if (cp != name_out) { - if (cp + 1 >= end) return -1; + if (cp >= name_out + name_out_len - 1) return -1; *cp++ = '.'; } - if (cp + label_len >= end) return -1; + if (label_len > name_out_len || + cp >= name_out + name_out_len - label_len) return -1; memcpy(cp, packet + j, label_len); cp += label_len; j += label_len; diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 959ec47449..539ead193e 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -1282,7 +1282,6 @@ static void channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) { int highest_supported_version = 0; - const uint8_t *cp, *end; int started_here = 0; tor_assert(cell); @@ -1322,11 +1321,15 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) } tor_assert(chan->conn->handshake_state); - end = cell->payload + cell->payload_len; - for (cp = cell->payload; cp+1 < end; cp += 2) { - uint16_t v = ntohs(get_uint16(cp)); - if (is_or_protocol_version_known(v) && v > highest_supported_version) - highest_supported_version = v; + + { + int i; + const uint8_t *cp = cell->payload; + for (i = 0; i < cell->payload_len / 2; ++i, cp += 2) { + uint16_t v = ntohs(get_uint16(cp)); + if (is_or_protocol_version_known(v) && v > highest_supported_version) + highest_supported_version = v; + } } if (!highest_supported_version) { log_fn(LOG_PROTOCOL_WARN, LD_OR, @@ -1685,12 +1688,16 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan) for (i = 0; i < n_certs; ++i) { uint8_t cert_type; uint16_t cert_len; - if (ptr + 3 > cell->payload + cell->payload_len) { + if (cell->payload_len < 3) + goto truncated; + if (ptr > cell->payload + cell->payload_len - 3) { goto truncated; } cert_type = *ptr; cert_len = ntohs(get_uint16(ptr+1)); - if (ptr + 3 + cert_len > cell->payload + cell->payload_len) { + if (cell->payload_len < 3 + cert_len) + goto truncated; + if (ptr > cell->payload + cell->payload_len - cert_len - 3) { goto truncated; } if (cert_type == OR_CERT_TYPE_TLS_LINK || diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index b03b590aa5..b71dc3c13a 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -32,6 +32,7 @@ #include "rephist.h" #include "routerlist.h" #include "routerset.h" + #include "ht.h" /********* START VARIABLES **********/ @@ -45,6 +46,9 @@ static smartlist_t *circuits_pending_chans = NULL; static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); +//static void circuit_set_rend_token(or_circuit_t *circ, int is_rend_circ, +// const uint8_t *token); +static void circuit_clear_rend_token(or_circuit_t *circ); /********* END VARIABLES ************/ @@ -434,8 +438,8 @@ circuit_close_all_marked(void) } /** Return the head of the global linked list of circuits. */ -struct global_circuitlist_s * -circuit_get_global_list(void) +MOCK_IMPL(struct global_circuitlist_s *, +circuit_get_global_list,(void)) { return &global_circuitlist; } @@ -756,6 +760,8 @@ circuit_free(circuit_t *circ) crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); + circuit_clear_rend_token(ocirc); + if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->base_.magic == OR_CIRCUIT_MAGIC); @@ -1229,43 +1235,167 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, return NULL; } -/** Return the first OR circuit in the global list whose purpose is - * <b>purpose</b>, and whose rend_token is the <b>len</b>-byte - * <b>token</b>. */ +/** Map from rendezvous cookie to or_circuit_t */ +static digestmap_t *rend_cookie_map = NULL; + +/** Map from introduction point digest to or_circuit_t */ +static digestmap_t *intro_digest_map = NULL; + +/** Return the OR circuit whose purpose is <b>purpose</b>, and whose + * rend_token is the REND_TOKEN_LEN-byte <b>token</b>. If <b>is_rend_circ</b>, + * look for rendezvous point circuits; otherwise look for introduction point + * circuits. */ static or_circuit_t * -circuit_get_by_rend_token_and_purpose(uint8_t purpose, const char *token, - size_t len) +circuit_get_by_rend_token_and_purpose(uint8_t purpose, int is_rend_circ, + const char *token) { - circuit_t *circ; - TOR_LIST_FOREACH(circ, &global_circuitlist, head) { - if (! circ->marked_for_close && - circ->purpose == purpose && - tor_memeq(TO_OR_CIRCUIT(circ)->rend_token, token, len)) - return TO_OR_CIRCUIT(circ); + or_circuit_t *circ; + digestmap_t *map = is_rend_circ ? rend_cookie_map : intro_digest_map; + + if (!map) + return NULL; + + circ = digestmap_get(map, token); + if (!circ || + circ->base_.purpose != purpose || + circ->base_.marked_for_close) + return NULL; + + if (!circ->rendinfo || + ! bool_eq(circ->rendinfo->is_rend_circ, is_rend_circ) || + tor_memneq(circ->rendinfo->rend_token, token, REND_TOKEN_LEN)) { + char *t = tor_strdup(hex_str(token, REND_TOKEN_LEN)); + log_warn(LD_BUG, "Wanted a circuit with %s:%d, but lookup returned %s:%d", + safe_str(t), is_rend_circ, + safe_str(hex_str(circ->rendinfo->rend_token, REND_TOKEN_LEN)), + (int)circ->rendinfo->is_rend_circ); + tor_free(t); + return NULL; } - return NULL; + + return circ; +} + +/** Clear the rendezvous cookie or introduction point key digest that's + * configured on <b>circ</b>, if any, and remove it from any such maps. */ +static void +circuit_clear_rend_token(or_circuit_t *circ) +{ + or_circuit_t *found_circ; + digestmap_t *map; + + if (!circ || !circ->rendinfo) + return; + + map = circ->rendinfo->is_rend_circ ? rend_cookie_map : intro_digest_map; + + if (!map) { + log_warn(LD_BUG, "Tried to clear rend token on circuit, but found no map"); + return; + } + + found_circ = digestmap_get(map, circ->rendinfo->rend_token); + if (found_circ == circ) { + /* Great, this is the right one. */ + digestmap_remove(map, circ->rendinfo->rend_token); + } else if (found_circ) { + log_warn(LD_BUG, "Tried to clear rend token on circuit, but " + "it was already replaced in the map."); + } else { + log_warn(LD_BUG, "Tried to clear rend token on circuit, but " + "it not in the map at all."); + } + + tor_free(circ->rendinfo); /* Sets it to NULL too */ +} + +/** Set the rendezvous cookie (if is_rend_circ), or the introduction point + * digest (if ! is_rend_circ) of <b>circ</b> to the REND_TOKEN_LEN-byte value + * in <b>token</b>, and add it to the appropriate map. If it previously had a + * token, clear it. If another circuit previously had the same + * cookie/intro-digest, mark that circuit and remove it from the map. */ +static void +circuit_set_rend_token(or_circuit_t *circ, int is_rend_circ, + const uint8_t *token) +{ + digestmap_t **map_p, *map; + or_circuit_t *found_circ; + + /* Find the right map, creating it as needed */ + map_p = is_rend_circ ? &rend_cookie_map : &intro_digest_map; + + if (!*map_p) + *map_p = digestmap_new(); + + map = *map_p; + + /* If this circuit already has a token, we need to remove that. */ + if (circ->rendinfo) + circuit_clear_rend_token(circ); + + if (token == NULL) { + /* We were only trying to remove this token, not set a new one. */ + return; + } + + found_circ = digestmap_get(map, (const char *)token); + if (found_circ) { + tor_assert(found_circ != circ); + circuit_clear_rend_token(found_circ); + if (! found_circ->base_.marked_for_close) { + circuit_mark_for_close(TO_CIRCUIT(found_circ), END_CIRC_REASON_FINISHED); + if (is_rend_circ) { + log_fn(LOG_PROTOCOL_WARN, LD_REND, + "Duplicate rendezvous cookie (%s...) used on two circuits", + hex_str((const char*)token, 4)); /* only log first 4 chars */ + } + } + } + + /* Now set up the rendinfo */ + circ->rendinfo = tor_malloc(sizeof(*circ->rendinfo)); + memcpy(circ->rendinfo->rend_token, token, REND_TOKEN_LEN); + circ->rendinfo->is_rend_circ = is_rend_circ ? 1 : 0; + + digestmap_set(map, (const char *)token, circ); } /** Return the circuit waiting for a rendezvous with the provided cookie. * Return NULL if no such circuit is found. */ or_circuit_t * -circuit_get_rendezvous(const char *cookie) +circuit_get_rendezvous(const uint8_t *cookie) { return circuit_get_by_rend_token_and_purpose( CIRCUIT_PURPOSE_REND_POINT_WAITING, - cookie, REND_COOKIE_LEN); + 1, (const char*)cookie); } /** Return the circuit waiting for intro cells of the given digest. * Return NULL if no such circuit is found. */ or_circuit_t * -circuit_get_intro_point(const char *digest) +circuit_get_intro_point(const uint8_t *digest) { return circuit_get_by_rend_token_and_purpose( - CIRCUIT_PURPOSE_INTRO_POINT, digest, - DIGEST_LEN); + CIRCUIT_PURPOSE_INTRO_POINT, 0, + (const char *)digest); +} + +/** Set the rendezvous cookie of <b>circ</b> to <b>cookie</b>. If another + * circuit previously had that cookie, mark it. */ +void +circuit_set_rendezvous_cookie(or_circuit_t *circ, const uint8_t *cookie) +{ + circuit_set_rend_token(circ, 1, cookie); +} + +/** Set the intro point key digest of <b>circ</b> to <b>cookie</b>. If another + * circuit previously had that intro point digest, mark it. */ +void +circuit_set_intro_point_digest(or_circuit_t *circ, const uint8_t *digest) +{ + circuit_set_rend_token(circ, 0, digest); } /** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 54a7ef42fa..916afba215 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -16,7 +16,7 @@ TOR_LIST_HEAD(global_circuitlist_s, circuit_t); -struct global_circuitlist_s* circuit_get_global_list(void); +MOCK_DECL(struct global_circuitlist_s*, circuit_get_global_list, (void)); const char *circuit_state_to_string(int state); const char *circuit_purpose_to_controller_string(uint8_t purpose); const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); @@ -46,8 +46,10 @@ origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( const rend_data_t *rend_data); origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, const char *digest, uint8_t purpose); -or_circuit_t *circuit_get_rendezvous(const char *cookie); -or_circuit_t *circuit_get_intro_point(const char *digest); +or_circuit_t *circuit_get_rendezvous(const uint8_t *cookie); +or_circuit_t *circuit_get_intro_point(const uint8_t *digest); +void circuit_set_rendezvous_cookie(or_circuit_t *circ, const uint8_t *cookie); +void circuit_set_intro_point_digest(or_circuit_t *circ, const uint8_t *digest); origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index c093ecd269..e362b1b49e 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -12,6 +12,7 @@ #include "config.h" #include "confparse.h" #include "control.h" +#include "main.h" #include "networkstatus.h" #include "statefile.h" @@ -1185,6 +1186,12 @@ circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt) } /** + * How long should we be unreachable before we think we need to check if + * our published IP address has changed. + */ +#define CIRCUIT_TIMEOUT_BEFORE_RECHECK_IP (60*3) + +/** * Called to indicate that the network showed some signs of liveness, * i.e. we received a cell. * @@ -1199,12 +1206,15 @@ circuit_build_times_network_is_live(circuit_build_times_t *cbt) { time_t now = approx_time(); if (cbt->liveness.nonlive_timeouts > 0) { + time_t time_since_live = now - cbt->liveness.network_last_live; log_notice(LD_CIRC, "Tor now sees network activity. Restoring circuit build " "timeout recording. Network was down for %d seconds " "during %d circuit attempts.", - (int)(now - cbt->liveness.network_last_live), + (int)time_since_live, cbt->liveness.nonlive_timeouts); + if (time_since_live > CIRCUIT_TIMEOUT_BEFORE_RECHECK_IP) + reschedule_descriptor_update_check(); } cbt->liveness.network_last_live = now; cbt->liveness.nonlive_timeouts = 0; diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 8b82de0f99..75a10ba0c4 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -1515,7 +1515,7 @@ circuit_launch_by_extend_info(uint8_t purpose, circ = circuit_find_to_cannibalize(purpose, extend_info, flags); if (circ) { uint8_t old_purpose = circ->base_.purpose; - struct timeval old_timestamp_began; + struct timeval old_timestamp_began = circ->base_.timestamp_began; log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)", build_state_get_exit_nickname(circ->build_state), purpose, diff --git a/src/or/config.c b/src/or/config.c index 3179018fb6..23a63ccd24 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -620,8 +620,8 @@ get_options_mutable(void) } /** Returns the currently configured options */ -const or_options_t * -get_options(void) +MOCK_IMPL(const or_options_t *, +get_options,(void)) { return get_options_mutable(); } @@ -4548,18 +4548,11 @@ parse_bridge_line(const char *line) addrport = field; } - /* Parse addrport. */ - if (tor_addr_port_lookup(addrport, - &bridge_line->addr, &bridge_line->port)<0) { + if (tor_addr_port_parse(LOG_INFO, addrport, + &bridge_line->addr, &bridge_line->port, 443)<0) { log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport); goto err; } - if (!bridge_line->port) { - log_info(LD_CONFIG, - "Bridge address '%s' has no port; using default port 443.", - addrport); - 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 @@ -4810,7 +4803,7 @@ get_bindaddr_from_transport_listen_line(const char *line,const char *transport) goto err; /* Validate addrport */ - if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) { + if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) { log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr " "address '%s'", addrport); goto err; diff --git a/src/or/config.h b/src/or/config.h index 8ee2a45725..bf386134b8 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -12,8 +12,10 @@ #ifndef TOR_CONFIG_H #define TOR_CONFIG_H +#include "testsupport.h" + const char *get_dirportfrontpage(void); -const or_options_t *get_options(void); +MOCK_DECL(const or_options_t *,get_options,(void)); or_options_t *get_options_mutable(void); int set_options(or_options_t *new_val, char **msg); void config_free_all(void); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 04ad2cc008..6572a918e6 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -1195,6 +1195,12 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port, "your pluggable transport proxy stopped running.", fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port), transport_name, transport_name); + + control_event_bootstrap_problem( + "Can't connect to bridge", + END_OR_CONN_REASON_PT_MISSING, + conn); + } else { log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but " "the proxy address could not be found.", diff --git a/src/or/control.c b/src/or/control.c index 23e2054f9e..c91705257d 100644..100755 --- a/src/or/control.c +++ b/src/or/control.c @@ -2193,6 +2193,9 @@ static const getinfo_item_t getinfo_items[] = { "v3 Networkstatus consensus as retrieved from a DirPort."), ITEM("exit-policy/default", policies, "The default value appended to the configured exit policy."), + ITEM("exit-policy/full", policies, "The entire exit policy of onion router"), + ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"), + ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"), PREFIX("ip-to-country/", geoip, "Perform a GEOIP lookup"), { NULL, NULL, NULL, 0 } }; @@ -4884,7 +4887,7 @@ control_event_bootstrap(bootstrap_status_t status, int progress) */ MOCK_IMPL(void, control_event_bootstrap_problem, (const char *warn, int reason, - const or_connection_t *or_conn)) + or_connection_t *or_conn)) { int status = bootstrap_percent; const char *tag, *summary; @@ -4895,6 +4898,11 @@ MOCK_IMPL(void, /* bootstrap_percent must not be in "undefined" state here. */ tor_assert(status >= 0); + if (or_conn->have_noted_bootstrap_problem) + return; + + or_conn->have_noted_bootstrap_problem = 1; + if (bootstrap_percent == 100) return; /* already bootstrapped; nothing to be done here. */ diff --git a/src/or/control.h b/src/or/control.h index ce605a1208..988c171d7f 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -94,7 +94,7 @@ void monitor_owning_controller_process(const char *process_spec); void control_event_bootstrap(bootstrap_status_t status, int progress); MOCK_DECL(void, control_event_bootstrap_problem,(const char *warn, int reason, - const or_connection_t *or_conn)); + or_connection_t *or_conn)); void control_event_clients_seen(const char *controller_str); void control_event_transport_launched(const char *mode, diff --git a/src/or/dirserv.c b/src/or/dirserv.c index b6c5dd41f4..f5994e0318 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2578,14 +2578,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, tor_assert(private_key); tor_assert(cert); - if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { - log_warn(LD_NET, "Couldn't resolve my hostname"); - return NULL; - } - if (!hostname || !strchr(hostname, '.')) { - tor_free(hostname); - hostname = tor_dup_ip(addr); - } if (crypto_pk_get_digest(private_key, signing_key_digest)<0) { log_err(LD_BUG, "Error computing signing key digest"); return NULL; @@ -2594,6 +2586,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, log_err(LD_BUG, "Error computing identity key digest"); return NULL; } + if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) { + log_warn(LD_NET, "Couldn't resolve my hostname"); + return NULL; + } + if (!hostname || !strchr(hostname, '.')) { + tor_free(hostname); + hostname = tor_dup_ip(addr); + } if (options->VersioningAuthoritativeDir) { client_versions = format_versions_list(options->RecommendedClientVersions); diff --git a/src/or/dns.c b/src/or/dns.c index a88a46eb71..21c82e8062 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -1353,6 +1353,7 @@ inform_pending_connections(cached_resolve_t *resolve) } resolve->pending_connections = pend->next; tor_free(pend); + tor_free(hostname); } } diff --git a/src/or/hibernate.c b/src/or/hibernate.c index bbda8424f6..c433ac1be9 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -239,8 +239,8 @@ accounting_parse_options(const or_options_t *options, int validate_only) /** If we want to manage the accounting system and potentially * hibernate, return 1, else return 0. */ -int -accounting_is_enabled(const or_options_t *options) +MOCK_IMPL(int, +accounting_is_enabled,(const or_options_t *options)) { if (options->AccountingMax) return 1; @@ -256,8 +256,8 @@ accounting_get_interval_length(void) } /** Return the time at which the current accounting interval will end. */ -time_t -accounting_get_end_time(void) +MOCK_IMPL(time_t, +accounting_get_end_time,(void)) { return interval_end_time; } @@ -823,8 +823,8 @@ hibernate_begin_shutdown(void) } /** Return true iff we are currently hibernating. */ -int -we_are_hibernating(void) +MOCK_IMPL(int, +we_are_hibernating,(void)) { return hibernate_state != HIBERNATE_STATE_LIVE; } diff --git a/src/or/hibernate.h b/src/or/hibernate.h index 4f7331ce8c..38ecb75129 100644 --- a/src/or/hibernate.h +++ b/src/or/hibernate.h @@ -12,16 +12,18 @@ #ifndef TOR_HIBERNATE_H #define TOR_HIBERNATE_H +#include "testsupport.h" + int accounting_parse_options(const or_options_t *options, int validate_only); -int accounting_is_enabled(const or_options_t *options); +MOCK_DECL(int, accounting_is_enabled, (const or_options_t *options)); int accounting_get_interval_length(void); -time_t accounting_get_end_time(void); +MOCK_DECL(time_t, accounting_get_end_time, (void)); void configure_accounting(time_t now); void accounting_run_housekeeping(time_t now); void accounting_add_bytes(size_t n_read, size_t n_written, int seconds); int accounting_record_bandwidth_usage(time_t now, or_state_t *state); void hibernate_begin_shutdown(void); -int we_are_hibernating(void); +MOCK_DECL(int, we_are_hibernating, (void)); void consider_hibernation(time_t now); int getinfo_helper_accounting(control_connection_t *conn, const char *question, char **answer, diff --git a/src/or/main.c b/src/or/main.c index feca35c440..0264064edc 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -469,15 +469,15 @@ get_connection_array(void) /** Provides the traffic read and written over the life of the process. */ -uint64_t -get_bytes_read(void) +MOCK_IMPL(uint64_t, +get_bytes_read,(void)) { return stats_n_bytes_read; } /* DOCDOC get_bytes_written */ -uint64_t -get_bytes_written(void) +MOCK_IMPL(uint64_t, +get_bytes_written,(void)) { return stats_n_bytes_written; } @@ -919,16 +919,7 @@ conn_close_if_marked(int i) return 0; } if (connection_wants_to_flush(conn)) { - int severity; - if (conn->type == CONN_TYPE_EXIT || - (conn->type == CONN_TYPE_OR && server_mode(get_options())) || - (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER)) - severity = LOG_INFO; - else - severity = LOG_NOTICE; - /* XXXX Maybe allow this to happen a certain amount per hour; it usually - * is meaningless. */ - log_fn(severity, LD_NET, "We stalled too much while trying to write %d " + log_fn(LOG_INFO, LD_NET, "We stalled too much while trying to write %d " "bytes to address %s. If this happens a lot, either " "something is wrong with your network connection, or " "something is wrong with theirs. " @@ -1162,6 +1153,18 @@ get_signewnym_epoch(void) return newnym_epoch; } +static time_t time_to_check_descriptor = 0; +/** + * Update our schedule so that we'll check whether we need to update our + * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL + * seconds. + */ +void +reschedule_descriptor_update_check(void) +{ + time_to_check_descriptor = 0; +} + /** Perform regular maintenance tasks. This function gets run once per * second by second_elapsed_callback(). */ @@ -1171,7 +1174,6 @@ run_scheduled_events(time_t now) static time_t last_rotated_x509_certificate = 0; 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; @@ -2119,8 +2121,8 @@ process_signal(uintptr_t sig) } /** Returns Tor's uptime. */ -long -get_uptime(void) +MOCK_IMPL(long, +get_uptime,(void)) { return stats_n_seconds_working; } diff --git a/src/or/main.h b/src/or/main.h index df302ffa72..a3bce3486f 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -24,8 +24,8 @@ void add_connection_to_closeable_list(connection_t *conn); int connection_is_on_closeable_list(connection_t *conn); smartlist_t *get_connection_array(void); -uint64_t get_bytes_read(void); -uint64_t get_bytes_written(void); +MOCK_DECL(uint64_t,get_bytes_read,(void)); +MOCK_DECL(uint64_t,get_bytes_written,(void)); /** Bitmask for events that we can turn on and off with * connection_watch_events. */ @@ -50,8 +50,10 @@ void directory_info_has_arrived(time_t now, int from_cache); void ip_address_changed(int at_interface); void dns_servers_relaunch_checks(void); +void reschedule_descriptor_update_check(void); + +MOCK_DECL(long,get_uptime,(void)); -long get_uptime(void); unsigned get_signewnym_epoch(void); void handle_signals(int is_parent); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 74c4ca45a2..b8ac2e05fb 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -322,6 +322,17 @@ networkstatus_check_document_signature(const networkstatus_t *consensus, DIGEST_LEN)) return -1; + if (authority_cert_is_blacklisted(cert)) { + /* We implement blacklisting for authority signing keys by treating + * all their signatures as always bad. That way we don't get into + * crazy loops of dropping and re-fetching signatures. */ + log_warn(LD_DIR, "Ignoring a consensus signature made with deprecated" + " signing key %s", + hex_str(cert->signing_key_digest, DIGEST_LEN)); + sig->bad_signature = 1; + return 0; + } + signed_digest_len = crypto_pk_keysize(cert->signing_key); signed_digest = tor_malloc(signed_digest_len); if (crypto_pk_public_checksig(cert->signing_key, diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 52c92661c0..a38a6d4993 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -85,8 +85,8 @@ node_get_mutable_by_id(const char *identity_digest) /** Return the node_t whose identity is <b>identity_digest</b>, or NULL * if no such node exists. */ -const node_t * -node_get_by_id(const char *identity_digest) +MOCK_IMPL(const node_t *, +node_get_by_id,(const char *identity_digest)) { return node_get_mutable_by_id(identity_digest); } diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 95d0c23283..8e719e012d 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -17,7 +17,7 @@ } STMT_END node_t *node_get_mutable_by_id(const char *identity_digest); -const node_t *node_get_by_id(const char *identity_digest); +MOCK_DECL(const node_t *, node_get_by_id, (const char *identity_digest)); const node_t *node_get_by_hex_id(const char *identity_digest); node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out); node_t *nodelist_add_microdesc(microdesc_t *md); diff --git a/src/or/or.h b/src/or/or.h index 5510af723e..4ca7ecc605 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -604,7 +604,8 @@ typedef enum { #define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */ #define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */ #define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */ -#define END_OR_CONN_REASON_MISC 9 +#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */ +#define END_OR_CONN_REASON_MISC 10 /* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for * documentation of these. The values must match. */ @@ -1481,6 +1482,10 @@ typedef struct or_connection_t { unsigned int is_outgoing:1; unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ unsigned int wide_circ_ids:1; + /** True iff this connection has had its bootstrap failure logged with + * control_event_bootstrap_problem. */ + unsigned int have_noted_bootstrap_problem:1; + uint16_t link_proto; /**< What protocol version are we using? 0 for * "none negotiated yet." */ @@ -3173,20 +3178,8 @@ typedef struct or_circuit_t { * is not marked for close. */ struct or_circuit_t *rend_splice; -#if REND_COOKIE_LEN >= DIGEST_LEN -#define REND_TOKEN_LEN REND_COOKIE_LEN -#else -#define REND_TOKEN_LEN DIGEST_LEN -#endif + struct or_circuit_rendinfo_s *rendinfo; - /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a - * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes - * otherwise. - * ???? move to a subtype or adjunct structure? Wastes 20 bytes. -NM - */ - char rend_token[REND_TOKEN_LEN]; - - /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */ /** Stores KH for the handshake. */ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ @@ -3213,6 +3206,25 @@ typedef struct or_circuit_t { uint32_t max_middle_cells; } or_circuit_t; +typedef struct or_circuit_rendinfo_s { + +#if REND_COOKIE_LEN != DIGEST_LEN +#error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN" +#endif +#define REND_TOKEN_LEN DIGEST_LEN + + /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a + * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes + * otherwise. + */ + char rend_token[REND_TOKEN_LEN]; + + /** True if this is a rendezvous point circuit; false if this is an + * introduction point. */ + unsigned is_rend_circ; + +} or_circuit_rendinfo_t; + /** Convert a circuit subtype to a circuit_t. */ #define TO_CIRCUIT(x) (&((x)->base_)) diff --git a/src/or/policies.c b/src/or/policies.c index 42dc46b7fd..8a91509a77 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -13,6 +13,7 @@ #include "dirserv.h" #include "nodelist.h" #include "policies.h" +#include "router.h" #include "routerparse.h" #include "geoip.h" #include "ht.h" @@ -1692,6 +1693,28 @@ getinfo_helper_policies(control_connection_t *conn, (void) errmsg; if (!strcmp(question, "exit-policy/default")) { *answer = tor_strdup(DEFAULT_EXIT_POLICY); + } else if (!strcmpstart(question, "exit-policy/")) { + const routerinfo_t *me = router_get_my_routerinfo(); + + int include_ipv4 = 0; + int include_ipv6 = 0; + + if (!strcmp(question, "exit-policy/ipv4")) { + include_ipv4 = 1; + } else if (!strcmp(question, "exit-policy/ipv6")) { + include_ipv6 = 1; + } else if (!strcmp(question, "exit-policy/full")) { + include_ipv4 = include_ipv6 = 1; + } else { + return 0; /* No such key. */ + } + + if (!me) { + *errmsg = "router_get_my_routerinfo returned NULL"; + return -1; + } + + *answer = router_dump_exit_policy_to_string(me,include_ipv4,include_ipv6); } return 0; } diff --git a/src/or/reasons.c b/src/or/reasons.c index 0674474e72..750e89bbe7 100644 --- a/src/or/reasons.c +++ b/src/or/reasons.c @@ -231,6 +231,8 @@ orconn_end_reason_to_control_string(int r) return "RESOURCELIMIT"; case END_OR_CONN_REASON_MISC: return "MISC"; + case END_OR_CONN_REASON_PT_MISSING: + return "PT_MISSING"; case 0: return ""; default: diff --git a/src/or/rendmid.c b/src/or/rendmid.c index c68f6da597..1103816806 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -94,7 +94,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, /* Close any other intro circuits with the same pk. */ c = NULL; - while ((c = circuit_get_intro_point(pk_digest))) { + while ((c = circuit_get_intro_point((const uint8_t *)pk_digest))) { log_info(LD_REND, "Replacing old circuit for service %s", safe_str(serviceid)); circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED); @@ -111,7 +111,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, /* Now, set up this circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); - memcpy(circ->rend_token, pk_digest, DIGEST_LEN); + circuit_set_intro_point_digest(circ, (uint8_t *)pk_digest); log_info(LD_REND, "Established introduction point on circuit %u for service %s", @@ -165,7 +165,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, (char*)request, REND_SERVICE_ID_LEN); /* The first 20 bytes are all we look at: they have a hash of Bob's PK. */ - intro_circ = circuit_get_intro_point((char*)request); + intro_circ = circuit_get_intro_point((const uint8_t*)request); if (!intro_circ) { log_info(LD_REND, "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; " @@ -236,7 +236,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - if (circuit_get_rendezvous((char*)request)) { + if (circuit_get_rendezvous(request)) { log_warn(LD_PROTOCOL, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; @@ -252,7 +252,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); - memcpy(circ->rend_token, request, REND_COOKIE_LEN); + circuit_set_rendezvous_cookie(circ, request); base16_encode(hexid,9,(char*)request,4); @@ -300,7 +300,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, "Got request for rendezvous from circuit %u to cookie %s.", (unsigned)circ->p_circ_id, hexid); - rend_circ = circuit_get_rendezvous((char*)request); + rend_circ = circuit_get_rendezvous(request); if (!rend_circ) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", @@ -328,7 +328,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); circuit_change_purpose(TO_CIRCUIT(rend_circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); - memset(circ->rend_token, 0, REND_COOKIE_LEN); + circuit_set_rendezvous_cookie(circ, NULL); rend_circ->rend_splice = circ; circ->rend_splice = rend_circ; diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 500efaf208..abd78da73a 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -82,7 +82,7 @@ typedef struct rend_service_port_config_t { #define MAX_INTRO_CIRCS_PER_PERIOD 10 /** How many times will a hidden service operator attempt to connect to * a requested rendezvous point before giving up? */ -#define MAX_REND_FAILURES 30 +#define MAX_REND_FAILURES 8 /** How many seconds should we spend trying to connect to a requested * rendezvous point before giving up? */ #define MAX_REND_TIMEOUT 30 diff --git a/src/or/rephist.c b/src/or/rephist.c index 87f930a28d..70be39e230 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -2995,8 +2995,8 @@ rep_hist_conn_stats_write(time_t now) * handshake we've received, and how many we've assigned to cpuworkers. * Useful for seeing trends in cpu load. * @{ */ -static int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; -static int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; +STATIC int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; +STATIC int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1] = {0}; /**@}*/ /** A new onionskin (using the <b>type</b> handshake) has arrived. */ diff --git a/src/or/router.c b/src/or/router.c index 1f5df4b898..86cefc9a6f 100644..100755 --- a/src/or/router.c +++ b/src/or/router.c @@ -1348,8 +1348,8 @@ authdir_mode_bridge(const or_options_t *options) /** Return true iff we are trying to be a server. */ -int -server_mode(const or_options_t *options) +MOCK_IMPL(int, +server_mode,(const or_options_t *options)) { if (options->ClientOnly) return 0; /* XXXX024 I believe we can kill off ORListenAddress here.*/ @@ -1358,8 +1358,8 @@ server_mode(const or_options_t *options) /** Return true iff we are trying to be a non-bridge server. */ -int -public_server_mode(const or_options_t *options) +MOCK_IMPL(int, +public_server_mode,(const or_options_t *options)) { if (!server_mode(options)) return 0; return (!options->BridgeRelay); @@ -1689,8 +1689,8 @@ router_is_me(const routerinfo_t *router) /** Return a routerinfo for this OR, rebuilding a fresh one if * necessary. Return NULL on error, or if called on an OP. */ -const routerinfo_t * -router_get_my_routerinfo(void) +MOCK_IMPL(const routerinfo_t *, +router_get_my_routerinfo,(void)) { if (!server_mode(get_options())) return NULL; @@ -2398,20 +2398,13 @@ router_dump_router_to_string(routerinfo_t *router, if (!router->exit_policy || !smartlist_len(router->exit_policy)) { smartlist_add(chunks, tor_strdup("reject *:*\n")); } else if (router->exit_policy) { - int i; - for (i = 0; i < smartlist_len(router->exit_policy); ++i) { - char pbuf[POLICY_BUF_LEN]; - addr_policy_t *tmpe = smartlist_get(router->exit_policy, i); - int result; - if (tor_addr_family(&tmpe->addr) == AF_INET6) - continue; /* Don't include IPv6 parts of address policy */ - result = policy_write_item(pbuf, POLICY_BUF_LEN, tmpe, 1); - if (result < 0) { - log_warn(LD_BUG,"descriptor policy_write_item ran out of room!"); - goto err; - } - smartlist_add_asprintf(chunks, "%s\n", pbuf); - } + char *exit_policy = router_dump_exit_policy_to_string(router,1,0); + + if (!exit_policy) + goto err; + + smartlist_add_asprintf(chunks, "%s\n", exit_policy); + tor_free(exit_policy); } if (router->ipv6_exit_policy) { @@ -2479,6 +2472,56 @@ router_dump_router_to_string(routerinfo_t *router, return output; } +/** + * OR only: Given <b>router</b>, produce a string with its exit policy. + * If <b>include_ipv4</b> is true, include IPv4 entries. + * If <b>include_ipv6</b> is true, include IPv6 entries. + */ +char * +router_dump_exit_policy_to_string(const routerinfo_t *router, + int include_ipv4, + int include_ipv6) +{ + smartlist_t *exit_policy_strings; + char *policy_string = NULL; + + if ((!router->exit_policy) || (router->policy_is_reject_star)) { + return tor_strdup("reject *:*"); + } + + exit_policy_strings = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(router->exit_policy, addr_policy_t *, tmpe) { + char *pbuf; + int bytes_written_to_pbuf; + if ((tor_addr_family(&tmpe->addr) == AF_INET6) && (!include_ipv6)) { + continue; /* Don't include IPv6 parts of address policy */ + } + if ((tor_addr_family(&tmpe->addr) == AF_INET) && (!include_ipv4)) { + continue; /* Don't include IPv4 parts of address policy */ + } + + pbuf = tor_malloc(POLICY_BUF_LEN); + bytes_written_to_pbuf = policy_write_item(pbuf,POLICY_BUF_LEN, tmpe, 1); + + if (bytes_written_to_pbuf < 0) { + log_warn(LD_BUG, "router_dump_exit_policy_to_string ran out of room!"); + tor_free(pbuf); + goto done; + } + + smartlist_add(exit_policy_strings,pbuf); + } SMARTLIST_FOREACH_END(tmpe); + + policy_string = smartlist_join_strings(exit_policy_strings, "\n", 0, NULL); + + done: + SMARTLIST_FOREACH(exit_policy_strings, char *, str, tor_free(str)); + smartlist_free(exit_policy_strings); + + return policy_string; +} + /** Copy the primary (IPv4) OR port (IP address and TCP port) for * <b>router</b> into *<b>ap_out</b>. */ void diff --git a/src/or/router.h b/src/or/router.h index bf6cdbea33..d18ff065ea 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -66,8 +66,8 @@ uint16_t router_get_advertised_or_port_by_af(const or_options_t *options, uint16_t router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport); -int server_mode(const or_options_t *options); -int public_server_mode(const or_options_t *options); +MOCK_DECL(int, server_mode, (const or_options_t *options)); +MOCK_DECL(int, public_server_mode, (const or_options_t *options)); int advertised_server_mode(void); int proxy_mode(const or_options_t *options); void consider_publishable_server(int force); @@ -82,7 +82,7 @@ void router_new_address_suggestion(const char *suggestion, const dir_connection_t *d_conn); int router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port); int router_my_exit_policy_is_reject_star(void); -const routerinfo_t *router_get_my_routerinfo(void); +MOCK_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); extrainfo_t *router_get_my_extrainfo(void); const char *router_get_my_descriptor(void); const char *router_get_descriptor_gen_reason(void); @@ -94,6 +94,9 @@ int router_pick_published_address(const or_options_t *options, uint32_t *addr); int router_rebuild_descriptor(int force); char *router_dump_router_to_string(routerinfo_t *router, crypto_pk_t *ident_key); +char *router_dump_exit_policy_to_string(const routerinfo_t *router, + int include_ipv4, + int include_ipv6); void router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *addr_port_out); void router_get_pref_orport(const routerinfo_t *router, diff --git a/src/or/routerlist.c b/src/or/routerlist.c index f1bd12c193..c15274e991 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -98,7 +98,8 @@ static smartlist_t *trusted_dir_servers = NULL; * and all fallback directory servers. */ static smartlist_t *fallback_dir_servers = NULL; -/** List of for a given authority, and download status for latest certificate. +/** List of certificates for a single authority, and download status for + * latest certificate. */ struct cert_list_t { /* @@ -621,6 +622,37 @@ authority_cert_dl_failed(const char *id_digest, } } +static const char *BAD_SIGNING_KEYS[] = { + "09CD84F751FD6E955E0F8ADB497D5401470D697E", // Expires 2015-01-11 16:26:31 + "0E7E9C07F0969D0468AD741E172A6109DC289F3C", // Expires 2014-08-12 10:18:26 + "57B85409891D3FB32137F642FDEDF8B7F8CDFDCD", // Expires 2015-02-11 17:19:09 + "87326329007AF781F587AF5B594E540B2B6C7630", // Expires 2014-07-17 11:10:09 + "98CC82342DE8D298CF99D3F1A396475901E0D38E", // Expires 2014-11-10 13:18:56 + "9904B52336713A5ADCB13E4FB14DC919E0D45571", // Expires 2014-04-20 20:01:01 + "9DCD8E3F1DD1597E2AD476BBA28A1A89F3095227", // Expires 2015-01-16 03:52:30 + "A61682F34B9BB9694AC98491FE1ABBFE61923941", // Expires 2014-06-11 09:25:09 + "B59F6E99C575113650C99F1C425BA7B20A8C071D", // Expires 2014-07-31 13:22:10 + "D27178388FA75B96D37FA36E0B015227DDDBDA51", // Expires 2014-08-04 04:01:57 + NULL, +}; + +/** DOCDOC */ +int +authority_cert_is_blacklisted(const authority_cert_t *cert) +{ + char hex_digest[HEX_DIGEST_LEN+1]; + int i; + base16_encode(hex_digest, sizeof(hex_digest), + cert->signing_key_digest, sizeof(cert->signing_key_digest)); + + for (i = 0; BAD_SIGNING_KEYS[i]; ++i) { + if (!strcasecmp(hex_digest, BAD_SIGNING_KEYS[i])) { + return 1; + } + } + return 0; +} + /** Return true iff when we've been getting enough failures when trying to * download the certificate with ID digest <b>id_digest</b> that we're willing * to start bugging the user about it. */ diff --git a/src/or/routerlist.h b/src/or/routerlist.h index cfa8683861..6e2f2eaea0 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -43,6 +43,7 @@ int router_reload_router_list(void); int authority_cert_dl_looks_uncertain(const char *id_digest); const smartlist_t *router_get_trusted_dir_servers(void); const smartlist_t *router_get_fallback_dir_servers(void); +int authority_cert_is_blacklisted(const authority_cert_t *cert); const routerstatus_t *router_pick_directory_server(dirinfo_type_t type, int flags); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 7bf9a4d8e7..14f800e7be 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -2687,6 +2687,14 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, log_warn(LD_DIR,"Mismatch between identities in certificate and vote"); goto err; } + if (ns->type != NS_TYPE_CONSENSUS) { + if (authority_cert_is_blacklisted(ns->cert)) { + log_warn(LD_DIR, "Rejecting vote signature made with blacklisted " + "signing key %s", + hex_str(ns->cert->signing_key_digest, DIGEST_LEN)); + goto err; + } + } voter->address = tor_strdup(tok->args[2]); if (!tor_inet_aton(tok->args[3], &in)) { log_warn(LD_DIR, "Error decoding IP address %s in network-status.", diff --git a/src/or/status.c b/src/or/status.c index e1820c8889..7e2afbce80 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -6,6 +6,8 @@ * \brief Keep status information and log the heartbeat messages. **/ +#define STATUS_PRIVATE + #include "or.h" #include "config.h" #include "status.h" @@ -22,7 +24,7 @@ static void log_accounting(const time_t now, const or_options_t *options); /** Return the total number of circuits. */ -static int +STATIC int count_circuits(void) { circuit_t *circ; @@ -36,7 +38,7 @@ count_circuits(void) /** Take seconds <b>secs</b> and return a newly allocated human-readable * uptime string */ -static char * +STATIC char * secs_to_uptime(long secs) { long int days = secs / 86400; @@ -63,7 +65,7 @@ secs_to_uptime(long secs) /** Take <b>bytes</b> and returns a newly allocated human-readable usage * string. */ -static char * +STATIC char * bytes_to_usage(uint64_t bytes) { char *bw_string = NULL; diff --git a/src/or/status.h b/src/or/status.h index 7c3b969c86..13458ea476 100644 --- a/src/or/status.h +++ b/src/or/status.h @@ -4,7 +4,15 @@ #ifndef TOR_STATUS_H #define TOR_STATUS_H +#include "testsupport.h" + int log_heartbeat(time_t now); +#ifdef STATUS_PRIVATE +STATIC int count_circuits(void); +STATIC char *secs_to_uptime(long secs); +STATIC char *bytes_to_usage(uint64_t bytes); +#endif + #endif diff --git a/src/or/transports.c b/src/or/transports.c index 8b4a11882b..7e496fe219 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -1243,8 +1243,10 @@ create_managed_proxy_environment(const managed_proxy_t *mp) { char *orport_tmp = get_first_listener_addrport_string(CONN_TYPE_OR_LISTENER); - smartlist_add_asprintf(envs, "TOR_PT_ORPORT=%s", orport_tmp); - tor_free(orport_tmp); + if (orport_tmp) { + smartlist_add_asprintf(envs, "TOR_PT_ORPORT=%s", orport_tmp); + tor_free(orport_tmp); + } } { @@ -1275,8 +1277,10 @@ create_managed_proxy_environment(const managed_proxy_t *mp) get_first_listener_addrport_string(CONN_TYPE_EXT_OR_LISTENER); char *cookie_file_loc = get_ext_or_auth_cookie_file_name(); - smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s", - ext_or_addrport_tmp); + if (ext_or_addrport_tmp) { + smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s", + ext_or_addrport_tmp); + } smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s", cookie_file_loc); diff --git a/src/test/include.am b/src/test/include.am index c59ebb2ade..fba439a616 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -43,6 +43,8 @@ src_test_test_SOURCES = \ src/test/test_config.c \ src/test/test_hs.c \ src/test/test_nodelist.c \ + src/test/test_policy.c \ + src/test/test_status.c \ src/ext/tinytest.c src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) diff --git a/src/test/test.c b/src/test/test.c index 0e0fc6a4f3..771725e231 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -598,343 +598,6 @@ test_circuit_timeout(void) return; } -/* Helper: assert that short_policy parses and writes back out as itself, - or as <b>expected</b> if that's provided. */ -static void -test_short_policy_parse(const char *input, - const char *expected) -{ - short_policy_t *short_policy = NULL; - char *out = NULL; - - if (expected == NULL) - expected = input; - - short_policy = parse_short_policy(input); - tt_assert(short_policy); - out = write_short_policy(short_policy); - tt_str_op(out, ==, expected); - - done: - tor_free(out); - short_policy_free(short_policy); -} - -/** Helper: Parse the exit policy string in <b>policy_str</b>, and make sure - * that policies_summarize() produces the string <b>expected_summary</b> from - * it. */ -static void -test_policy_summary_helper(const char *policy_str, - const char *expected_summary) -{ - config_line_t line; - smartlist_t *policy = smartlist_new(); - char *summary = NULL; - char *summary_after = NULL; - int r; - short_policy_t *short_policy = NULL; - - line.key = (char*)"foo"; - line.value = (char *)policy_str; - line.next = NULL; - - r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1); - test_eq(r, 0); - summary = policy_summarize(policy, AF_INET); - - test_assert(summary != NULL); - test_streq(summary, expected_summary); - - short_policy = parse_short_policy(summary); - tt_assert(short_policy); - summary_after = write_short_policy(short_policy); - test_streq(summary, summary_after); - - done: - tor_free(summary_after); - tor_free(summary); - if (policy) - addr_policy_list_free(policy); - short_policy_free(short_policy); -} - -/** Run unit tests for generating summary lines of exit policies */ -static void -test_policies(void) -{ - int i; - smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL, - *policy4 = NULL, *policy5 = NULL, *policy6 = NULL, - *policy7 = NULL; - addr_policy_t *p; - tor_addr_t tar; - config_line_t line; - smartlist_t *sm = NULL; - char *policy_str = NULL; - short_policy_t *short_parsed = NULL; - - policy = smartlist_new(); - - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); - test_assert(p != NULL); - test_eq(ADDR_POLICY_REJECT, p->policy_type); - tor_addr_from_ipv4h(&tar, 0xc0a80000u); - test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT)); - test_eq(16, p->maskbits); - test_eq(1, p->prt_min); - test_eq(65535, p->prt_max); - - smartlist_add(policy, p); - - tor_addr_from_ipv4h(&tar, 0x01020304u); - test_assert(ADDR_POLICY_ACCEPTED == - compare_tor_addr_to_addr_policy(&tar, 2, policy)); - tor_addr_make_unspec(&tar); - test_assert(ADDR_POLICY_PROBABLY_ACCEPTED == - compare_tor_addr_to_addr_policy(&tar, 2, policy)); - tor_addr_from_ipv4h(&tar, 0xc0a80102); - test_assert(ADDR_POLICY_REJECTED == - compare_tor_addr_to_addr_policy(&tar, 2, policy)); - - test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1)); - test_assert(policy2); - - policy3 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject *:*",-1); - test_assert(p != NULL); - smartlist_add(policy3, p); - p = router_parse_addr_policy_item_from_string("accept *:*",-1); - test_assert(p != NULL); - smartlist_add(policy3, p); - - policy4 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); - test_assert(p != NULL); - smartlist_add(policy4, p); - p = router_parse_addr_policy_item_from_string("accept *:443",-1); - test_assert(p != NULL); - smartlist_add(policy4, p); - - policy5 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("reject *:65535",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1); - test_assert(p != NULL); - smartlist_add(policy5, p); - - policy6 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1); - test_assert(p != NULL); - smartlist_add(policy6, p); - - policy7 = smartlist_new(); - p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1); - test_assert(p != NULL); - smartlist_add(policy7, p); - - test_assert(!exit_policy_is_general_exit(policy)); - test_assert(exit_policy_is_general_exit(policy2)); - test_assert(!exit_policy_is_general_exit(NULL)); - test_assert(!exit_policy_is_general_exit(policy3)); - test_assert(!exit_policy_is_general_exit(policy4)); - test_assert(!exit_policy_is_general_exit(policy5)); - test_assert(!exit_policy_is_general_exit(policy6)); - test_assert(!exit_policy_is_general_exit(policy7)); - - test_assert(cmp_addr_policies(policy, policy2)); - test_assert(cmp_addr_policies(policy, NULL)); - test_assert(!cmp_addr_policies(policy2, policy2)); - test_assert(!cmp_addr_policies(NULL, NULL)); - - test_assert(!policy_is_reject_star(policy2, AF_INET)); - test_assert(policy_is_reject_star(policy, AF_INET)); - test_assert(policy_is_reject_star(NULL, AF_INET)); - - addr_policy_list_free(policy); - policy = NULL; - - /* make sure compacting logic works. */ - policy = NULL; - line.key = (char*)"foo"; - line.value = (char*)"accept *:80,reject private:*,reject *:*"; - line.next = NULL; - test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1)); - test_assert(policy); - //test_streq(policy->string, "accept *:80"); - //test_streq(policy->next->string, "reject *:*"); - test_eq(smartlist_len(policy), 4); - - /* test policy summaries */ - /* check if we properly ignore private IP addresses */ - test_policy_summary_helper("reject 192.168.0.0/16:*," - "reject 0.0.0.0/8:*," - "reject 10.0.0.0/8:*," - "accept *:10-30," - "accept *:90," - "reject *:*", - "accept 10-30,90"); - /* check all accept policies, and proper counting of rejects */ - test_policy_summary_helper("reject 11.0.0.0/9:80," - "reject 12.0.0.0/9:80," - "reject 13.0.0.0/9:80," - "reject 14.0.0.0/9:80," - "accept *:*", "accept 1-65535"); - test_policy_summary_helper("reject 11.0.0.0/9:80," - "reject 12.0.0.0/9:80," - "reject 13.0.0.0/9:80," - "reject 14.0.0.0/9:80," - "reject 15.0.0.0:81," - "accept *:*", "accept 1-65535"); - test_policy_summary_helper("reject 11.0.0.0/9:80," - "reject 12.0.0.0/9:80," - "reject 13.0.0.0/9:80," - "reject 14.0.0.0/9:80," - "reject 15.0.0.0:80," - "accept *:*", - "reject 80"); - /* no exits */ - test_policy_summary_helper("accept 11.0.0.0/9:80," - "reject *:*", - "reject 1-65535"); - /* port merging */ - test_policy_summary_helper("accept *:80," - "accept *:81," - "accept *:100-110," - "accept *:111," - "reject *:*", - "accept 80-81,100-111"); - /* border ports */ - test_policy_summary_helper("accept *:1," - "accept *:3," - "accept *:65535," - "reject *:*", - "accept 1,3,65535"); - /* holes */ - test_policy_summary_helper("accept *:1," - "accept *:3," - "accept *:5," - "accept *:7," - "reject *:*", - "accept 1,3,5,7"); - test_policy_summary_helper("reject *:1," - "reject *:3," - "reject *:5," - "reject *:7," - "accept *:*", - "reject 1,3,5,7"); - - /* Short policies with unrecognized formats should get accepted. */ - test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5"); - test_short_policy_parse("accept 2,fred,3", "accept 2,3"); - test_short_policy_parse("accept 2,fred,3,bob", "accept 2,3"); - test_short_policy_parse("accept 2,-3,500-600", "accept 2,500-600"); - /* Short policies with nil entries are accepted too. */ - test_short_policy_parse("accept 1,,3", "accept 1,3"); - test_short_policy_parse("accept 100-200,,", "accept 100-200"); - test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40"); - - /* Try parsing various broken short policies */ -#define TT_BAD_SHORT_POLICY(s) \ - do { \ - tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \ - } while (0) - TT_BAD_SHORT_POLICY("accept 200-199"); - TT_BAD_SHORT_POLICY(""); - TT_BAD_SHORT_POLICY("rejekt 1,2,3"); - TT_BAD_SHORT_POLICY("reject "); - TT_BAD_SHORT_POLICY("reject"); - TT_BAD_SHORT_POLICY("rej"); - TT_BAD_SHORT_POLICY("accept 2,3,100000"); - TT_BAD_SHORT_POLICY("accept 2,3x,4"); - TT_BAD_SHORT_POLICY("accept 2,3x,4"); - TT_BAD_SHORT_POLICY("accept 2-"); - TT_BAD_SHORT_POLICY("accept 2-x"); - TT_BAD_SHORT_POLICY("accept 1-,3"); - TT_BAD_SHORT_POLICY("accept 1-,3"); - - /* Test a too-long policy. */ - { - int i; - char *policy = NULL; - smartlist_t *chunks = smartlist_new(); - smartlist_add(chunks, tor_strdup("accept ")); - for (i=1; i<10000; ++i) - smartlist_add_asprintf(chunks, "%d,", i); - smartlist_add(chunks, tor_strdup("20000")); - policy = smartlist_join_strings(chunks, "", 0, NULL); - SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch)); - smartlist_free(chunks); - short_parsed = parse_short_policy(policy);/* shouldn't be accepted */ - tor_free(policy); - tt_ptr_op(NULL, ==, short_parsed); - } - - /* truncation ports */ - sm = smartlist_new(); - for (i=1; i<2000; i+=2) { - char buf[POLICY_BUF_LEN]; - tor_snprintf(buf, sizeof(buf), "reject *:%d", i); - smartlist_add(sm, tor_strdup(buf)); - } - smartlist_add(sm, tor_strdup("accept *:*")); - policy_str = smartlist_join_strings(sm, ",", 0, NULL); - test_policy_summary_helper( policy_str, - "accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44," - "46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90," - "92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128," - "130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164," - "166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200," - "202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236," - "238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272," - "274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308," - "310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344," - "346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380," - "382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416," - "418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452," - "454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488," - "490,492,494,496,498,500,502,504,506,508,510,512,514,516,518,520,522"); - - done: - addr_policy_list_free(policy); - addr_policy_list_free(policy2); - addr_policy_list_free(policy3); - addr_policy_list_free(policy4); - addr_policy_list_free(policy5); - addr_policy_list_free(policy6); - addr_policy_list_free(policy7); - tor_free(policy_str); - if (sm) { - SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); - smartlist_free(sm); - } - short_policy_free(short_parsed); -} - /** Test encoding and parsing of rendezvous service descriptors. */ static void test_rend_fns(void) @@ -1603,7 +1266,6 @@ static struct testcase_t test_array[] = { { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL }, #endif ENT(circuit_timeout), - ENT(policies), ENT(rend_fns), ENT(geoip), FORK(geoip_with_pt), @@ -1633,11 +1295,12 @@ extern struct testcase_t socks_tests[]; extern struct testcase_t extorport_tests[]; extern struct testcase_t controller_event_tests[]; extern struct testcase_t logging_tests[]; -extern struct testcase_t backtrace_tests[]; extern struct testcase_t hs_tests[]; extern struct testcase_t nodelist_tests[]; extern struct testcase_t routerkeys_tests[]; extern struct testcase_t oom_tests[]; +extern struct testcase_t policy_tests[]; +extern struct testcase_t status_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1666,6 +1329,8 @@ static struct testgroup_t testgroups[] = { { "nodelist/", nodelist_tests }, { "routerkeys/", routerkeys_tests }, { "oom/", oom_tests }, + { "policy/" , policy_tests }, + { "status/" , status_tests }, END_OF_GROUPS }; diff --git a/src/test/test.h b/src/test/test.h index ba82f52add..0ccf6c718e 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -65,5 +65,97 @@ crypto_pk_t *pk_generate(int idx); void legacy_test_helper(void *data); extern const struct testcase_setup_t legacy_setup; +#define US2_CONCAT_2__(a, b) a ## __ ## b +#define US_CONCAT_2__(a, b) a ## _ ## b +#define US_CONCAT_3__(a, b, c) a ## _ ## b ## _ ## c +#define US_CONCAT_2_(a, b) US_CONCAT_2__(a, b) +#define US_CONCAT_3_(a, b, c) US_CONCAT_3__(a, b, c) + +/* + * These macros are helpful for streamlining the authorship of several test + * cases that use mocks. + * + * The pattern is as follows. + * * Declare a top level namespace: + * #define NS_MODULE foo + * + * * For each test case you want to write, create a new submodule in the + * namespace. All mocks and other information should belong to a single + * submodule to avoid interference with other test cases. + * You can simply name the submodule after the function in the module you + * are testing: + * #define NS_SUBMODULE some_function + * or, if you're wanting to write several tests against the same function, + * ie., you are testing an aspect of that function, you can use: + * #define NS_SUBMODULE ASPECT(some_function, behavior) + * + * * Declare all the mocks you will use. The NS_DECL macro serves to declare + * the mock in the current namespace (defined by NS_MODULE and NS_SUBMODULE). + * It behaves like MOCK_DECL: + * NS_DECL(int, dependent_function, (void *)); + * Here, dependent_function must be declared and implemented with the + * MOCK_DECL and MOCK_IMPL macros. The NS_DECL macro also defines an integer + * global for use for tracking how many times a mock was called, and can be + * accessed by CALLED(mock_name). For example, you might put + * CALLED(dependent_function)++; + * in your mock body. + * + * * Define a function called NS(main) that will contain the body of the + * test case. The NS macro can be used to reference a name in the current + * namespace. + * + * * In NS(main), indicate that a mock function in the current namespace, + * declared with NS_DECL is to override that in the global namespace, + * with the NS_MOCK macro: + * NS_MOCK(dependent_function) + * Unmock with: + * NS_UNMOCK(dependent_function) + * + * * Define the mocks with the NS macro, eg., + * int + * NS(dependent_function)(void *) + * { + * CALLED(dependent_function)++; + * } + * + * * In the struct testcase_t array, you can use the TEST_CASE and + * TEST_CASE_ASPECT macros to define the cases without having to do so + * explicitly nor without having to reset NS_SUBMODULE, eg., + * struct testcase_t foo_tests[] = { + * TEST_CASE_ASPECT(some_function, behavior), + * ... + * END_OF_TESTCASES + * which will define a test case named "some_function__behavior". + */ + +#define NAME_TEST_(name) #name +#define NAME_TEST(name) NAME_TEST_(name) +#define ASPECT(test_module, test_name) US2_CONCAT_2__(test_module, test_name) +#define TEST_CASE(function) \ + { \ + NAME_TEST(function), \ + NS_FULL(NS_MODULE, function, test_main), \ + TT_FORK, \ + NULL, \ + NULL, \ + } +#define TEST_CASE_ASPECT(function, aspect) \ + { \ + NAME_TEST(ASPECT(function, aspect)), \ + NS_FULL(NS_MODULE, ASPECT(function, aspect), test_main), \ + TT_FORK, \ + NULL, \ + NULL, \ + } + +#define NS(name) US_CONCAT_3_(NS_MODULE, NS_SUBMODULE, name) +#define NS_FULL(module, submodule, name) US_CONCAT_3_(module, submodule, name) + +#define CALLED(mock_name) US_CONCAT_2_(NS(mock_name), called) +#define NS_DECL(retval, mock_fn, args) \ + static retval NS(mock_fn) args; int CALLED(mock_fn) = 0 +#define NS_MOCK(name) MOCK(name, NS(name)) +#define NS_UNMOCK(name) UNMOCK(name) + #endif diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 1c2a90e1ec..cee2dcf2a0 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -73,7 +73,7 @@ test_addr_basic(void) } done: - ; + tor_free(cp); } #define test_op_ip6_(a,op,b,e1,e2) \ @@ -743,42 +743,89 @@ test_addr_parse(void) /* Correct call. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.1:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == 0); tor_addr_to_str(buf, &addr, sizeof(buf), 0); test_streq(buf, "192.0.2.1"); test_eq(port, 1234); + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]:1234", + &addr, &port, -1); + test_assert(r == 0); + tor_addr_to_str(buf, &addr, sizeof(buf), 0); + test_streq(buf, "::1"); + test_eq(port, 1234); + /* Domain name. */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == -1); /* Only IP. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2", - &addr, &port); + &addr, &port, -1); test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,200); + + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]", + &addr, &port, -1); + test_assert(r == -1); + + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]", + &addr, &port, 400); + test_assert(r == 0); + tt_int_op(port,==,400); + /* Bad port. */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2.2:66666", - &addr, &port); + &addr, &port, -1); + test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2:66666", + &addr, &port, 200); test_assert(r == -1); /* Only domain name */ r= tor_addr_port_parse(LOG_DEBUG, "torproject.org", - &addr, &port); + &addr, &port, -1); + test_assert(r == -1); + r= tor_addr_port_parse(LOG_DEBUG, + "torproject.org", + &addr, &port, 200); test_assert(r == -1); /* Bad IP address */ r= tor_addr_port_parse(LOG_DEBUG, "192.0.2:1234", - &addr, &port); + &addr, &port, -1); test_assert(r == -1); + /* Make sure that the default port has lower priority than the real + one */ + r= tor_addr_port_parse(LOG_DEBUG, + "192.0.2.2:1337", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,1337); + + r= tor_addr_port_parse(LOG_DEBUG, + "[::1]:1369", + &addr, &port, 200); + test_assert(r == 0); + tt_int_op(port,==,1369); + done: ; } diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 54aa51d3c7..53cd41591f 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -161,8 +161,101 @@ test_clist_maps(void *arg) UNMOCK(circuitmux_detach_circuit); } +static void +test_rend_token_maps(void *arg) +{ + or_circuit_t *c1, *c2, *c3, *c4; + const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y"; + const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it "; + const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care."; + /* -- Adapted from a quote by Fredrik Lundh. */ + + (void)arg; + (void)tok1; //xxxx + c1 = or_circuit_new(0, NULL); + c2 = or_circuit_new(0, NULL); + c3 = or_circuit_new(0, NULL); + c4 = or_circuit_new(0, NULL); + + /* Make sure we really filled up the tok* variables */ + tt_int_op(tok1[REND_TOKEN_LEN-1], ==, 'y'); + tt_int_op(tok2[REND_TOKEN_LEN-1], ==, ' '); + tt_int_op(tok3[REND_TOKEN_LEN-1], ==, '.'); + + /* No maps; nothing there. */ + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1)); + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1)); + + circuit_set_rendezvous_cookie(c1, tok1); + circuit_set_intro_point_digest(c2, tok2); + + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok3)); + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3)); + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2)); + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1)); + + /* Without purpose set, we don't get the circuits */ + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1)); + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2)); + + c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; + c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; + + /* Okay, make sure they show up now. */ + tt_ptr_op(c1, ==, circuit_get_rendezvous(tok1)); + tt_ptr_op(c2, ==, circuit_get_intro_point(tok2)); + + /* Two items at the same place with the same token. */ + c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; + circuit_set_rendezvous_cookie(c3, tok2); + tt_ptr_op(c2, ==, circuit_get_intro_point(tok2)); + tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2)); + + /* Marking a circuit makes it not get returned any more */ + circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED); + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1)); + circuit_free(TO_CIRCUIT(c1)); + c1 = NULL; + + /* Freeing a circuit makes it not get returned any more. */ + circuit_free(TO_CIRCUIT(c2)); + c2 = NULL; + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2)); + + /* c3 -- are you still there? */ + tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2)); + /* Change its cookie. This never happens in Tor per se, but hey. */ + c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; + circuit_set_intro_point_digest(c3, tok3); + + tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2)); + tt_ptr_op(c3, ==, circuit_get_intro_point(tok3)); + + /* Now replace c3 with c4. */ + c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; + circuit_set_intro_point_digest(c4, tok3); + + tt_ptr_op(c4, ==, circuit_get_intro_point(tok3)); + + tt_ptr_op(c3->rendinfo, ==, NULL); + tt_ptr_op(c4->rendinfo, !=, NULL); + test_mem_op(c4->rendinfo, ==, tok3, REND_TOKEN_LEN); + + /* Now clear c4's cookie. */ + circuit_set_intro_point_digest(c4, NULL); + tt_ptr_op(c4->rendinfo, ==, NULL); + tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3)); + + done: + circuit_free(TO_CIRCUIT(c1)); + circuit_free(TO_CIRCUIT(c2)); + circuit_free(TO_CIRCUIT(c3)); + circuit_free(TO_CIRCUIT(c4)); +} + struct testcase_t circuitlist_tests[] = { { "maps", test_clist_maps, TT_FORK, NULL, NULL }, + { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_config.c b/src/test/test_config.c index 3a1e6cb78a..dbb50798b8 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -421,6 +421,23 @@ test_config_parse_bridge_line(void *arg) smartlist_free(sl_tmp); } + { + smartlist_t *sl_tmp = smartlist_new(); + smartlist_add_asprintf(sl_tmp, "dub=come"); + smartlist_add_asprintf(sl_tmp, "save=me"); + + good_bridge_line_test("transport 192.0.2.1:12 " + "4352e58420e68f5e40bf7c74faddccd9d1349666 " + "dub=come save=me", + + "192.0.2.1:12", + "4352e58420e68f5e40bf7c74faddccd9d1349666", + "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", diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index b34f5e38de..f91ac7415e 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -364,7 +364,7 @@ test_ext_or_cookie_auth_testvec(void *arg) static void ignore_bootstrap_problem(const char *warn, int reason, - const or_connection_t *conn) + or_connection_t *conn) { (void)warn; (void)reason; diff --git a/src/test/test_policy.c b/src/test/test_policy.c new file mode 100644 index 0000000000..d2ba1612de --- /dev/null +++ b/src/test/test_policy.c @@ -0,0 +1,432 @@ +/* Copyright (c) 2013, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "or.h" +#include "router.h" +#include "routerparse.h" +#include "policies.h" +#include "test.h" + +/* Helper: assert that short_policy parses and writes back out as itself, + or as <b>expected</b> if that's provided. */ +static void +test_short_policy_parse(const char *input, + const char *expected) +{ + short_policy_t *short_policy = NULL; + char *out = NULL; + + if (expected == NULL) + expected = input; + + short_policy = parse_short_policy(input); + tt_assert(short_policy); + out = write_short_policy(short_policy); + tt_str_op(out, ==, expected); + + done: + tor_free(out); + short_policy_free(short_policy); +} + +/** Helper: Parse the exit policy string in <b>policy_str</b>, and make sure + * that policies_summarize() produces the string <b>expected_summary</b> from + * it. */ +static void +test_policy_summary_helper(const char *policy_str, + const char *expected_summary) +{ + config_line_t line; + smartlist_t *policy = smartlist_new(); + char *summary = NULL; + char *summary_after = NULL; + int r; + short_policy_t *short_policy = NULL; + + line.key = (char*)"foo"; + line.value = (char *)policy_str; + line.next = NULL; + + r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1); + test_eq(r, 0); + summary = policy_summarize(policy, AF_INET); + + test_assert(summary != NULL); + test_streq(summary, expected_summary); + + short_policy = parse_short_policy(summary); + tt_assert(short_policy); + summary_after = write_short_policy(short_policy); + test_streq(summary, summary_after); + + done: + tor_free(summary_after); + tor_free(summary); + if (policy) + addr_policy_list_free(policy); + short_policy_free(short_policy); +} + +/** Run unit tests for generating summary lines of exit policies */ +static void +test_policies_general(void *arg) +{ + int i; + smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL, + *policy4 = NULL, *policy5 = NULL, *policy6 = NULL, + *policy7 = NULL; + addr_policy_t *p; + tor_addr_t tar; + config_line_t line; + smartlist_t *sm = NULL; + char *policy_str = NULL; + short_policy_t *short_parsed = NULL; + (void)arg; + + policy = smartlist_new(); + + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + test_assert(p != NULL); + test_eq(ADDR_POLICY_REJECT, p->policy_type); + tor_addr_from_ipv4h(&tar, 0xc0a80000u); + test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT)); + test_eq(16, p->maskbits); + test_eq(1, p->prt_min); + test_eq(65535, p->prt_max); + + smartlist_add(policy, p); + + tor_addr_from_ipv4h(&tar, 0x01020304u); + test_assert(ADDR_POLICY_ACCEPTED == + compare_tor_addr_to_addr_policy(&tar, 2, policy)); + tor_addr_make_unspec(&tar); + test_assert(ADDR_POLICY_PROBABLY_ACCEPTED == + compare_tor_addr_to_addr_policy(&tar, 2, policy)); + tor_addr_from_ipv4h(&tar, 0xc0a80102); + test_assert(ADDR_POLICY_REJECTED == + compare_tor_addr_to_addr_policy(&tar, 2, policy)); + + test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1)); + test_assert(policy2); + + policy3 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("reject *:*",-1); + test_assert(p != NULL); + smartlist_add(policy3, p); + p = router_parse_addr_policy_item_from_string("accept *:*",-1); + test_assert(p != NULL); + smartlist_add(policy3, p); + + policy4 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("accept *:443",-1); + test_assert(p != NULL); + smartlist_add(policy4, p); + p = router_parse_addr_policy_item_from_string("accept *:443",-1); + test_assert(p != NULL); + smartlist_add(policy4, p); + + policy5 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("reject *:65535",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1); + test_assert(p != NULL); + smartlist_add(policy5, p); + + policy6 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1); + test_assert(p != NULL); + smartlist_add(policy6, p); + + policy7 = smartlist_new(); + p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1); + test_assert(p != NULL); + smartlist_add(policy7, p); + + test_assert(!exit_policy_is_general_exit(policy)); + test_assert(exit_policy_is_general_exit(policy2)); + test_assert(!exit_policy_is_general_exit(NULL)); + test_assert(!exit_policy_is_general_exit(policy3)); + test_assert(!exit_policy_is_general_exit(policy4)); + test_assert(!exit_policy_is_general_exit(policy5)); + test_assert(!exit_policy_is_general_exit(policy6)); + test_assert(!exit_policy_is_general_exit(policy7)); + + test_assert(cmp_addr_policies(policy, policy2)); + test_assert(cmp_addr_policies(policy, NULL)); + test_assert(!cmp_addr_policies(policy2, policy2)); + test_assert(!cmp_addr_policies(NULL, NULL)); + + test_assert(!policy_is_reject_star(policy2, AF_INET)); + test_assert(policy_is_reject_star(policy, AF_INET)); + test_assert(policy_is_reject_star(NULL, AF_INET)); + + addr_policy_list_free(policy); + policy = NULL; + + /* make sure compacting logic works. */ + policy = NULL; + line.key = (char*)"foo"; + line.value = (char*)"accept *:80,reject private:*,reject *:*"; + line.next = NULL; + test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1)); + test_assert(policy); + //test_streq(policy->string, "accept *:80"); + //test_streq(policy->next->string, "reject *:*"); + test_eq(smartlist_len(policy), 4); + + /* test policy summaries */ + /* check if we properly ignore private IP addresses */ + test_policy_summary_helper("reject 192.168.0.0/16:*," + "reject 0.0.0.0/8:*," + "reject 10.0.0.0/8:*," + "accept *:10-30," + "accept *:90," + "reject *:*", + "accept 10-30,90"); + /* check all accept policies, and proper counting of rejects */ + test_policy_summary_helper("reject 11.0.0.0/9:80," + "reject 12.0.0.0/9:80," + "reject 13.0.0.0/9:80," + "reject 14.0.0.0/9:80," + "accept *:*", "accept 1-65535"); + test_policy_summary_helper("reject 11.0.0.0/9:80," + "reject 12.0.0.0/9:80," + "reject 13.0.0.0/9:80," + "reject 14.0.0.0/9:80," + "reject 15.0.0.0:81," + "accept *:*", "accept 1-65535"); + test_policy_summary_helper("reject 11.0.0.0/9:80," + "reject 12.0.0.0/9:80," + "reject 13.0.0.0/9:80," + "reject 14.0.0.0/9:80," + "reject 15.0.0.0:80," + "accept *:*", + "reject 80"); + /* no exits */ + test_policy_summary_helper("accept 11.0.0.0/9:80," + "reject *:*", + "reject 1-65535"); + /* port merging */ + test_policy_summary_helper("accept *:80," + "accept *:81," + "accept *:100-110," + "accept *:111," + "reject *:*", + "accept 80-81,100-111"); + /* border ports */ + test_policy_summary_helper("accept *:1," + "accept *:3," + "accept *:65535," + "reject *:*", + "accept 1,3,65535"); + /* holes */ + test_policy_summary_helper("accept *:1," + "accept *:3," + "accept *:5," + "accept *:7," + "reject *:*", + "accept 1,3,5,7"); + test_policy_summary_helper("reject *:1," + "reject *:3," + "reject *:5," + "reject *:7," + "accept *:*", + "reject 1,3,5,7"); + + /* Short policies with unrecognized formats should get accepted. */ + test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5"); + test_short_policy_parse("accept 2,fred,3", "accept 2,3"); + test_short_policy_parse("accept 2,fred,3,bob", "accept 2,3"); + test_short_policy_parse("accept 2,-3,500-600", "accept 2,500-600"); + /* Short policies with nil entries are accepted too. */ + test_short_policy_parse("accept 1,,3", "accept 1,3"); + test_short_policy_parse("accept 100-200,,", "accept 100-200"); + test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40"); + + /* Try parsing various broken short policies */ +#define TT_BAD_SHORT_POLICY(s) \ + do { \ + tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \ + } while (0) + TT_BAD_SHORT_POLICY("accept 200-199"); + TT_BAD_SHORT_POLICY(""); + TT_BAD_SHORT_POLICY("rejekt 1,2,3"); + TT_BAD_SHORT_POLICY("reject "); + TT_BAD_SHORT_POLICY("reject"); + TT_BAD_SHORT_POLICY("rej"); + TT_BAD_SHORT_POLICY("accept 2,3,100000"); + TT_BAD_SHORT_POLICY("accept 2,3x,4"); + TT_BAD_SHORT_POLICY("accept 2,3x,4"); + TT_BAD_SHORT_POLICY("accept 2-"); + TT_BAD_SHORT_POLICY("accept 2-x"); + TT_BAD_SHORT_POLICY("accept 1-,3"); + TT_BAD_SHORT_POLICY("accept 1-,3"); + + /* Test a too-long policy. */ + { + int i; + char *policy = NULL; + smartlist_t *chunks = smartlist_new(); + smartlist_add(chunks, tor_strdup("accept ")); + for (i=1; i<10000; ++i) + smartlist_add_asprintf(chunks, "%d,", i); + smartlist_add(chunks, tor_strdup("20000")); + policy = smartlist_join_strings(chunks, "", 0, NULL); + SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch)); + smartlist_free(chunks); + short_parsed = parse_short_policy(policy);/* shouldn't be accepted */ + tor_free(policy); + tt_ptr_op(NULL, ==, short_parsed); + } + + /* truncation ports */ + sm = smartlist_new(); + for (i=1; i<2000; i+=2) { + char buf[POLICY_BUF_LEN]; + tor_snprintf(buf, sizeof(buf), "reject *:%d", i); + smartlist_add(sm, tor_strdup(buf)); + } + smartlist_add(sm, tor_strdup("accept *:*")); + policy_str = smartlist_join_strings(sm, ",", 0, NULL); + test_policy_summary_helper( policy_str, + "accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44," + "46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90," + "92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128," + "130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164," + "166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200," + "202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236," + "238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272," + "274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308," + "310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344," + "346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380," + "382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416," + "418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452," + "454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488," + "490,492,494,496,498,500,502,504,506,508,510,512,514,516,518,520,522"); + + done: + addr_policy_list_free(policy); + addr_policy_list_free(policy2); + addr_policy_list_free(policy3); + addr_policy_list_free(policy4); + addr_policy_list_free(policy5); + addr_policy_list_free(policy6); + addr_policy_list_free(policy7); + tor_free(policy_str); + if (sm) { + SMARTLIST_FOREACH(sm, char *, s, tor_free(s)); + smartlist_free(sm); + } + short_policy_free(short_parsed); +} + +static void +test_dump_exit_policy_to_string(void *arg) +{ + char *ep; + addr_policy_t *policy_entry; + + routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t)); + + (void)arg; + + ri->policy_is_reject_star = 1; + ri->exit_policy = NULL; // expecting "reject *:*" + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("reject *:*",ep); + + tor_free(ep); + + ri->exit_policy = smartlist_new(); + ri->policy_is_reject_star = 0; + + policy_entry = router_parse_addr_policy_item_from_string("accept *:*",-1); + + smartlist_add(ri->exit_policy,policy_entry); + + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("accept *:*",ep); + + tor_free(ep); + + policy_entry = router_parse_addr_policy_item_from_string("reject *:25",-1); + + smartlist_add(ri->exit_policy,policy_entry); + + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("accept *:*\nreject *:25",ep); + + tor_free(ep); + + policy_entry = + router_parse_addr_policy_item_from_string("reject 8.8.8.8:*",-1); + + smartlist_add(ri->exit_policy,policy_entry); + + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*",ep); + + policy_entry = + router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*",-1); + + smartlist_add(ri->exit_policy,policy_entry); + + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n" + "reject6 [fc00::]/7:*",ep); + + policy_entry = + router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*",-1); + + smartlist_add(ri->exit_policy,policy_entry); + + ep = router_dump_exit_policy_to_string(ri,1,1); + + test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n" + "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",ep); + + done: + + SMARTLIST_FOREACH(ri->exit_policy, addr_policy_t *, + entry, addr_policy_free(entry)); + tor_free(ri); + tor_free(ep); +} + +struct testcase_t policy_tests[] = { + { "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0, + NULL, NULL }, + { "general", test_policies_general, 0, NULL, NULL }, + END_OF_TESTCASES +}; + diff --git a/src/test/test_status.c b/src/test/test_status.c new file mode 100644 index 0000000000..b704053d04 --- /dev/null +++ b/src/test/test_status.c @@ -0,0 +1,1109 @@ +#define STATUS_PRIVATE +#define HIBERNATE_PRIVATE +#define LOG_PRIVATE +#define REPHIST_PRIVATE + +#include <float.h> +#include <math.h> + +#include "or.h" +#include "torlog.h" +#include "tor_queue.h" +#include "status.h" +#include "circuitlist.h" +#include "config.h" +#include "hibernate.h" +#include "rephist.h" +#include "relay.h" +#include "router.h" +#include "main.h" +#include "nodelist.h" +#include "statefile.h" +#include "test.h" + +#define NS_MODULE status + +#define NS_SUBMODULE count_circuits + +/* + * Test that count_circuits() is correctly counting the number of + * global circuits. + */ + +struct global_circuitlist_s mock_global_circuitlist = + TOR_LIST_HEAD_INITIALIZER(global_circuitlist); + +NS_DECL(struct global_circuitlist_s *, circuit_get_global_list, (void)); + +static void +NS(test_main)(void *arg) +{ + /* Choose origin_circuit_t wlog. */ + origin_circuit_t *mock_circuit1, *mock_circuit2; + circuit_t *circ, *tmp; + int expected_circuits = 2, actual_circuits; + + (void)arg; + + mock_circuit1 = tor_malloc_zero(sizeof(origin_circuit_t)); + mock_circuit2 = tor_malloc_zero(sizeof(origin_circuit_t)); + TOR_LIST_INSERT_HEAD( + &mock_global_circuitlist, TO_CIRCUIT(mock_circuit1), head); + TOR_LIST_INSERT_HEAD( + &mock_global_circuitlist, TO_CIRCUIT(mock_circuit2), head); + + NS_MOCK(circuit_get_global_list); + + actual_circuits = count_circuits(); + + tt_assert(expected_circuits == actual_circuits); + + done: + TOR_LIST_FOREACH_SAFE( + circ, NS(circuit_get_global_list)(), head, tmp); + tor_free(circ); + NS_UNMOCK(circuit_get_global_list); +} + +static struct global_circuitlist_s * +NS(circuit_get_global_list)(void) +{ + return &mock_global_circuitlist; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE secs_to_uptime + +/* + * Test that secs_to_uptime() is converting the number of seconds that + * Tor is up for into the appropriate string form containing hours and minutes. + */ + +static void +NS(test_main)(void *arg) +{ + const char *expected; + char *actual; + (void)arg; + + expected = "0:00 hours"; + actual = secs_to_uptime(0); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "0:00 hours"; + actual = secs_to_uptime(1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "0:01 hours"; + actual = secs_to_uptime(60); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "0:59 hours"; + actual = secs_to_uptime(60 * 59); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1:00 hours"; + actual = secs_to_uptime(60 * 60); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "23:59 hours"; + actual = secs_to_uptime(60 * 60 * 23 + 60 * 59); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1 day 0:00 hours"; + actual = secs_to_uptime(60 * 60 * 23 + 60 * 60); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1 day 0:00 hours"; + actual = secs_to_uptime(86400 + 1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1 day 0:01 hours"; + actual = secs_to_uptime(86400 + 60); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "10 days 0:00 hours"; + actual = secs_to_uptime(86400 * 10); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "10 days 0:00 hours"; + actual = secs_to_uptime(864000 + 1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "10 days 0:01 hours"; + actual = secs_to_uptime(864000 + 60); + tt_str_op(actual, ==, expected); + tor_free(actual); + + done: + if (actual != NULL) + tor_free(actual); +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE bytes_to_usage + +/* + * Test that bytes_to_usage() is correctly converting the number of bytes that + * Tor has read/written into the appropriate string form containing kilobytes, + * megabytes, or gigabytes. + */ + +static void +NS(test_main)(void *arg) +{ + const char *expected; + char *actual; + (void)arg; + + expected = "0 kB"; + actual = bytes_to_usage(0); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "0 kB"; + actual = bytes_to_usage(1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1 kB"; + actual = bytes_to_usage(1024); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1023 kB"; + actual = bytes_to_usage((1 << 20) - 1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.00 MB"; + actual = bytes_to_usage((1 << 20)); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.00 MB"; + actual = bytes_to_usage((1 << 20) + 5242); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.01 MB"; + actual = bytes_to_usage((1 << 20) + 5243); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1024.00 MB"; + actual = bytes_to_usage((1 << 30) - 1); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.00 GB"; + actual = bytes_to_usage((1 << 30)); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.00 GB"; + actual = bytes_to_usage((1 << 30) + 5368709); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "1.01 GB"; + actual = bytes_to_usage((1 << 30) + 5368710); + tt_str_op(actual, ==, expected); + tor_free(actual); + + expected = "10.00 GB"; + actual = bytes_to_usage((U64_LITERAL(1) << 30) * 10L); + tt_str_op(actual, ==, expected); + tor_free(actual); + + done: + if (actual != NULL) + tor_free(actual); +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, fails) + +/* + * Tests that log_heartbeat() fails when in the public server mode, + * not hibernating, and we couldn't get the current routerinfo. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(router_get_my_routerinfo); + + expected = -1; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + + done: + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(router_get_my_routerinfo); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 2.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 0; +} + +static const or_options_t * +NS(get_options)(void) +{ + return NULL; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 1; +} + +static const routerinfo_t * +NS(router_get_my_routerinfo)(void) +{ + return NULL; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, not_in_consensus) + +/* + * Tests that log_heartbeat() logs appropriately if we are not in the cached + * consensus. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); +NS_DECL(const node_t *, node_get_by_id, (const char *identity_digest)); +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap)); +NS_DECL(int, server_mode, (const or_options_t *options)); + +static routerinfo_t *mock_routerinfo; +extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1]; +extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1]; + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(router_get_my_routerinfo); + NS_MOCK(node_get_by_id); + NS_MOCK(logv); + NS_MOCK(server_mode); + + log_global_min_severity_ = LOG_DEBUG; + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1; + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP] = 1; + onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR] = 1; + onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1; + + expected = 0; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + tt_int_op(CALLED(logv), ==, 3); + + done: + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(router_get_my_routerinfo); + NS_UNMOCK(node_get_by_id); + NS_UNMOCK(logv); + NS_UNMOCK(server_mode); + tor_free(mock_routerinfo); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 1.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 0; +} + +static const or_options_t * +NS(get_options)(void) +{ + return NULL; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 1; +} + +static const routerinfo_t * +NS(router_get_my_routerinfo)(void) +{ + mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); + + return mock_routerinfo; +} + +static const node_t * +NS(node_get_by_id)(const char *identity_digest) +{ + (void)identity_digest; + + return NULL; +} + +static void +NS(logv)(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap) +{ + switch (CALLED(logv)) + { + case 0: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: It seems like we are not in the cached consensus."); + break; + case 1: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Tor's uptime is %s, with %d circuits open. " + "I've sent %s and received %s.%s"); + tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */ + tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */ + tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */ + break; + case 2: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op( + strstr(funcname, "rep_hist_log_circuit_handshake_stats"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor."); + tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (TAP) */ + tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (TAP) */ + tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (NTOR) */ + tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (NTOR) */ + break; + default: + tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args + break; + } + + done: + CALLED(logv)++; +} + +static int +NS(server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, simple) + +/* + * Tests that log_heartbeat() correctly logs heartbeat information + * normally. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(long, get_uptime, (void)); +NS_DECL(uint64_t, get_bytes_read, (void)); +NS_DECL(uint64_t, get_bytes_written, (void)); +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap)); +NS_DECL(int, server_mode, (const or_options_t *options)); + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(get_uptime); + NS_MOCK(get_bytes_read); + NS_MOCK(get_bytes_written); + NS_MOCK(logv); + NS_MOCK(server_mode); + + log_global_min_severity_ = LOG_DEBUG; + + expected = 0; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + + done: + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(get_uptime); + NS_UNMOCK(get_bytes_read); + NS_UNMOCK(get_bytes_written); + NS_UNMOCK(logv); + NS_UNMOCK(server_mode); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 1.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 1; +} + +static const or_options_t * +NS(get_options)(void) +{ + return NULL; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static long +NS(get_uptime)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_read)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_written)(void) +{ + return 0; +} + +static void +NS(logv)(int severity, log_domain_mask_t domain, const char *funcname, + const char *suffix, const char *format, va_list ap) +{ + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Tor's uptime is %s, with %d circuits open. " + "I've sent %s and received %s.%s"); + tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */ + tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */ + tt_str_op(va_arg(ap, char *), ==, " We are currently hibernating."); + + done: + ; +} + +static int +NS(server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, calls_log_accounting) + +/* + * Tests that log_heartbeat() correctly logs heartbeat information + * and accounting information when configured. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(long, get_uptime, (void)); +NS_DECL(uint64_t, get_bytes_read, (void)); +NS_DECL(uint64_t, get_bytes_written, (void)); +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap)); +NS_DECL(int, server_mode, (const or_options_t *options)); +NS_DECL(or_state_t *, get_or_state, (void)); +NS_DECL(int, accounting_is_enabled, (const or_options_t *options)); +NS_DECL(time_t, accounting_get_end_time, (void)); + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(get_uptime); + NS_MOCK(get_bytes_read); + NS_MOCK(get_bytes_written); + NS_MOCK(logv); + NS_MOCK(server_mode); + NS_MOCK(get_or_state); + NS_MOCK(accounting_is_enabled); + NS_MOCK(accounting_get_end_time); + + log_global_min_severity_ = LOG_DEBUG; + + expected = 0; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + tt_int_op(CALLED(logv), ==, 2); + + done: + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(get_uptime); + NS_UNMOCK(get_bytes_read); + NS_UNMOCK(get_bytes_written); + NS_UNMOCK(logv); + NS_UNMOCK(server_mode); + NS_UNMOCK(accounting_is_enabled); + NS_UNMOCK(accounting_get_end_time); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 1.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 0; +} + +static const or_options_t * +NS(get_options)(void) +{ + or_options_t *mock_options = tor_malloc_zero(sizeof(or_options_t)); + mock_options->AccountingMax = 0; + + return mock_options; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static long +NS(get_uptime)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_read)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_written)(void) +{ + return 0; +} + +static void +NS(logv)(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap) +{ + switch (CALLED(logv)) + { + case 0: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Tor's uptime is %s, with %d circuits open. " + "I've sent %s and received %s.%s"); + tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */ + tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */ + tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */ + break; + case 1: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_accounting"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Accounting enabled. Sent: %s / %s, Received: %s / %s. " + "The current accounting interval ends on %s, in %s."); + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_rcvd */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */ + /* format_local_iso_time uses local tz, just check mins and secs. */ + tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"), !=, NULL); /* end_buf */ + tt_str_op(va_arg(ap, char *), ==, "0:01 hours"); /* remaining */ + break; + default: + tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args + break; + } + + done: + CALLED(logv)++; +} + +static int +NS(server_mode)(const or_options_t *options) +{ + (void)options; + + return 1; +} + +static int +NS(accounting_is_enabled)(const or_options_t *options) +{ + (void)options; + + return 1; +} + +static time_t +NS(accounting_get_end_time)(void) +{ + return 60; +} + +static or_state_t * +NS(get_or_state)(void) +{ + or_state_t *mock_state = tor_malloc_zero(sizeof(or_state_t)); + mock_state->AccountingBytesReadInInterval = 0; + mock_state->AccountingBytesWrittenInInterval = 0; + + return mock_state; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, packaged_cell_fullness) + +/* + * Tests that log_heartbeat() correctly logs packaged cell + * fullness information. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(long, get_uptime, (void)); +NS_DECL(uint64_t, get_bytes_read, (void)); +NS_DECL(uint64_t, get_bytes_written, (void)); +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap)); +NS_DECL(int, server_mode, (const or_options_t *options)); +NS_DECL(int, accounting_is_enabled, (const or_options_t *options)); + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(get_uptime); + NS_MOCK(get_bytes_read); + NS_MOCK(get_bytes_written); + NS_MOCK(logv); + NS_MOCK(server_mode); + NS_MOCK(accounting_is_enabled); + log_global_min_severity_ = LOG_DEBUG; + + stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE; + stats_n_data_cells_packaged = 1; + expected = 0; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + tt_int_op(CALLED(logv), ==, 2); + + done: + stats_n_data_bytes_packaged = 0; + stats_n_data_cells_packaged = 0; + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(get_uptime); + NS_UNMOCK(get_bytes_read); + NS_UNMOCK(get_bytes_written); + NS_UNMOCK(logv); + NS_UNMOCK(server_mode); + NS_UNMOCK(accounting_is_enabled); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 1.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 0; +} + +static const or_options_t * +NS(get_options)(void) +{ + return NULL; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static long +NS(get_uptime)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_read)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_written)(void) +{ + return 0; +} + +static void +NS(logv)(int severity, log_domain_mask_t domain, const char *funcname, + const char *suffix, const char *format, va_list ap) +{ + switch (CALLED(logv)) + { + case 0: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Tor's uptime is %s, with %d circuits open. " + "I've sent %s and received %s.%s"); + tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */ + tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */ + tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */ + break; + case 1: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Average packaged cell fullness: %2.3f%%"); + tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1); + break; + default: + tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args + break; + } + + done: + CALLED(logv)++; +} + +static int +NS(server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static int +NS(accounting_is_enabled)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +#undef NS_SUBMODULE +#define NS_SUBMODULE ASPECT(log_heartbeat, tls_write_overhead) + +/* + * Tests that log_heartbeat() correctly logs the TLS write overhead information + * when the TLS write overhead ratio exceeds 1. + */ + +NS_DECL(double, tls_get_write_overhead_ratio, (void)); +NS_DECL(int, we_are_hibernating, (void)); +NS_DECL(const or_options_t *, get_options, (void)); +NS_DECL(int, public_server_mode, (const or_options_t *options)); +NS_DECL(long, get_uptime, (void)); +NS_DECL(uint64_t, get_bytes_read, (void)); +NS_DECL(uint64_t, get_bytes_written, (void)); +NS_DECL(void, logv, (int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap)); +NS_DECL(int, server_mode, (const or_options_t *options)); +NS_DECL(int, accounting_is_enabled, (const or_options_t *options)); + +static void +NS(test_main)(void *arg) +{ + int expected, actual; + (void)arg; + + NS_MOCK(tls_get_write_overhead_ratio); + NS_MOCK(we_are_hibernating); + NS_MOCK(get_options); + NS_MOCK(public_server_mode); + NS_MOCK(get_uptime); + NS_MOCK(get_bytes_read); + NS_MOCK(get_bytes_written); + NS_MOCK(logv); + NS_MOCK(server_mode); + NS_MOCK(accounting_is_enabled); + stats_n_data_cells_packaged = 0; + log_global_min_severity_ = LOG_DEBUG; + + expected = 0; + actual = log_heartbeat(0); + + tt_int_op(actual, ==, expected); + tt_int_op(CALLED(logv), ==, 2); + + done: + NS_UNMOCK(tls_get_write_overhead_ratio); + NS_UNMOCK(we_are_hibernating); + NS_UNMOCK(get_options); + NS_UNMOCK(public_server_mode); + NS_UNMOCK(get_uptime); + NS_UNMOCK(get_bytes_read); + NS_UNMOCK(get_bytes_written); + NS_UNMOCK(logv); + NS_UNMOCK(server_mode); + NS_UNMOCK(accounting_is_enabled); +} + +static double +NS(tls_get_write_overhead_ratio)(void) +{ + return 2.0; +} + +static int +NS(we_are_hibernating)(void) +{ + return 0; +} + +static const or_options_t * +NS(get_options)(void) +{ + return NULL; +} + +static int +NS(public_server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static long +NS(get_uptime)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_read)(void) +{ + return 0; +} + +static uint64_t +NS(get_bytes_written)(void) +{ + return 0; +} + +static void +NS(logv)(int severity, log_domain_mask_t domain, + const char *funcname, const char *suffix, const char *format, va_list ap) +{ + switch (CALLED(logv)) + { + case 0: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, + "Heartbeat: Tor's uptime is %s, with %d circuits open. " + "I've sent %s and received %s.%s"); + tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */ + tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */ + tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */ + tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */ + break; + case 1: + tt_int_op(severity, ==, LOG_NOTICE); + tt_int_op(domain, ==, LD_HEARTBEAT); + tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL); + tt_ptr_op(suffix, ==, NULL); + tt_str_op(format, ==, "TLS write overhead: %.f%%"); + tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1); + break; + default: + tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args + break; + } + + done: + CALLED(logv)++; +} + +static int +NS(server_mode)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +static int +NS(accounting_is_enabled)(const or_options_t *options) +{ + (void)options; + + return 0; +} + +#undef NS_SUBMODULE + +struct testcase_t status_tests[] = { + TEST_CASE(count_circuits), + TEST_CASE(secs_to_uptime), + TEST_CASE(bytes_to_usage), + TEST_CASE_ASPECT(log_heartbeat, fails), + TEST_CASE_ASPECT(log_heartbeat, simple), + TEST_CASE_ASPECT(log_heartbeat, not_in_consensus), + TEST_CASE_ASPECT(log_heartbeat, calls_log_accounting), + TEST_CASE_ASPECT(log_heartbeat, packaged_cell_fullness), + TEST_CASE_ASPECT(log_heartbeat, tls_write_overhead), + END_OF_TESTCASES +}; + diff --git a/src/test/test_util.c b/src/test/test_util.c index a471b8eb19..08efd453c9 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1189,19 +1189,19 @@ test_util_strmisc(void) } /* Test str-foo functions */ - cp = tor_strdup("abcdef"); - test_assert(tor_strisnonupper(cp)); - cp[3] = 'D'; - test_assert(!tor_strisnonupper(cp)); - tor_strupper(cp); - test_streq(cp, "ABCDEF"); - tor_strlower(cp); - test_streq(cp, "abcdef"); - test_assert(tor_strisnonupper(cp)); - test_assert(tor_strisprint(cp)); - cp[3] = 3; - test_assert(!tor_strisprint(cp)); - tor_free(cp); + cp_tmp = tor_strdup("abcdef"); + test_assert(tor_strisnonupper(cp_tmp)); + cp_tmp[3] = 'D'; + test_assert(!tor_strisnonupper(cp_tmp)); + tor_strupper(cp_tmp); + test_streq(cp_tmp, "ABCDEF"); + tor_strlower(cp_tmp); + test_streq(cp_tmp, "abcdef"); + test_assert(tor_strisnonupper(cp_tmp)); + test_assert(tor_strisprint(cp_tmp)); + cp_tmp[3] = 3; + test_assert(!tor_strisprint(cp_tmp)); + tor_free(cp_tmp); /* Test memmem and memstr */ { @@ -1212,6 +1212,10 @@ test_util_strmisc(void) test_assert(!tor_memmem(haystack, 4, "cde", 3)); haystack = "ababcad"; test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2); + test_eq_ptr(tor_memmem(haystack, 7, "ad", 2), haystack + 5); + test_eq_ptr(tor_memmem(haystack, 7, "cad", 3), haystack + 4); + test_assert(!tor_memmem(haystack, 7, "dadad", 5)); + test_assert(!tor_memmem(haystack, 7, "abcdefghij", 10)); /* memstr */ test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2); test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4); @@ -2321,6 +2325,8 @@ test_util_listdir(void *ptr) done: tor_free(fname1); tor_free(fname2); + tor_free(fname3); + tor_free(dir1); tor_free(dirname); if (dir_contents) { SMARTLIST_FOREACH(dir_contents, char *, cp, tor_free(cp)); diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index 2f95cf7c52..d0c30b8b02 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -547,6 +547,9 @@ main(int argc, char **argv) if (signing_key) EVP_PKEY_free(signing_key); tor_free(address); + tor_free(identity_key_file); + tor_free(signing_key_file); + tor_free(certificate_file); crypto_global_cleanup(); return r; |