Merge commit 'tor-0.2.2.4-alpha' into debian-merge

* commit 'tor-0.2.2.4-alpha': (49 commits)
  Fix testsuite call.
  bump to 0.2.2.4-alpha
  Don't set unreachable from dirvote unless we've been running a while.
  correct the spec for the stream_bw event.
  fix a bug where we were decrementing the wrong bucket
  remove some dead code. some of it was tickling coverity.
  add blurbs for recent alpha releases
  Fix a memleak when throwing away some build times
  amend changelog for recent commits, plus clean up
  Tweak an assert that shouldn't fire either way.
  Tweak values for when to discard all of our history.
  Remove another overzealous assert.
  try to stem the 'sea of fail'
  fix the wiki link in doc pages. remove obsolete FAQ.
  Ignore one-hop circuits for circuit timeout calc
  Move Tonga to an alternate IP address
  update spec to reflect change in Fast definition
  Move moria1 to a nearby IP address
  Dir auths reject relays running < Tor 0.1.2.14
  Fix 1108: Handle corrupt or large build times state.
  ...
This commit is contained in:
Peter Palfrader 2009-10-11 10:17:56 +02:00
commit 01da810609
48 changed files with 26858 additions and 16099 deletions

8
.gitignore vendored
View File

@ -127,7 +127,13 @@
/src/or/or_sha1.i
/src/or/micro-revision.*
/src/or/tor
/src/or/test
/src/or/libtor.a
# /src/test
/src/test/Makefile
/src/test/Makefile.in
/src/test/test
# /src/tools/
/src/tools/tor-checkkey

View File

@ -1,4 +1,48 @@
Changes in version 0.2.2.4-alpha - 2009-10-10
o Major bugfixes:
- Fix several more asserts in the circuit_build_times code, for
example one that causes Tor to fail to start once we have
accumulated 5000 build times in the state file. Bugfixes on
0.2.2.2-alpha; fixes bug 1108.
o New directory authorities:
- Move moria1 and Tonga to alternate IP addresses.
o Minor features:
- Log SSL state transitions at debug level during handshake, and
include SSL states in error messages. This may help debug future
SSL handshake issues.
- Add a new "Handshake" log domain for activities that happen
during the TLS handshake.
- Revert to the "June 3 2009" ip-to-country file. The September one
seems to have removed most US IP addresses.
- Directory authorities now reject Tor relays with versions less than
0.1.2.14. This step cuts out four relays from the current network,
none of which are very big.
o Minor bugfixes:
- Fix a couple of smaller issues with gathering statistics. Bugfixes
on 0.2.2.1-alpha.
- Fix two memory leaks in the error case of
circuit_build_times_parse_state. Bugfix on 0.2.2.2-alpha.
- Don't count one-hop circuits when we're estimating how long it
takes circuits to build on average. Otherwise we'll set our circuit
build timeout lower than we should. Bugfix on 0.2.2.2-alpha.
- Directory authorities no longer change their opinion of, or vote on,
whether a router is Running, unless they have themselves been
online long enough to have some idea. Bugfix on 0.2.0.6-alpha.
Fixes bug 1023.
o Code simplifications and refactoring:
- Revise our unit tests to use the "tinytest" framework, so we
can run tests in their own processes, have smarter setup/teardown
code, and so on. The unit test code has moved to its own
subdirectory, and has been split into multiple modules.
Changes in version 0.2.2.3-alpha - 2009-09-23
Tor 0.2.2.3-alpha fixes a few crash bugs in 0.2.2.2-alpha.
o Major bugfixes:
- Fix an overzealous assert in our new circuit build timeout code.
Bugfix on 0.2.2.2-alpha; fixes bug 1103.
@ -10,6 +54,12 @@ Changes in version 0.2.2.3-alpha - 2009-09-23
Changes in version 0.2.2.2-alpha - 2009-09-21
Tor 0.2.2.2-alpha introduces our latest performance improvement for
clients: Tor tracks the average time it takes to build a circuit, and
avoids using circuits that take too long to build. For fast connections,
this feature can cut your expected latency in half. For slow or flaky
connections, it could ruin your Tor experience. Let us know if it does!
o Major features:
- Tor now tracks how long it takes to build client-side circuits
over time, and adapts its timeout to local network performance.
@ -79,6 +129,11 @@ Changes in version 0.2.2.2-alpha - 2009-09-21
Changes in version 0.2.2.1-alpha - 2009-08-26
Tor 0.2.2.1-alpha disables ".exit" address notation by default, allows
Tor clients to bootstrap on networks where only port 80 is reachable,
makes it more straightforward to support hardware crypto accelerators,
and starts the groundwork for gathering stats safely at relays.
o Security fixes:
- Start the process of disabling ".exit" address notation, since it
can be used for a variety of esoteric application-level attacks

View File

@ -58,15 +58,16 @@ dist: check
doxygen:
doxygen && cd doc/doxygen/latex && make
test:
./src/or/test
test: all
./src/test/test
# Avoid strlcpy.c, strlcat.c, tree.h
check-spaces:
./contrib/checkSpace.pl -C \
src/common/*.h \
src/common/[^asO]*.c src/common/address.c \
src/or/[^et]*.[ch] src/or/t*.c src/or/eventdns_tor.h
src/or/[^et]*.[ch] src/or/t*.c src/or/eventdns_tor.h \
src/test/test*.[ch]
check-docs:
./contrib/checkOptionDocs.pl

View File

@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2008, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_INIT
AM_INIT_AUTOMAKE(tor, 0.2.2.3-alpha)
AM_INIT_AUTOMAKE(tor, 0.2.2.4-alpha)
AM_CONFIG_HEADER(orconfig.h)
AC_CANONICAL_HOST
@ -826,7 +826,7 @@ fi
CPPFLAGS="$CPPFLAGS $TOR_CPPFLAGS_libevent $TOR_CPPFLAGS_openssl $TOR_CPPFLAGS_zlib"
AC_CONFIG_FILES([Makefile tor.spec Doxyfile contrib/tor.sh contrib/torctl contrib/torify contrib/tor.logrotate contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample doc/tor.1 src/Makefile doc/Makefile doc/design-paper/Makefile doc/spec/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/win32/Makefile src/tools/Makefile contrib/suse/Makefile contrib/suse/tor.sh])
AC_CONFIG_FILES([Makefile tor.spec Doxyfile contrib/tor.sh contrib/torctl contrib/torify contrib/tor.logrotate contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample doc/tor.1 src/Makefile doc/Makefile doc/design-paper/Makefile doc/spec/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/test/Makefile src/win32/Makefile src/tools/Makefile contrib/suse/Makefile contrib/suse/tor.sh])
AC_OUTPUT
if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then

View File

@ -185,7 +185,7 @@ if [ ! -z $STRIP ]
then
${HOST_TRIPLET}strip \
src/or/tor \
src/or/test \
src/test/test \
src/tools/tor-resolve
fi

View File

@ -9,7 +9,7 @@
!include "FileFunc.nsh"
!insertmacro GetParameters
!define VERSION "0.2.2.3-alpha"
!define VERSION "0.2.2.4-alpha"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"

View File

@ -1,4 +0,0 @@
This file is obsolete. Check out the online FAQ at the wiki
for more accurate and complete questions and answers:
http://wiki.noreply.org/wiki/TheOnionRouter/TorFAQ

View File

@ -26,7 +26,7 @@ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/or/tor
make clean
make CFLAGS='-g -fprofile-arcs -ftest-coverage'
./src/or/test
./src/test/test
cd src/common; gcov *.[ch]
cd ../or; gcov *.[ch]
@ -150,7 +150,7 @@ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/or/tor
1.4. Log conventions
http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#LogLevels
https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#LogLevels
No error or warning messages should be expected during normal OR or OP
operation.

View File

@ -272,7 +272,7 @@ Future versions:
the RPM and other startup scripts should too?
- add a "default.action" file to the tor/vidalia bundle so we can
fix the https thing in the default configuration:
http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#PrivoxyWeirdSSLPort
https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#PrivoxyWeirdSSLPort
=======================================================================

View File

@ -1597,17 +1597,21 @@
4.1.13. Bandwidth used on an application stream
The syntax is:
"650" SP "STREAM_BW" SP StreamID SP BytesRead SP BytesWritten CRLF
BytesRead = 1*DIGIT
"650" SP "STREAM_BW" SP StreamID SP BytesWritten SP BytesRead CRLF
BytesWritten = 1*DIGIT
BytesRead = 1*DIGIT
BytesRead and BytesWritten are the number of bytes read and written since
the last STREAM_BW event on this stream. These events are generated about
once per second per stream; no events are generated for streams that have
not read or written.
BytesWritten and BytesRead are the number of bytes written and read
by the application since the last STREAM_BW event on this stream.
These events apply only to streams entering Tor (such as on a SOCKSPort,
TransPort, or so on). They are not generated for exiting streams.
Note that from Tor's perspective, *reading* a byte on a stream means
that the application *wrote* the byte. That's why the order of "written"
vs "read" is opposite for stream_bw events compared to bw events.
These events are generated about once per second per stream; no events
are generated for streams that have not written or read. These events
apply only to streams entering Tor (such as on a SOCKSPort, TransPort,
or so on). They are not generated for exiting streams.
4.1.14. Per-country client stats

View File

@ -1342,7 +1342,7 @@
least one /8 address space.
"Fast" -- A router is 'Fast' if it is active, and its bandwidth is
either in the top 7/8ths for known active routers or at least 100KB/s.
either in the top 7/8ths for known active routers or at least 20KB/s.
"Guard" -- A router is a possible 'Guard' if its Weighted Fractional
Uptime is at least the median for "familiar" active routers, and if

View File

@ -41,7 +41,7 @@ Verify the configuration file is valid.
\fB--nt-service\fP
\fB--service [install|remove|start|stop]\fP
Manage the Tor Windows NT/2000/XP service. Current instructions can
be found at http://wiki.noreply.org/noreply/TheOnionRouter/TorFAQ#WinNTService
be found at https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#WinNTService
.LP
.TP
\fB--list-torrc-options\fP

View File

@ -1,5 +1,5 @@
# leave in dependency order, since common must be built first
SUBDIRS = common or tools win32 config
DIST_SUBDIRS = common or tools win32 config
SUBDIRS = common or test tools win32 config
DIST_SUBDIRS = common or test tools win32 config

View File

@ -16,7 +16,7 @@ libor_a_SOURCES = address.c log.c util.c compat.c container.c mempool.c \
libor_crypto_a_SOURCES = crypto.c aes.c tortls.c torgzip.c
libor_event_a_SOURCES = compat_libevent.c
noinst_HEADERS = address.h log.h crypto.h test.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc compat_libevent.h
noinst_HEADERS = address.h log.h crypto.h util.h compat.h aes.h torint.h tortls.h strlcpy.c strlcat.c torgzip.h container.h ht.h mempool.h memarea.h ciphers.inc compat_libevent.h tortls_states.h
common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
if test "@SHA1SUM@" != none; then \

View File

@ -745,7 +745,7 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", "HIST", NULL
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,

View File

@ -90,9 +90,10 @@
#define LD_ACCT (1u<<17)
/** Router history */
#define LD_HIST (1u<<18)
/** OR handshaking */
#define LD_HANDSHAKE (1u<<19)
/** Number of logging domains in the code. */
#define N_LOGGING_DOMAINS 19
#define N_LOGGING_DOMAINS 20
typedef uint32_t log_domain_mask_t;

View File

@ -1,184 +0,0 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_TEST_H
#define _TOR_TEST_H
/**
* \file test.h
* \brief Macros used by unit tests.
*/
#include "compat.h"
#ifdef __GNUC__
#define PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define PRETTY_FUNCTION ""
#endif
#define test_fail_msg(msg) \
STMT_BEGIN \
have_failed = 1; \
printf("\nFile %s: line %d (%s): %s", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
msg); \
goto done; \
STMT_END
#define test_fail() test_fail_msg("Assertion failed.")
#define test_assert(expr) \
STMT_BEGIN \
if (expr) { printf("."); fflush(stdout); } else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): assertion failed: (%s)\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr); \
goto done; \
} STMT_END
#define test_eq_type(tp, fmt, expr1, expr2) \
STMT_BEGIN \
tp _test_v1=(tp)(expr1); \
tp _test_v2=(tp)(expr2); \
if (_test_v1==_test_v2) { printf("."); fflush(stdout); } else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
" "fmt "!="fmt"\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2, \
_test_v1, _test_v2); \
goto done; \
} STMT_END
#define test_eq(expr1, expr2) \
test_eq_type(long, "%ld", expr1, expr2)
#define test_eq_ptr(expr1, expr2) \
test_eq_type(void*, "%p", expr1, expr2)
#define test_neq_type(tp, fmt, expr1, expr2) \
STMT_BEGIN \
tp _test_v1=(tp)(expr1); \
tp _test_v2=(tp)(expr2); \
if (_test_v1!=_test_v2) { printf("."); fflush(stdout); } else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n" \
" ("fmt" == "fmt")\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2, \
_test_v1, _test_v2); \
goto done; \
} STMT_END
#define test_neq(expr1, expr2) \
test_neq_type(long, "%ld", expr1, expr2)
#define test_neq_ptr(expr1, expr2) \
test_neq_type(void *, "%p", expr1, expr2)
#define test_streq(expr1, expr2) \
STMT_BEGIN \
const char *_test_v1=(expr1), *_test_v2=(expr2); \
if (!strcmp(_test_v1,_test_v2)) { printf("."); fflush(stdout); } else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n"\
" (\"%s\" != \"%s\")\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2, \
_test_v1, _test_v2); \
goto done; \
} STMT_END
#define test_strneq(expr1, expr2) \
STMT_BEGIN \
const char *_test_v1=(expr1), *_test_v2=(expr2); \
if (strcmp(_test_v1,_test_v2)) { printf("."); fflush(stdout); } else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n"\
" (\"%s\" == \"%s\")\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2, \
_test_v1, _test_v2); \
goto done; \
} STMT_END
#define test_memeq(expr1, expr2, len) \
STMT_BEGIN \
const void *_test_v1=(expr1), *_test_v2=(expr2); \
char *mem1, *mem2; \
if (!memcmp(_test_v1,_test_v2,(len))) { \
printf("."); fflush(stdout); } else { \
have_failed = 1; \
mem1 = tor_malloc(len*2+1); \
mem2 = tor_malloc(len*2+1); \
base16_encode(mem1, len*2+1, _test_v1, len); \
base16_encode(mem2, len*2+1, _test_v2, len); \
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
" %s != %s\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2, mem1, mem2); \
tor_free(mem1); \
tor_free(mem2); \
goto done; \
} STMT_END
#define test_memeq_hex(expr1, hex) \
STMT_BEGIN \
const char *_test_v1 = (char*)(expr1); \
const char *_test_v2 = (hex); \
size_t _len_v2 = strlen(_test_v2); \
char *_mem2 = tor_malloc(_len_v2/2); \
tor_assert((_len_v2 & 1) == 0); \
base16_decode(_mem2, _len_v2/2, _test_v2, _len_v2); \
if (!memcmp(_mem2, _test_v1, _len_v2/2)) { \
printf("."); fflush(stdout); } else { \
char *_mem1 = tor_malloc(_len_v2+1); \
base16_encode(_mem1, _len_v2+1, _test_v1, _len_v2/2); \
printf("\nFile %s: line %d (%s): Assertion failed: (%s==%s)\n" \
" %s != %s\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, _test_v2, _mem1, _test_v2); \
tor_free(_mem1); \
tor_free(_mem2); \
goto done; \
} \
tor_free(_mem2); \
STMT_END
#define test_memneq(expr1, expr2, len) \
STMT_BEGIN \
void *_test_v1=(expr1), *_test_v2=(expr2); \
if (memcmp(_test_v1,_test_v2,(len))) { \
printf("."); fflush(stdout); \
} else { \
have_failed = 1; \
printf("\nFile %s: line %d (%s): Assertion failed: (%s!=%s)\n", \
_SHORT_FILE_, \
__LINE__, \
PRETTY_FUNCTION, \
#expr1, #expr2); \
goto done; \
} STMT_END
#endif

View File

@ -165,28 +165,49 @@ static int tls_library_is_initialized = 0;
#define _TOR_TLS_SYSCALL (_MIN_TOR_TLS_ERROR_VAL - 2)
#define _TOR_TLS_ZERORETURN (_MIN_TOR_TLS_ERROR_VAL - 1)
#include "tortls_states.h"
/** Return the symbolic name of an OpenSSL state. */
static const char *
ssl_state_to_string(int ssl_state)
{
static char buf[40];
int i;
for (i = 0; state_map[i].name; ++i) {
if (state_map[i].state == ssl_state)
return state_map[i].name;
}
tor_snprintf(buf, sizeof(buf), "Unknown state %d", ssl_state);
return buf;
}
/** Log all pending tls errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
*/
static void
tls_log_errors(tor_tls_t *tls, int severity, const char *doing)
tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
{
const char *state = NULL;
int st;
unsigned long err;
const char *msg, *lib, *func, *addr;
addr = tls ? tls->address : NULL;
st = (tls && tls->ssl) ? tls->ssl->state : -1;
while ((err = ERR_get_error()) != 0) {
msg = (const char*)ERR_reason_error_string(err);
lib = (const char*)ERR_lib_error_string(err);
func = (const char*)ERR_func_error_string(err);
if (!state)
state = (st>=0)?ssl_state_to_string(st):"---";
if (!msg) msg = "(null)";
if (doing) {
log(severity, LD_NET, "TLS error while %s%s%s: %s (in %s:%s)",
log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
doing, addr?" with ":"", addr?addr:"",
msg, lib, func);
msg, lib, func, state);
} else {
log(severity, LD_NET, "TLS error%s%s: %s (in %s:%s)",
log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
addr?" with ":"", addr?addr:"",
msg, lib, func);
msg, lib, func, state);
}
}
}
@ -262,7 +283,7 @@ tor_tls_err_to_string(int err)
*/
static int
tor_tls_get_error(tor_tls_t *tls, int r, int extra,
const char *doing, int severity)
const char *doing, int severity, int domain)
{
int err = SSL_get_error(tls->ssl, r);
int tor_error = TOR_TLS_ERROR_MISC;
@ -277,25 +298,28 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
if (extra&CATCH_SYSCALL)
return _TOR_TLS_SYSCALL;
if (r == 0) {
log(severity, LD_NET, "TLS error: unexpected close while %s", doing);
log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
doing, ssl_state_to_string(tls->ssl->state));
tor_error = TOR_TLS_ERROR_IO;
} else {
int e = tor_socket_errno(tls->socket);
log(severity, LD_NET,
"TLS error: <syscall error while %s> (errno=%d: %s)",
doing, e, tor_socket_strerror(e));
"TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
doing, e, tor_socket_strerror(e),
ssl_state_to_string(tls->ssl->state));
tor_error = tor_errno_to_tls_error(e);
}
tls_log_errors(tls, severity, doing);
tls_log_errors(tls, severity, domain, doing);
return tor_error;
case SSL_ERROR_ZERO_RETURN:
if (extra&CATCH_ZERO)
return _TOR_TLS_ZERORETURN;
log(severity, LD_NET, "TLS connection closed while %s", doing);
tls_log_errors(tls, severity, doing);
log(severity, LD_NET, "TLS connection closed while %s in state %s",
doing, ssl_state_to_string(tls->ssl->state));
tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_CLOSE;
default:
tls_log_errors(tls, severity, doing);
tls_log_errors(tls, severity, domain, doing);
return TOR_TLS_ERROR_MISC;
}
}
@ -427,7 +451,7 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
x509 = NULL;
}
done:
tls_log_errors(NULL, LOG_WARN, "generating certificate");
tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate");
if (sign_pkey)
EVP_PKEY_free(sign_pkey);
if (pkey)
@ -615,7 +639,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, unsigned int key_lifetime)
return 0;
error:
tls_log_errors(NULL, LOG_WARN, "creating TLS context");
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
tor_free(nickname);
tor_free(nn2);
if (pkey)
@ -811,7 +835,7 @@ tor_tls_new(int sock, int isServer)
tor_assert(global_tls_context); /* make sure somebody made it first */
if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
tls_log_errors(NULL, LOG_WARN, "generating TLS context");
tls_log_errors(NULL, LOG_WARN, LD_NET, "generating TLS context");
tor_free(result);
return NULL;
}
@ -827,7 +851,7 @@ tor_tls_new(int sock, int isServer)
if (!SSL_set_cipher_list(result->ssl,
isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
tls_log_errors(NULL, LOG_WARN, "setting ciphers");
tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers");
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
@ -840,7 +864,7 @@ tor_tls_new(int sock, int isServer)
result->socket = sock;
bio = BIO_new_socket(sock, BIO_NOCLOSE);
if (! bio) {
tls_log_errors(NULL, LOG_WARN, "opening BIO");
tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
#ifdef SSL_set_tlsext_host_name
SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
@ -867,7 +891,7 @@ tor_tls_new(int sock, int isServer)
}
#endif
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, "generating TLS context");
tls_log_errors(NULL, LOG_WARN, LD_NET, "generating TLS context");
return result;
}
@ -962,7 +986,7 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
#endif
return r;
}
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
@ -998,7 +1022,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
tls->wantwrite_n = 0;
}
r = SSL_write(tls->ssl, cp, (int)n);
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO);
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
if (err == TOR_TLS_DONE) {
return r;
}
@ -1016,18 +1040,27 @@ int
tor_tls_handshake(tor_tls_t *tls)
{
int r;
int oldstate;
tor_assert(tls);
tor_assert(tls->ssl);
tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
check_no_tls_errors();
oldstate = tls->ssl->state;
if (tls->isServer) {
log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
ssl_state_to_string(tls->ssl->state));
r = SSL_accept(tls->ssl);
} else {
log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
ssl_state_to_string(tls->ssl->state));
r = SSL_connect(tls->ssl);
}
r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO);
if (oldstate != tls->ssl->state)
log_debug(LD_HANDSHAKE, "After call, %p was in state %s",
tls, ssl_state_to_string(tls->ssl->state));
r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE);
if (ERR_peek_error() != 0) {
tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN,
tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE,
"handshaking");
return TOR_TLS_ERROR_MISC;
}
@ -1048,7 +1081,8 @@ tor_tls_handshake(tor_tls_t *tls)
" get set. Fixing that.");
}
tls->wasV2Handshake = 1;
log_debug(LD_NET, "Completed V2 TLS handshake with client; waiting "
log_debug(LD_HANDSHAKE,
"Completed V2 TLS handshake with client; waiting "
"for renegotiation.");
} else {
tls->wasV2Handshake = 0;
@ -1060,10 +1094,13 @@ tor_tls_handshake(tor_tls_t *tls)
X509 *cert = SSL_get_peer_certificate(tls->ssl);
STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl);
int n_certs = sk_X509_num(chain);
if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0)))
if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) {
log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it "
"looks like a v1 handshake on %p", tls);
tls->wasV2Handshake = 0;
else {
log_debug(LD_NET, "Server sent back a single certificate; looks like "
} else {
log_debug(LD_HANDSHAKE,
"Server sent back a single certificate; looks like "
"a v2 handshake on %p.", tls);
tls->wasV2Handshake = 1;
}
@ -1071,7 +1108,7 @@ tor_tls_handshake(tor_tls_t *tls)
X509_free(cert);
#endif
if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) {
tls_log_errors(NULL, LOG_WARN, "re-setting ciphers");
tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers");
r = TOR_TLS_ERROR_MISC;
}
}
@ -1094,7 +1131,8 @@ tor_tls_renegotiate(tor_tls_t *tls)
if (tls->state != TOR_TLS_ST_RENEGOTIATE) {
int r = SSL_renegotiate(tls->ssl);
if (r <= 0) {
return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN);
return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN,
LD_HANDSHAKE);
}
tls->state = TOR_TLS_ST_RENEGOTIATE;
}
@ -1103,7 +1141,8 @@ tor_tls_renegotiate(tor_tls_t *tls)
tls->state = TOR_TLS_ST_OPEN;
return TOR_TLS_DONE;
} else
return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO);
return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO,
LD_HANDSHAKE);
}
/** Shut down an open tls connection <b>tls</b>. When finished, returns
@ -1127,7 +1166,7 @@ tor_tls_shutdown(tor_tls_t *tls)
r = SSL_read(tls->ssl, buf, 128);
} while (r>0);
err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
LOG_INFO);
LOG_INFO, LD_NET);
if (err == _TOR_TLS_ZERORETURN) {
tls->state = TOR_TLS_ST_GOTCLOSE;
/* fall through... */
@ -1143,7 +1182,7 @@ tor_tls_shutdown(tor_tls_t *tls)
return TOR_TLS_DONE;
}
err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
LOG_INFO);
LOG_INFO, LD_NET);
if (err == _TOR_TLS_SYSCALL) {
/* The underlying TCP connection closed while we were shutting down. */
tls->state = TOR_TLS_ST_CLOSED;
@ -1175,7 +1214,7 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
{
X509 *cert;
cert = SSL_get_peer_certificate(tls->ssl);
tls_log_errors(tls, LOG_WARN, "getting peer certificate");
tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
if (!cert)
return 0;
X509_free(cert);
@ -1202,7 +1241,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end;
}
if (!(ASN1_TIME_print(bio, X509_get_notBefore(cert)))) {
tls_log_errors(NULL, LOG_WARN, "printing certificate lifetime");
tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
goto end;
}
BIO_get_mem_ptr(bio, &buf);
@ -1210,7 +1249,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
(void)BIO_reset(bio);
if (!(ASN1_TIME_print(bio, X509_get_notAfter(cert)))) {
tls_log_errors(NULL, LOG_WARN, "printing certificate lifetime");
tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
goto end;
}
BIO_get_mem_ptr(bio, &buf);
@ -1224,7 +1263,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
end:
/* Not expected to get invoked */
tls_log_errors(NULL, LOG_WARN, "getting certificate lifetime");
tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime");
if (bio)
BIO_free(bio);
if (s1)
@ -1298,7 +1337,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
if (!(id_pkey = X509_get_pubkey(id_cert)) ||
X509_verify(cert, id_pkey) <= 0) {
log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
tls_log_errors(tls, severity,"verifying certificate");
tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
goto done;
}
@ -1317,7 +1356,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_env_t **identity_key)
/* This should never get invoked, but let's make sure in case OpenSSL
* acts unexpectedly. */
tls_log_errors(tls, LOG_WARN, "finishing tor_tls_verify");
tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");
return r;
}
@ -1356,7 +1395,7 @@ tor_tls_check_lifetime(tor_tls_t *tls, int tolerance)
if (cert)
X509_free(cert);
/* Not expected to get invoked */
tls_log_errors(tls, LOG_WARN, "checking certificate lifetime");
tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");
return r;
}
@ -1424,7 +1463,7 @@ _check_no_tls_errors(const char *fname, int line)
return;
log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
tor_fix_source_file(fname), line);
tls_log_errors(NULL, LOG_WARN, NULL);
tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}
/** Return true iff the initial TLS connection at <b>tls</b> did not use a v2

414
src/common/tortls_states.h Normal file
View File

@ -0,0 +1,414 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Helper file: included only in tortls.c */
#ifndef _TORTLS_STATES_H
#define _TORTLS_STATES_H
/* The main body of this file was mechanically generated with this
perl script:
my %keys = ();
for $fn (@ARGV) {
open(F, $fn);
while (<F>) {
next unless /^#define ((?:SSL|DTLS)\w*_ST_\w*)/;
$keys{$1} = 1;
}
close(F);
}
for $k (sort keys %keys) {
print "#ifdef $k\n S($k),\n#endif\n"
}
*/
/** Mapping from allowed value of SSL.state to the name of C macro for that
* state. Used for debugging an openssl connection. */
static const struct { int state; const char *name; } state_map[] = {
#define S(state) { state, #state }
#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A
S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A),
#endif
#ifdef DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B
S(DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B),
#endif
#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A
S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A),
#endif
#ifdef DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B
S(DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B),
#endif
#ifdef SSL23_ST_CR_SRVR_HELLO_A
S(SSL23_ST_CR_SRVR_HELLO_A),
#endif
#ifdef SSL23_ST_CR_SRVR_HELLO_B
S(SSL23_ST_CR_SRVR_HELLO_B),
#endif
#ifdef SSL23_ST_CW_CLNT_HELLO_A
S(SSL23_ST_CW_CLNT_HELLO_A),
#endif
#ifdef SSL23_ST_CW_CLNT_HELLO_B
S(SSL23_ST_CW_CLNT_HELLO_B),
#endif
#ifdef SSL23_ST_SR_CLNT_HELLO_A
S(SSL23_ST_SR_CLNT_HELLO_A),
#endif
#ifdef SSL23_ST_SR_CLNT_HELLO_B
S(SSL23_ST_SR_CLNT_HELLO_B),
#endif
#ifdef SSL2_ST_CLIENT_START_ENCRYPTION
S(SSL2_ST_CLIENT_START_ENCRYPTION),
#endif
#ifdef SSL2_ST_GET_CLIENT_FINISHED_A
S(SSL2_ST_GET_CLIENT_FINISHED_A),
#endif
#ifdef SSL2_ST_GET_CLIENT_FINISHED_B
S(SSL2_ST_GET_CLIENT_FINISHED_B),
#endif
#ifdef SSL2_ST_GET_CLIENT_HELLO_A
S(SSL2_ST_GET_CLIENT_HELLO_A),
#endif
#ifdef SSL2_ST_GET_CLIENT_HELLO_B
S(SSL2_ST_GET_CLIENT_HELLO_B),
#endif
#ifdef SSL2_ST_GET_CLIENT_HELLO_C
S(SSL2_ST_GET_CLIENT_HELLO_C),
#endif
#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_A
S(SSL2_ST_GET_CLIENT_MASTER_KEY_A),
#endif
#ifdef SSL2_ST_GET_CLIENT_MASTER_KEY_B
S(SSL2_ST_GET_CLIENT_MASTER_KEY_B),
#endif
#ifdef SSL2_ST_GET_SERVER_FINISHED_A
S(SSL2_ST_GET_SERVER_FINISHED_A),
#endif
#ifdef SSL2_ST_GET_SERVER_FINISHED_B
S(SSL2_ST_GET_SERVER_FINISHED_B),
#endif
#ifdef SSL2_ST_GET_SERVER_HELLO_A
S(SSL2_ST_GET_SERVER_HELLO_A),
#endif
#ifdef SSL2_ST_GET_SERVER_HELLO_B
S(SSL2_ST_GET_SERVER_HELLO_B),
#endif
#ifdef SSL2_ST_GET_SERVER_VERIFY_A
S(SSL2_ST_GET_SERVER_VERIFY_A),
#endif
#ifdef SSL2_ST_GET_SERVER_VERIFY_B
S(SSL2_ST_GET_SERVER_VERIFY_B),
#endif
#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_A
S(SSL2_ST_SEND_CLIENT_CERTIFICATE_A),
#endif
#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_B
S(SSL2_ST_SEND_CLIENT_CERTIFICATE_B),
#endif
#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_C
S(SSL2_ST_SEND_CLIENT_CERTIFICATE_C),
#endif
#ifdef SSL2_ST_SEND_CLIENT_CERTIFICATE_D
S(SSL2_ST_SEND_CLIENT_CERTIFICATE_D),
#endif
#ifdef SSL2_ST_SEND_CLIENT_FINISHED_A
S(SSL2_ST_SEND_CLIENT_FINISHED_A),
#endif
#ifdef SSL2_ST_SEND_CLIENT_FINISHED_B
S(SSL2_ST_SEND_CLIENT_FINISHED_B),
#endif
#ifdef SSL2_ST_SEND_CLIENT_HELLO_A
S(SSL2_ST_SEND_CLIENT_HELLO_A),
#endif
#ifdef SSL2_ST_SEND_CLIENT_HELLO_B
S(SSL2_ST_SEND_CLIENT_HELLO_B),
#endif
#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_A
S(SSL2_ST_SEND_CLIENT_MASTER_KEY_A),
#endif
#ifdef SSL2_ST_SEND_CLIENT_MASTER_KEY_B
S(SSL2_ST_SEND_CLIENT_MASTER_KEY_B),
#endif
#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_A
S(SSL2_ST_SEND_REQUEST_CERTIFICATE_A),
#endif
#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_B
S(SSL2_ST_SEND_REQUEST_CERTIFICATE_B),
#endif
#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_C
S(SSL2_ST_SEND_REQUEST_CERTIFICATE_C),
#endif
#ifdef SSL2_ST_SEND_REQUEST_CERTIFICATE_D
S(SSL2_ST_SEND_REQUEST_CERTIFICATE_D),
#endif
#ifdef SSL2_ST_SEND_SERVER_FINISHED_A
S(SSL2_ST_SEND_SERVER_FINISHED_A),
#endif
#ifdef SSL2_ST_SEND_SERVER_FINISHED_B
S(SSL2_ST_SEND_SERVER_FINISHED_B),
#endif
#ifdef SSL2_ST_SEND_SERVER_HELLO_A
S(SSL2_ST_SEND_SERVER_HELLO_A),
#endif
#ifdef SSL2_ST_SEND_SERVER_HELLO_B
S(SSL2_ST_SEND_SERVER_HELLO_B),
#endif
#ifdef SSL2_ST_SEND_SERVER_VERIFY_A
S(SSL2_ST_SEND_SERVER_VERIFY_A),
#endif
#ifdef SSL2_ST_SEND_SERVER_VERIFY_B
S(SSL2_ST_SEND_SERVER_VERIFY_B),
#endif
#ifdef SSL2_ST_SEND_SERVER_VERIFY_C
S(SSL2_ST_SEND_SERVER_VERIFY_C),
#endif
#ifdef SSL2_ST_SERVER_START_ENCRYPTION
S(SSL2_ST_SERVER_START_ENCRYPTION),
#endif
#ifdef SSL2_ST_X509_GET_CLIENT_CERTIFICATE
S(SSL2_ST_X509_GET_CLIENT_CERTIFICATE),
#endif
#ifdef SSL2_ST_X509_GET_SERVER_CERTIFICATE
S(SSL2_ST_X509_GET_SERVER_CERTIFICATE),
#endif
#ifdef SSL3_ST_CR_CERT_A
S(SSL3_ST_CR_CERT_A),
#endif
#ifdef SSL3_ST_CR_CERT_B
S(SSL3_ST_CR_CERT_B),
#endif
#ifdef SSL3_ST_CR_CERT_REQ_A
S(SSL3_ST_CR_CERT_REQ_A),
#endif
#ifdef SSL3_ST_CR_CERT_REQ_B
S(SSL3_ST_CR_CERT_REQ_B),
#endif
#ifdef SSL3_ST_CR_CERT_STATUS_A
S(SSL3_ST_CR_CERT_STATUS_A),
#endif
#ifdef SSL3_ST_CR_CERT_STATUS_B
S(SSL3_ST_CR_CERT_STATUS_B),
#endif
#ifdef SSL3_ST_CR_CHANGE_A
S(SSL3_ST_CR_CHANGE_A),
#endif
#ifdef SSL3_ST_CR_CHANGE_B
S(SSL3_ST_CR_CHANGE_B),
#endif
#ifdef SSL3_ST_CR_FINISHED_A
S(SSL3_ST_CR_FINISHED_A),
#endif
#ifdef SSL3_ST_CR_FINISHED_B
S(SSL3_ST_CR_FINISHED_B),
#endif
#ifdef SSL3_ST_CR_KEY_EXCH_A
S(SSL3_ST_CR_KEY_EXCH_A),
#endif
#ifdef SSL3_ST_CR_KEY_EXCH_B
S(SSL3_ST_CR_KEY_EXCH_B),
#endif
#ifdef SSL3_ST_CR_SESSION_TICKET_A
S(SSL3_ST_CR_SESSION_TICKET_A),
#endif
#ifdef SSL3_ST_CR_SESSION_TICKET_B
S(SSL3_ST_CR_SESSION_TICKET_B),
#endif
#ifdef SSL3_ST_CR_SRVR_DONE_A
S(SSL3_ST_CR_SRVR_DONE_A),
#endif
#ifdef SSL3_ST_CR_SRVR_DONE_B
S(SSL3_ST_CR_SRVR_DONE_B),
#endif
#ifdef SSL3_ST_CR_SRVR_HELLO_A
S(SSL3_ST_CR_SRVR_HELLO_A),
#endif
#ifdef SSL3_ST_CR_SRVR_HELLO_B
S(SSL3_ST_CR_SRVR_HELLO_B),
#endif
#ifdef SSL3_ST_CW_CERT_A
S(SSL3_ST_CW_CERT_A),
#endif
#ifdef SSL3_ST_CW_CERT_B
S(SSL3_ST_CW_CERT_B),
#endif
#ifdef SSL3_ST_CW_CERT_C
S(SSL3_ST_CW_CERT_C),
#endif
#ifdef SSL3_ST_CW_CERT_D
S(SSL3_ST_CW_CERT_D),
#endif
#ifdef SSL3_ST_CW_CERT_VRFY_A
S(SSL3_ST_CW_CERT_VRFY_A),
#endif
#ifdef SSL3_ST_CW_CERT_VRFY_B
S(SSL3_ST_CW_CERT_VRFY_B),
#endif
#ifdef SSL3_ST_CW_CHANGE_A
S(SSL3_ST_CW_CHANGE_A),
#endif
#ifdef SSL3_ST_CW_CHANGE_B
S(SSL3_ST_CW_CHANGE_B),
#endif
#ifdef SSL3_ST_CW_CLNT_HELLO_A
S(SSL3_ST_CW_CLNT_HELLO_A),
#endif
#ifdef SSL3_ST_CW_CLNT_HELLO_B
S(SSL3_ST_CW_CLNT_HELLO_B),
#endif
#ifdef SSL3_ST_CW_FINISHED_A
S(SSL3_ST_CW_FINISHED_A),
#endif
#ifdef SSL3_ST_CW_FINISHED_B
S(SSL3_ST_CW_FINISHED_B),
#endif
#ifdef SSL3_ST_CW_FLUSH
S(SSL3_ST_CW_FLUSH),
#endif
#ifdef SSL3_ST_CW_KEY_EXCH_A
S(SSL3_ST_CW_KEY_EXCH_A),
#endif
#ifdef SSL3_ST_CW_KEY_EXCH_B
S(SSL3_ST_CW_KEY_EXCH_B),
#endif
#ifdef SSL3_ST_SR_CERT_A
S(SSL3_ST_SR_CERT_A),
#endif
#ifdef SSL3_ST_SR_CERT_B
S(SSL3_ST_SR_CERT_B),
#endif
#ifdef SSL3_ST_SR_CERT_VRFY_A
S(SSL3_ST_SR_CERT_VRFY_A),
#endif
#ifdef SSL3_ST_SR_CERT_VRFY_B
S(SSL3_ST_SR_CERT_VRFY_B),
#endif
#ifdef SSL3_ST_SR_CHANGE_A
S(SSL3_ST_SR_CHANGE_A),
#endif
#ifdef SSL3_ST_SR_CHANGE_B
S(SSL3_ST_SR_CHANGE_B),
#endif
#ifdef SSL3_ST_SR_CLNT_HELLO_A
S(SSL3_ST_SR_CLNT_HELLO_A),
#endif
#ifdef SSL3_ST_SR_CLNT_HELLO_B
S(SSL3_ST_SR_CLNT_HELLO_B),
#endif
#ifdef SSL3_ST_SR_CLNT_HELLO_C
S(SSL3_ST_SR_CLNT_HELLO_C),
#endif
#ifdef SSL3_ST_SR_FINISHED_A
S(SSL3_ST_SR_FINISHED_A),
#endif
#ifdef SSL3_ST_SR_FINISHED_B
S(SSL3_ST_SR_FINISHED_B),
#endif
#ifdef SSL3_ST_SR_KEY_EXCH_A
S(SSL3_ST_SR_KEY_EXCH_A),
#endif
#ifdef SSL3_ST_SR_KEY_EXCH_B
S(SSL3_ST_SR_KEY_EXCH_B),
#endif
#ifdef SSL3_ST_SW_CERT_A
S(SSL3_ST_SW_CERT_A),
#endif
#ifdef SSL3_ST_SW_CERT_B
S(SSL3_ST_SW_CERT_B),
#endif
#ifdef SSL3_ST_SW_CERT_REQ_A
S(SSL3_ST_SW_CERT_REQ_A),
#endif
#ifdef SSL3_ST_SW_CERT_REQ_B
S(SSL3_ST_SW_CERT_REQ_B),
#endif
#ifdef SSL3_ST_SW_CERT_STATUS_A
S(SSL3_ST_SW_CERT_STATUS_A),
#endif
#ifdef SSL3_ST_SW_CERT_STATUS_B
S(SSL3_ST_SW_CERT_STATUS_B),
#endif
#ifdef SSL3_ST_SW_CHANGE_A
S(SSL3_ST_SW_CHANGE_A),
#endif
#ifdef SSL3_ST_SW_CHANGE_B
S(SSL3_ST_SW_CHANGE_B),
#endif
#ifdef SSL3_ST_SW_FINISHED_A
S(SSL3_ST_SW_FINISHED_A),
#endif
#ifdef SSL3_ST_SW_FINISHED_B
S(SSL3_ST_SW_FINISHED_B),
#endif
#ifdef SSL3_ST_SW_FLUSH
S(SSL3_ST_SW_FLUSH),
#endif
#ifdef SSL3_ST_SW_HELLO_REQ_A
S(SSL3_ST_SW_HELLO_REQ_A),
#endif
#ifdef SSL3_ST_SW_HELLO_REQ_B
S(SSL3_ST_SW_HELLO_REQ_B),
#endif
#ifdef SSL3_ST_SW_HELLO_REQ_C
S(SSL3_ST_SW_HELLO_REQ_C),
#endif
#ifdef SSL3_ST_SW_KEY_EXCH_A
S(SSL3_ST_SW_KEY_EXCH_A),
#endif
#ifdef SSL3_ST_SW_KEY_EXCH_B
S(SSL3_ST_SW_KEY_EXCH_B),
#endif
#ifdef SSL3_ST_SW_SESSION_TICKET_A
S(SSL3_ST_SW_SESSION_TICKET_A),
#endif
#ifdef SSL3_ST_SW_SESSION_TICKET_B
S(SSL3_ST_SW_SESSION_TICKET_B),
#endif
#ifdef SSL3_ST_SW_SRVR_DONE_A
S(SSL3_ST_SW_SRVR_DONE_A),
#endif
#ifdef SSL3_ST_SW_SRVR_DONE_B
S(SSL3_ST_SW_SRVR_DONE_B),
#endif
#ifdef SSL3_ST_SW_SRVR_HELLO_A
S(SSL3_ST_SW_SRVR_HELLO_A),
#endif
#ifdef SSL3_ST_SW_SRVR_HELLO_B
S(SSL3_ST_SW_SRVR_HELLO_B),
#endif
#ifdef SSL_ST_ACCEPT
S(SSL_ST_ACCEPT),
#endif
#ifdef SSL_ST_BEFORE
S(SSL_ST_BEFORE),
#endif
#ifdef SSL_ST_CONNECT
S(SSL_ST_CONNECT),
#endif
#ifdef SSL_ST_INIT
S(SSL_ST_INIT),
#endif
#ifdef SSL_ST_MASK
S(SSL_ST_MASK),
#endif
#ifdef SSL_ST_OK
S(SSL_ST_OK),
#endif
#ifdef SSL_ST_READ_BODY
S(SSL_ST_READ_BODY),
#endif
#ifdef SSL_ST_READ_DONE
S(SSL_ST_READ_DONE),
#endif
#ifdef SSL_ST_READ_HEADER
S(SSL_ST_READ_HEADER),
#endif
#ifdef SSL_ST_RENEGOTIATE
S(SSL_ST_RENEGOTIATE),
#endif
{ 0, NULL }
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,5 @@
TESTS = test
noinst_PROGRAMS = test
bin_PROGRAMS = tor
noinst_LIBRARIES = libtor.a
if BUILD_NT_SERVICES
tor_platform_source=ntmain.c
@ -18,7 +15,7 @@ else
evdns_source=eventdns.c
endif
COMMON_SRC = buffers.c circuitbuild.c circuitlist.c \
libtor_a_SOURCES = buffers.c circuitbuild.c circuitlist.c \
circuituse.c command.c config.c \
connection.c connection_edge.c connection_or.c control.c \
cpuworker.c directory.c dirserv.c dirvote.c \
@ -28,7 +25,11 @@ COMMON_SRC = buffers.c circuitbuild.c circuitlist.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
$(evdns_source) config_codedigest.c
tor_SOURCES = $(COMMON_SRC) tor_main.c
#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
# ../common/libor-event.a
tor_SOURCES = tor_main.c
AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
@ -39,14 +40,7 @@ AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
# matters a lot there, and is quite hard to debug if you forget to do it.
tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
tor_LDADD = ../common/libor.a ../common/libor-crypto.a \
../common/libor-event.a \
-lz -lm -levent -lssl -lcrypto @TOR_LIB_WS32@ @TOR_LIB_GDI@
test_SOURCES = $(COMMON_SRC) test_data.c test.c
test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
test_LDADD = ../common/libor.a ../common/libor-crypto.a \
tor_LDADD = ./libtor.a ../common/libor.a ../common/libor-crypto.a \
../common/libor-event.a \
-lz -lm -levent -lssl -lcrypto @TOR_LIB_WS32@ @TOR_LIB_GDI@
@ -71,17 +65,15 @@ micro-revision.i: FORCE
mv micro-revision.tmp micro-revision.i; \
fi; true
or_sha1.i: $(tor_SOURCES) test_data.c test.c
or_sha1.i: $(tor_SOURCES)
if test "@SHA1SUM@" != none; then \
@SHA1SUM@ $(tor_SOURCES) test_data.c test.c | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
@SHA1SUM@ $(tor_SOURCES) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
elif test "@OPENSSL@" != none; then \
@OPENSSL@ sha1 $(tor_SOURCES) test_data.c test.c | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
@OPENSSL@ sha1 $(tor_SOURCES) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
else \
rm or_sha1.i; \
touch or_sha1.i; \
fi
#Dummy target to ensure that micro-revision.i _always_ gets built.
FORCE:

View File

@ -162,7 +162,7 @@ circuit_build_times_init(circuit_build_times_t *cbt)
}
/**
* Rewind our timeout history by n positions.
* Rewind our timeout history by n timeout positions.
*/
static void
circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
@ -170,6 +170,8 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
int i = 0;
if (cbt->pre_timeouts) {
/* If we have pre-timeouts, it means we're not yet storing
* timeouts in our normal array. Only rewind the counter. */
if (cbt->pre_timeouts > n) {
cbt->pre_timeouts -= n;
} else {
@ -180,8 +182,6 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
"Pre-timeouts: %d", n, cbt->build_times_idx,
cbt->total_build_times, cbt->pre_timeouts);
tor_assert(cbt->build_times_idx == 0);
tor_assert(cbt->total_build_times == 0);
return;
}
@ -204,21 +204,18 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
}
/**
* Add a timeoutout value to the set of build times. Time units
* are milliseconds
* Add a new timeout value <b>time</b> to the set of build times. Time
* units are milliseconds.
*
* circuit_build_times is a circular array, so loop around when
* circuit_build_times <b>cbt</a> is a circular array, so loop around when
* array is full.
*/
int
circuit_build_times_add_time(circuit_build_times_t *cbt, build_time_t time)
{
if (time > BUILD_TIME_MAX) {
log_notice(LD_CIRC,
"Circuit build time of %ums exceeds max. Capping at 65536ms", time);
time = BUILD_TIME_MAX;
} else if (time <= 0) {
log_err(LD_CIRC, "Circuit build time is %u!", time);
tor_assert(time <= BUILD_TIME_MAX);
if (time <= 0) {
log_warn(LD_CIRC, "Circuit build time is %u!", time);
return -1;
}
@ -372,18 +369,29 @@ circuit_build_times_update_state(circuit_build_times_t *cbt,
* Stolen from http://en.wikipedia.org/wiki/Fisher\u2013Yates_shuffle
*/
static void
circuit_build_times_shuffle_array(circuit_build_times_t *cbt)
circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
build_time_t *raw_times,
int num_times)
{
int n = cbt->total_build_times;
int n = num_times;
if (num_times > NCIRCUITS_TO_OBSERVE) {
log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d",
num_times, NCIRCUITS_TO_OBSERVE);
}
/* This code can only be run on a compact array */
tor_assert(cbt->total_build_times == cbt->build_times_idx);
while (n-- > 1) {
int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
build_time_t tmp = cbt->circuit_build_times[k];
cbt->circuit_build_times[k] = cbt->circuit_build_times[n];
cbt->circuit_build_times[n] = tmp;
}
/* This code can only be run on a compact array */
while (n-- > 1) {
int k = crypto_rand_int(n + 1); /* 0 <= k <= n. */
build_time_t tmp = raw_times[k];
raw_times[k] = raw_times[n];
raw_times[n] = tmp;
}
/* Since the times are now shuffled, take a random NCIRCUITS_TO_OBSERVE
* subset (ie the first NCIRCUITS_TO_OBSERVE values) */
for (n = 0; n < MIN(num_times, NCIRCUITS_TO_OBSERVE); n++) {
circuit_build_times_add_time(cbt, raw_times[n]);
}
}
/**
@ -397,14 +405,14 @@ int
circuit_build_times_parse_state(circuit_build_times_t *cbt,
or_state_t *state, char **msg)
{
int tot_values = 0, N = 0;
int tot_values = 0;
uint32_t loaded_cnt = 0, N = 0;
config_line_t *line;
int i;
*msg = NULL;
build_time_t *loaded_times = tor_malloc(sizeof(build_time_t)
* state->TotalBuildTimes);
circuit_build_times_init(cbt);
/* We don't support decreasing the table size yet */
tor_assert(state->TotalBuildTimes <= NCIRCUITS_TO_OBSERVE);
*msg = NULL;
for (line = state->BuildtimeHistogram; line; line = line->next) {
smartlist_t *args = smartlist_create();
@ -427,6 +435,8 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
if (!ok) {
*msg = tor_strdup("Unable to parse circuit build times: "
"Unparsable bin number");
SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
smartlist_free(args);
break;
}
count = (uint32_t)tor_parse_ulong(count_str, 0, 0,
@ -434,20 +444,37 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
if (!ok) {
*msg = tor_strdup("Unable to parse circuit build times: "
"Unparsable bin count");
SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
smartlist_free(args);
break;
}
if (loaded_cnt+count > state->TotalBuildTimes) {
log_warn(LD_CIRC,
"Too many build times in state file. "
"Stopping short before %d",
loaded_cnt+count);
SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
smartlist_free(args);
break;
}
for (k = 0; k < count; k++) {
circuit_build_times_add_time(cbt, ms);
loaded_times[loaded_cnt++] = ms;
}
N++;
SMARTLIST_FOREACH(args, char*, cp, tor_free(cp));
smartlist_free(args);
}
}
circuit_build_times_shuffle_array(cbt);
if (loaded_cnt != state->TotalBuildTimes) {
log_warn(LD_CIRC,
"Corrupt state file? Build times count mismatch. "
"Read %d, file says %d", loaded_cnt, state->TotalBuildTimes);
}
circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt);
/* Verify that we didn't overwrite any indexes */
for (i=0; i < NCIRCUITS_TO_OBSERVE; i++) {
@ -458,9 +485,10 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
log_info(LD_CIRC,
"Loaded %d/%d values from %d lines in circuit time histogram",
tot_values, cbt->total_build_times, N);
tor_assert(cbt->total_build_times == state->TotalBuildTimes);
tor_assert(tot_values == cbt->total_build_times);
tor_assert(cbt->total_build_times == tot_values);
tor_assert(cbt->total_build_times <= NCIRCUITS_TO_OBSERVE);
circuit_build_times_set_timeout(cbt);
tor_free(loaded_times);
return *msg ? -1 : 0;
}
@ -598,10 +626,10 @@ circuit_build_times_add_timeout_worker(circuit_build_times_t *cbt,
"%ums vs %lfms using Xm: %d a: %lf, q: %lf",
gentime, cbt->timeout_ms, cbt->Xm, cbt->alpha, quantile_cutoff);
} else if (gentime > BUILD_TIME_MAX) {
gentime = BUILD_TIME_MAX;
log_info(LD_CIRC,
"Generated a synthetic timeout larger than the max: %u",
gentime);
gentime = BUILD_TIME_MAX;
} else {
log_info(LD_CIRC, "Generated synthetic circuit build time %u for timeout",
gentime);
@ -624,7 +652,7 @@ circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
// CircBuildTimeout = Xm*((1-0.8))^(-1/a))
// ln(CircBuildTimeout) = ln(Xm)+ln(((1-0.8)))*(-1/a)
// -ln(1-0.8)/(ln(CircBuildTimeout)-ln(Xm))=a
tor_assert(quantile > 0);
tor_assert(quantile >= 0);
tor_assert(cbt->Xm > 0);
cbt->alpha = ln(1.0-quantile)/(ln(cbt->Xm)-ln(timeout_ms));
tor_assert(cbt->alpha > 0);
@ -727,10 +755,8 @@ circuit_build_times_network_timeout(circuit_build_times_t *cbt,
if (cbt->liveness.network_last_live <= start_time &&
start_time <= (now - cbt->timeout_ms/1000.0)) {
cbt->liveness.nonlive_timeouts++;
}
/* Check for one-hop timeout */
if (did_onehop) {
} else if (did_onehop) {
/* Count a one-hop timeout */
cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1;
cbt->liveness.after_firsthop_idx++;
cbt->liveness.after_firsthop_idx %= RECENT_CIRCUITS;
@ -797,7 +823,7 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
timeout_count += cbt->liveness.timeouts_after_firsthop[i];
}
/* If 75% of our recent circuits are timing out after the first hop,
/* If 80% of our recent circuits are timing out after the first hop,
* we need to re-estimate a new initial alpha and timeout. */
if (timeout_count < MAX_RECENT_TIMEOUT_COUNT) {
return 0;
@ -1477,17 +1503,19 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) {
struct timeval end;
long timediff;
tor_gettimeofday(&end);
timediff = tv_mdiff(&circ->_base.highres_created, &end);
if (timediff > INT32_MAX)
timediff = INT32_MAX;
/* done building the circuit. whew. */
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
circuit_build_times_add_time(&circ_times, (build_time_t)timediff);
circuit_build_times_network_circ_success(&circ_times);
circuit_build_times_set_timeout(&circ_times);
if (!circ->build_state->onehop_tunnel) {
struct timeval end;
long timediff;
tor_gettimeofday(&end);
timediff = tv_mdiff(&circ->_base.highres_created, &end);
if (timediff > INT32_MAX)
timediff = INT32_MAX;
circuit_build_times_add_time(&circ_times, (build_time_t)timediff);
circuit_build_times_network_circ_success(&circ_times);
circuit_build_times_set_timeout(&circ_times);
}
log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0);
if (circ->build_state->onehop_tunnel)

View File

@ -915,14 +915,14 @@ add_default_trusted_dir_authorities(authority_type_t type)
int i;
const char *dirservers[] = {
"moria1 v1 orport=9001 v3ident=E2A2AF570166665D738736D0DD58169CC61D8A8B "
"128.31.0.34:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441",
"128.31.0.39:9031 FFCB 46DB 1339 DA84 674C 70D7 CB58 6434 C437 0441",
"moria2 v1 orport=9002 128.31.0.34:9032 "
"719B E45D E224 B607 C537 07D0 E214 3E2D 423E 74CF",
"tor26 v1 orport=443 v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
"86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
"dizum orport=443 v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
"194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
"Tonga orport=443 bridge no-v2 82.94.251.206:80 "
"Tonga orport=443 bridge no-v2 82.94.251.203:80 "
"4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
"ides orport=9090 no-v2 v3ident=27B6B5996C426270A5C95488AA5BCEB6BCC86956 "
"216.224.124.114:9030 F397 038A DC51 3361 35E7 B80B D99C A384 4360 292B",
@ -2696,6 +2696,8 @@ is_listening_on_low_port(uint16_t port_option,
const config_line_t *listen_options)
{
#ifdef MS_WINDOWS
(void) port_option;
(void) listen_options;
return 0; /* No port is too low for windows. */
#else
const config_line_t *l;

View File

@ -2352,7 +2352,7 @@ loop_again:
if (n_read) {
/* Probably a no-op, but hey. */
connection_buckets_decrement(linked, approx_time(), 0, n_read);
connection_buckets_decrement(linked, approx_time(), n_read, 0);
if (connection_flushed_some(linked) < 0)
connection_mark_for_close(linked);

View File

@ -1547,18 +1547,6 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
uint32_t answer;
struct in_addr in;
/* Reply to resolves immediately if we can. */
if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
log_warn(LD_APP,"Address to be resolved is too large. Failing.");
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
connection_ap_handshake_socks_resolved(conn,
RESOLVED_TYPE_ERROR_TRANSIENT,
0,NULL,-1,TIME_MAX);
connection_mark_unattached_ap(conn,
END_STREAM_REASON_SOCKSPROTOCOL |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
return -1;
}
if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
/* leave it in network order */
answer = in.s_addr;
@ -2156,12 +2144,6 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
tor_assert(payload_len <= (int)sizeof(inaddr_buf));
}
if (payload_len > RELAY_PAYLOAD_SIZE) {
/* This should be impossible: we don't accept addresses this big. */
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
return -1;
}
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);

View File

@ -289,7 +289,7 @@ connection_or_finished_connecting(or_connection_t *or_conn)
conn = TO_CONN(or_conn);
tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
log_debug(LD_OR,"OR connect() to router at %s:%u finished.",
log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.",
conn->address,conn->port);
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
@ -780,7 +780,7 @@ connection_tls_start_handshake(or_connection_t *conn, int receiving)
return -1;
}
connection_start_reading(TO_CONN(conn));
log_debug(LD_OR,"starting TLS handshake on fd %d", conn->_base.s);
log_debug(LD_HANDSHAKE,"starting TLS handshake on fd %d", conn->_base.s);
note_crypto_pk_op(receiving ? TLS_HANDSHAKE_S : TLS_HANDSHAKE_C);
if (connection_tls_continue_handshake(conn) < 0) {
@ -920,12 +920,12 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
check_no_tls_errors();
has_cert = tor_tls_peer_has_cert(conn->tls);
if (started_here && !has_cert) {
log_info(LD_PROTOCOL,"Tried connecting to router at %s:%d, but it didn't "
log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't "
"send a cert! Closing.",
safe_address, conn->_base.port);
return -1;
} else if (!has_cert) {
log_debug(LD_PROTOCOL,"Got incoming connection with no certificate. "
log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. "
"That's ok.");
}
check_no_tls_errors();
@ -934,15 +934,16 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
int v = tor_tls_verify(started_here?severity:LOG_INFO,
conn->tls, &identity_rcvd);
if (started_here && v<0) {
log_fn(severity,LD_OR,"Tried connecting to router at %s:%d: It"
log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It"
" has a cert but it's invalid. Closing.",
safe_address, conn->_base.port);
return -1;
} else if (v<0) {
log_info(LD_PROTOCOL,"Incoming connection gave us an invalid cert "
log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert "
"chain; ignoring.");
} else {
log_debug(LD_OR,"The certificate seems to be valid on %s connection "
log_debug(LD_HANDSHAKE,
"The certificate seems to be valid on %s connection "
"with %s:%d", conn_type, safe_address, conn->_base.port);
}
check_no_tls_errors();
@ -969,7 +970,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
conn->nickname[0] = '$';
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
log_info(LD_OR, "Connected to router %s at %s:%d without knowing "
log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing "
"its key. Hoping for the best.",
conn->nickname, conn->_base.address, conn->_base.port);
}
@ -985,7 +986,7 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
base16_encode(seen, sizeof(seen), digest_rcvd_out, DIGEST_LEN);
base16_encode(expected, sizeof(expected), conn->identity_digest,
DIGEST_LEN);
log_fn(severity, LD_OR,
log_fn(severity, LD_HANDSHAKE,
"Tried connecting to router at %s:%d, but identity key was not "
"as expected: wanted %s but got %s.",
conn->_base.address, conn->_base.port, expected, seen);
@ -1027,7 +1028,7 @@ connection_tls_finish_handshake(or_connection_t *conn)
char digest_rcvd[DIGEST_LEN];
int started_here = connection_or_nonopen_was_started_here(conn);
log_debug(LD_OR,"tls handshake with %s done. verifying.",
log_debug(LD_HANDSHAKE,"tls handshake with %s done. verifying.",
safe_str(conn->_base.address));
directory_set_dirty();

View File

@ -371,10 +371,10 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
/* 0.1.1.17-rc was the first version that claimed to be stable, doesn't
* crash and drop circuits all the time, and is even vaguely compatible with
* the current network */
if (platform && !tor_version_as_new_as(platform,"0.1.1.17-rc")) {
/* Tor 0.1.2.x is pretty old, but there are a lot of them running still,
* and there aren't any critical relay-side vulnerabilities. Once more
* of them die off, we should raise this minimum to 0.2.0.x. */
if (platform && !tor_version_as_new_as(platform,"0.1.2.14")) {
if (msg)
*msg = "Tor version is far too old to work.";
return FP_REJECT;
@ -896,6 +896,13 @@ list_single_server_status(routerinfo_t *desc, int is_live)
return tor_strdup(buf);
}
static INLINE int
running_long_enough_to_decide_unreachable(void)
{
return time_of_process_start
+ get_options()->TestingAuthDirTimeToLearnReachability < approx_time();
}
/** Each server needs to have passed a reachability test no more
* than this number of seconds ago, or he is listed as down in
* the directory. */
@ -907,6 +914,10 @@ list_single_server_status(routerinfo_t *desc, int is_live)
void
dirserv_set_router_is_running(routerinfo_t *router, time_t now)
{
/*XXXX022 This function is a mess. Separate out the part that calculates
whether it's reachable and the part that tells rephist that the router was
unreachable.
*/
int answer;
if (router_is_me(router) && !we_are_hibernating())
@ -915,7 +926,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
answer = get_options()->AssumeReachable ||
now < router->last_reachable + REACHABLE_TIMEOUT;
if (!answer) {
if (!answer && running_long_enough_to_decide_unreachable()) {
/* not considered reachable. tell rephist. */
rep_hist_note_router_unreachable(router->cache_info.identity_digest, now);
}
@ -2390,9 +2401,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
}
fclose(fp);
log_notice(LD_DIRSERV,
"Bandwidth measurement file successfully read. "
"Applied %d measurements.", applied_lines);
log_info(LD_DIRSERV,
"Bandwidth measurement file successfully read. "
"Applied %d measurements.", applied_lines);
return 0;
}
@ -2420,15 +2431,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
networkstatus_voter_info_t *voter = NULL;
vote_timing_t timing;
digestmap_t *omit_as_sybil = NULL;
int vote_on_reachability = 1;
const int vote_on_reachability = running_long_enough_to_decide_unreachable();
tor_assert(private_key);
tor_assert(cert);
if (now - time_of_process_start <
options->TestingAuthDirTimeToLearnReachability)
vote_on_reachability = 0;
if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
log_warn(LD_NET, "Couldn't resolve my hostname");
return NULL;

View File

@ -370,10 +370,12 @@ static void
rotate_request_period(void)
{
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
#if REQUEST_HIST_LEN > 1
memmove(&c->n_v2_ns_requests[0], &c->n_v2_ns_requests[1],
sizeof(uint32_t)*(REQUEST_HIST_LEN-1));
memmove(&c->n_v3_ns_requests[0], &c->n_v3_ns_requests[1],
sizeof(uint32_t)*(REQUEST_HIST_LEN-1));
#endif
c->n_v2_ns_requests[REQUEST_HIST_LEN-1] = 0;
c->n_v3_ns_requests[REQUEST_HIST_LEN-1] = 0;
});
@ -393,7 +395,7 @@ geoip_note_client_seen(geoip_client_action_t action,
clientmap_entry_t lookup, *ent;
if (action == GEOIP_CLIENT_CONNECT) {
/* Only remember statistics as entry guard or as bridge. */
if (!options->EntryStatistics ||
if (!options->EntryStatistics &&
(!(options->BridgeRelay && options->BridgeRecordUsageByCountry)))
return;
/* Did we recently switch from bridge to relay or back? */
@ -1009,6 +1011,8 @@ geoip_dirreq_stats_write(time_t now)
if (fprintf(out, "dirreq-v3-reqs %s\ndirreq-v2-reqs %s\n",
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
goto done;
tor_free(data_v2);
tor_free(data_v3);
#define RESPONSE_GRANULARITY 8
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
ns_v2_responses[i] = round_uint32_to_next_multiple_of(

View File

@ -981,7 +981,6 @@ run_scheduled_events(time_t now)
time_to_write_stats_files = now + WRITE_STATS_INTERVAL;
} else {
/* Write stats to disk. */
time_to_write_stats_files += WRITE_STATS_INTERVAL;
if (options->CellStatistics)
rep_hist_buffer_stats_write(time_to_write_stats_files);
if (options->DirReqStatistics)
@ -990,6 +989,7 @@ run_scheduled_events(time_t now)
geoip_entry_stats_write(time_to_write_stats_files);
if (options->ExitPortStatistics)
rep_hist_exit_stats_write(time_to_write_stats_files);
time_to_write_stats_files += WRITE_STATS_INTERVAL;
}
} else {
/* Never write stats to disk */

View File

@ -6,6 +6,12 @@
#define MAIN_PRIVATE
#include "or.h"
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#else
#include <event.h>
#endif
#include <tchar.h>
#define GENSRV_SERVICENAME TEXT("tor")
#define GENSRV_DISPLAYNAME TEXT("Tor Win32 Service")
@ -218,7 +224,7 @@ nt_service_control(DWORD request)
log_notice(LD_GENERAL,
"Got stop/shutdown request; shutting down cleanly.");
service_status.dwCurrentState = SERVICE_STOP_PENDING;
event_loopexit(&exit_now);
event_base_loopexit(tor_libevent_get_base(), &exit_now);
return;
}
service_fns.SetServiceStatus_fn(hStatus, &service_status);

View File

@ -2927,7 +2927,7 @@ typedef uint32_t build_time_t;
* This tells us to abandon timeout history and set
* the timeout back to BUILD_TIMEOUT_INITIAL_VALUE.
*/
#define MAX_RECENT_TIMEOUT_COUNT (lround(RECENT_CIRCUITS*0.75))
#define MAX_RECENT_TIMEOUT_COUNT (lround(RECENT_CIRCUITS*0.8))
/** Information about the state of our local network connection */
typedef struct {
@ -3867,7 +3867,7 @@ int dnsserv_launch_request(const char *name, int is_reverse);
#define DIR_ENTRY_RECORD_USAGE_RETAIN_IPS (24*60*60)
/** How long do we have to have observed per-country request history before
* we are willing to talk about it? */
#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (24*60*60)
#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (12*60*60)
#ifdef GEOIP_PRIVATE
int geoip_parse_entry(const char *line);

View File

@ -1461,9 +1461,9 @@ rep_hist_exit_stats_write(time_t now)
comma ? "," : "", other_streams)<0)
goto done;
/* Reset counters */
memset(exit_bytes_read, 0, sizeof(exit_bytes_read));
memset(exit_bytes_written, 0, sizeof(exit_bytes_written));
memset(exit_streams, 0, sizeof(exit_streams));
memset(exit_bytes_read, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
memset(exit_bytes_written, 0, EXIT_STATS_NUM_PORTS * sizeof(uint64_t));
memset(exit_streams, 0, EXIT_STATS_NUM_PORTS * sizeof(uint32_t));
start_of_exit_stats_interval = now;
if (open_file)
@ -2771,6 +2771,7 @@ rep_hist_buffer_stats_write(time_t now)
goto done;
finish_writing_to_file(open_file);
open_file = NULL;
start_of_buffer_stats_interval = now;
done:
if (open_file)
abort_writing_to_file(open_file);

View File

@ -1826,9 +1826,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
/** Load the contents of <b>filename</b>, find the last line starting with
* <b>end_line</b>, ensure that its timestamp is not more than 25 hours in
* the past or more than 1 hour in the future with respect to <b>now</b>,
* and write the file contents starting with that line to **<b>out</b>.
* Return 1 for success, 0 if the file does not exist or does not contain
* a line matching these criteria, or -1 for failure. */
* and write the file contents starting with that line to *<b>out</b>.
* Return 1 for success, 0 if the file does not exist, or -1 if the file
* does not contain a line matching these criteria or other failure. */
static int
load_stats_file(const char *filename, const char *end_line, time_t now,
char **out)
@ -1903,11 +1903,11 @@ extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
char *contents = NULL;
time_t since = time(NULL) - (24*60*60);
time_t now = time(NULL);
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
if (options->DirReqStatistics &&
load_stats_file("stats"PATH_SEPARATOR"dirreq-stats",
"dirreq-stats-end", since, &contents) > 0) {
"dirreq-stats-end", now, &contents) > 0) {
size_t pos = strlen(s);
if (strlcpy(s + pos, contents, maxlen - strlen(s)) !=
strlen(contents)) {
@ -1919,7 +1919,7 @@ extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
}
if (options->EntryStatistics &&
load_stats_file("stats"PATH_SEPARATOR"entry-stats",
"entry-stats-end", since, &contents) > 0) {
"entry-stats-end", now, &contents) > 0) {
size_t pos = strlen(s);
if (strlcpy(s + pos, contents, maxlen - strlen(s)) !=
strlen(contents)) {
@ -1931,7 +1931,7 @@ extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
}
if (options->CellStatistics &&
load_stats_file("stats"PATH_SEPARATOR"buffer-stats",
"cell-stats-end", since, &contents) > 0) {
"cell-stats-end", now, &contents) > 0) {
size_t pos = strlen(s);
if (strlcpy(s + pos, contents, maxlen - strlen(s)) !=
strlen(contents)) {
@ -1943,7 +1943,7 @@ extrainfo_dump_to_string(char *s, size_t maxlen, extrainfo_t *extrainfo,
}
if (options->ExitPortStatistics &&
load_stats_file("stats"PATH_SEPARATOR"exit-stats",
"exit-stats-end", since, &contents) > 0) {
"exit-stats-end", now, &contents) > 0) {
size_t pos = strlen(s);
if (strlcpy(s + pos, contents, maxlen - strlen(s)) !=
strlen(contents)) {

File diff suppressed because it is too large Load Diff

31
src/test/Makefile.am Normal file
View File

@ -0,0 +1,31 @@
TESTS = test
noinst_PROGRAMS = test
AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
-DBINDIR="\"$(bindir)\""
AM_CFLAGS = -I../or
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
# This seems to matter nowhere but on windows, but I assure you that it
# matters a lot there, and is quite hard to debug if you forget to do it.
test_SOURCES = \
test_data.c \
test.c \
test_addr.c \
test_crypto.c \
test_dir.c \
test_containers.c \
test_util.c \
tinytest.c
test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
../common/libor-event.a \
-lz -lm -levent -lssl -lcrypto @TOR_LIB_WS32@ @TOR_LIB_GDI@
noinst_HEADERS = tinytest.h tinytest_macros.h

1212
src/test/test.c Normal file

File diff suppressed because it is too large Load Diff

75
src/test/test.h Normal file
View File

@ -0,0 +1,75 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef _TOR_TEST_H
#define _TOR_TEST_H
/**
* \file test.h
* \brief Macros and functions used by unit tests.
*/
#include "compat.h"
#include "tinytest.h"
#define TT_EXIT_TEST_FUNCTION STMT_BEGIN goto done; STMT_END
#include "tinytest_macros.h"
#ifdef __GNUC__
#define PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define PRETTY_FUNCTION ""
#endif
#define test_fail_msg(msg) TT_DIE((msg))
#define test_fail() test_fail_msg("Assertion failed.")
#define test_assert(expr) tt_assert(expr)
#define test_eq(expr1, expr2) tt_int_op((expr1), ==, (expr2))
#define test_eq_ptr(expr1, expr2) tt_ptr_op((expr1), ==, (expr2))
#define test_neq(expr1, expr2) tt_int_op((expr1), !=, (expr2))
#define test_neq_ptr(expr1, expr2) tt_ptr_op((expr1), !=, (expr2))
#define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2))
#define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2))
#define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2))
#define test_mem_op(expr1, op, expr2, len) \
tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \
const char *, \
(memcmp(_val1, _val2, len) op 0), \
char *, "%s", \
{ size_t printlen = (len)*2+1; \
_print = tor_malloc(printlen); \
base16_encode(_print, printlen, _value, \
(len)); }, \
{ tor_free(_print); } \
);
#define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len)
#define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len)
/* As test_mem_op, but decodes 'hex' before comparing. There must be a
* local char* variable called mem_op_hex_tmp for this to work. */
#define test_mem_op_hex(expr1, op, hex) \
STMT_BEGIN \
size_t length = strlen(hex); \
tor_free(mem_op_hex_tmp); \
mem_op_hex_tmp = tor_malloc(length/2); \
tor_assert((length&1)==0); \
base16_decode(mem_op_hex_tmp, length/2, hex, length); \
test_mem_op(expr1, op, mem_op_hex_tmp, length/2); \
STMT_END
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
const char *get_fname(const char *name);
crypto_pk_env_t *pk_generate(int idx);
void legacy_test_helper(void *data);
extern const struct testcase_setup_t legacy_setup;
#endif

497
src/test/test_addr.c Normal file
View File

@ -0,0 +1,497 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
#include "test.h"
static void
test_addr_basic(void)
{
uint32_t u32;
uint16_t u16;
char *cp;
/* Test parse_addr_port */
cp = NULL; u32 = 3; u16 = 3;
test_assert(!parse_addr_port(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
test_streq(cp, "1.2.3.4");
test_eq(u32, 0x01020304u);
test_eq(u16, 0);
tor_free(cp);
test_assert(!parse_addr_port(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
test_streq(cp, "4.3.2.1");
test_eq(u32, 0x04030201u);
test_eq(u16, 99);
tor_free(cp);
test_assert(!parse_addr_port(LOG_WARN, "nonexistent.address:4040",
&cp, NULL, &u16));
test_streq(cp, "nonexistent.address");
test_eq(u16, 4040);
tor_free(cp);
test_assert(!parse_addr_port(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
test_streq(cp, "localhost");
test_eq(u32, 0x7f000001u);
test_eq(u16, 9999);
tor_free(cp);
u32 = 3;
test_assert(!parse_addr_port(LOG_WARN, "localhost", NULL, &u32, &u16));
test_eq(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
tor_free(cp);
test_eq(0, addr_mask_get_bits(0x0u));
test_eq(32, addr_mask_get_bits(0xFFFFFFFFu));
test_eq(16, addr_mask_get_bits(0xFFFF0000u));
test_eq(31, addr_mask_get_bits(0xFFFFFFFEu));
test_eq(1, addr_mask_get_bits(0x80000000u));
/* Test inet_ntop */
{
char tmpbuf[TOR_ADDR_BUF_LEN];
const char *ip = "176.192.208.224";
struct in_addr in;
tor_inet_pton(AF_INET, ip, &in);
tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf));
test_streq(tmpbuf, ip);
}
done:
;
}
#define _test_op_ip6(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
(memcmp(_val1->s6_addr, _val2->s6_addr, 16) op 0), \
char *, "%s", \
{ int i; char *cp; \
cp = _print = tor_malloc(64); \
for (i=0;i<16;++i) { \
tor_snprintf(cp, 3,"%02x", (unsigned)_value->s6_addr[i]);\
cp += 2; \
if (i != 15) *cp++ = ':'; \
} \
}, { tor_free(_print); } \
); \
STMT_END
/** Helper: Assert that two strings both decode as IPv6 addresses with
* tor_inet_pton(), and both decode to the same address. */
#define test_pton6_same(a,b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
_test_op_ip6(&a1,==,&a2,#a,#b); \
STMT_END
/** Helper: Assert that <b>a</b> is recognized as a bad IPv6 address by
* tor_inet_pton(). */
#define test_pton6_bad(a) \
test_eq(0, tor_inet_pton(AF_INET6, a, &a1))
/** Helper: assert that <b>a</b>, when parsed by tor_inet_pton() and displayed
* with tor_inet_ntop(), yields <b>b</b>. Also assert that <b>b</b> parses to
* the same value as <b>a</b>. */
#define test_ntop6_reduces(a,b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
_test_op_ip6(&a1, ==, &a2, a, b); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
* passes tor_addr_is_internal() with <b>for_listening</b>. */
#define test_internal_ip(a,for_listening) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
t1.family = AF_INET6; \
if (!tor_addr_is_internal(&t1, for_listening)) \
test_fail_msg( a "was not internal."); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
* does not pass tor_addr_is_internal() with <b>for_listening</b>. */
#define test_external_ip(a,for_listening) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
t1.family = AF_INET6; \
if (tor_addr_is_internal(&t1, for_listening)) \
test_fail_msg(a "was not external."); \
STMT_END
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare(). */
#define test_addr_compare(a, op, b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \
t1.family = t2.family = AF_INET6; \
r = tor_addr_compare(&t1,&t2,CMP_SEMANTIC); \
if (!(r op 0)) \
test_fail_msg("failed: tor_addr_compare("a","b") "#op" 0"); \
STMT_END
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare_masked() with <b>m</b> masked. */
#define test_addr_compare_masked(a, op, b, m) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \
t1.family = t2.family = AF_INET6; \
r = tor_addr_compare_masked(&t1,&t2,m,CMP_SEMANTIC); \
if (!(r op 0)) \
test_fail_msg("failed: tor_addr_compare_masked("a","b","#m") "#op" 0"); \
STMT_END
/** Helper: assert that <b>xx</b> is parseable as a masked IPv6 address with
* ports by tor_parse_mask_addr_ports(), with family <b>f</b>, IP address
* as 4 32-bit words <b>ip1...ip4</b>, mask bits as <b>mm</b>, and port range
* as <b>pt1..pt2</b>. */
#define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \
STMT_BEGIN \
test_eq(tor_addr_parse_mask_ports(xx, &t1, &mask, &port1, &port2), f); \
p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \
test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \
test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \
test_eq(htonl(ip3), tor_addr_to_in6_addr32(&t1)[2]); \
test_eq(htonl(ip4), tor_addr_to_in6_addr32(&t1)[3]); \
test_eq(mask, mm); \
test_eq(port1, pt1); \
test_eq(port2, pt2); \
STMT_END
/** Run unit tests for IPv6 encoding/decoding/manipulation functions. */
static void
test_addr_ip6_helpers(void)
{
char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN];
struct in6_addr a1, a2;
tor_addr_t t1, t2;
int r, i;
uint16_t port1, port2;
maskbits_t mask;
const char *p1;
struct sockaddr_storage sa_storage;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
// struct in_addr b1, b2;
/* Test tor_inet_ntop and tor_inet_pton: IPv6 */
/* ==== Converting to and from sockaddr_t. */
sin = (struct sockaddr_in *)&sa_storage;
sin->sin_family = AF_INET;
sin->sin_port = 9090;
sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/
tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);
test_eq(tor_addr_family(&t1), AF_INET);
test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102);
memset(&sa_storage, 0, sizeof(sa_storage));
test_eq(sizeof(struct sockaddr_in),
tor_addr_to_sockaddr(&t1, 1234, (struct sockaddr *)&sa_storage,
sizeof(sa_storage)));
test_eq(1234, ntohs(sin->sin_port));
test_eq(0x7f7f0102, ntohl(sin->sin_addr.s_addr));
memset(&sa_storage, 0, sizeof(sa_storage));
sin6 = (struct sockaddr_in6 *)&sa_storage;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(7070);
sin6->sin6_addr.s6_addr[0] = 128;
tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);
test_eq(tor_addr_family(&t1), AF_INET6);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
test_streq(p1, "8000::");
memset(&sa_storage, 0, sizeof(sa_storage));
test_eq(sizeof(struct sockaddr_in6),
tor_addr_to_sockaddr(&t1, 9999, (struct sockaddr *)&sa_storage,
sizeof(sa_storage)));
test_eq(AF_INET6, sin6->sin6_family);
test_eq(9999, ntohs(sin6->sin6_port));
test_eq(0x80000000, ntohl(S6_ADDR32(sin6->sin6_addr)[0]));
/* ==== tor_addr_lookup: static cases. (Can't test dns without knowing we
* have a good resolver. */
test_eq(0, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1));
test_eq(AF_INET, tor_addr_family(&t1));
test_eq(tor_addr_to_ipv4h(&t1), 0x7f808182);
test_eq(0, tor_addr_lookup("9000::5", AF_UNSPEC, &t1));
test_eq(AF_INET6, tor_addr_family(&t1));
test_eq(0x90, tor_addr_to_in6_addr8(&t1)[0]);
test_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
test_eq(0x05, tor_addr_to_in6_addr8(&t1)[15]);
/* === Test pton: valid af_inet6 */
/* Simple, valid parsing. */
r = tor_inet_pton(AF_INET6,
"0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1);
test_assert(r==1);
for (i=0;i<16;++i) { test_eq(i+1, (int)a1.s6_addr[i]); }
/* ipv4 ending. */
test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10",
"0102:0304:0506:0708:090A:0B0C:13.14.15.16");
/* shortened words. */
test_pton6_same("0001:0099:BEEF:0000:0123:FFFF:0001:0001",
"1:99:BEEF:0:0123:FFFF:1:1");
/* zeros at the beginning */
test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
"::9:c0a8:1:1");
test_pton6_same("0000:0000:0000:0000:0009:C0A8:0001:0001",
"::9:c0a8:0.1.0.1");
/* zeros in the middle. */
test_pton6_same("fe80:0000:0000:0000:0202:1111:0001:0001",
"fe80::202:1111:1:1");
/* zeros at the end. */
test_pton6_same("1000:0001:0000:0007:0000:0000:0000:0000",
"1000:1:0:7::");
/* === Test ntop: af_inet6 */
test_ntop6_reduces("0:0:0:0:0:0:0:0", "::");
test_ntop6_reduces("0001:0099:BEEF:0006:0123:FFFF:0001:0001",
"1:99:beef:6:123:ffff:1:1");
//test_ntop6_reduces("0:0:0:0:0:0:c0a8:0101", "::192.168.1.1");
test_ntop6_reduces("0:0:0:0:0:ffff:c0a8:0101", "::ffff:192.168.1.1");
test_ntop6_reduces("002:0:0000:0:3::4", "2::3:0:0:4");
test_ntop6_reduces("0:0::1:0:3", "::1:0:3");
test_ntop6_reduces("008:0::0", "8::");
test_ntop6_reduces("0:0:0:0:0:ffff::1", "::ffff:0.0.0.1");
test_ntop6_reduces("abcd:0:0:0:0:0:7f00::", "abcd::7f00:0");
test_ntop6_reduces("0000:0000:0000:0000:0009:C0A8:0001:0001",
"::9:c0a8:1:1");
test_ntop6_reduces("fe80:0000:0000:0000:0202:1111:0001:0001",
"fe80::202:1111:1:1");
test_ntop6_reduces("1000:0001:0000:0007:0000:0000:0000:0000",
"1000:1:0:7::");
/* === Test pton: invalid in6. */
test_pton6_bad("foobar.");
test_pton6_bad("55555::");
test_pton6_bad("9:-60::");
test_pton6_bad("1:2:33333:4:0002:3::");
//test_pton6_bad("1:2:3333:4:00002:3::");// BAD, but glibc doesn't say so.
test_pton6_bad("1:2:3333:4:fish:3::");
test_pton6_bad("1:2:3:4:5:6:7:8:9");
test_pton6_bad("1:2:3:4:5:6:7");
test_pton6_bad("1:2:3:4:5:6:1.2.3.4.5");
test_pton6_bad("1:2:3:4:5:6:1.2.3");
test_pton6_bad("::1.2.3");
test_pton6_bad("::1.2.3.4.5");
test_pton6_bad("99");
test_pton6_bad("");
test_pton6_bad("1::2::3:4");
test_pton6_bad("a:::b:c");
test_pton6_bad(":::a:b:c");
test_pton6_bad("a:b:c:::");
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
test_internal_ip("fc01::2:7", 0);
test_internal_ip("fdff:ffff::f:f", 0);
test_external_ip("fe00::3:f", 0);
test_external_ip("fe7f:ffff::2:7", 0);
test_internal_ip("fe80::2:7", 0);
test_internal_ip("febf:ffff::f:f", 0);
test_internal_ip("fec0::2:7:7", 0);
test_internal_ip("feff:ffff::e:7:7", 0);
test_external_ip("ff00::e:7:7", 0);
test_internal_ip("::", 0);
test_internal_ip("::1", 0);
test_internal_ip("::1", 1);
test_internal_ip("::", 0);
test_external_ip("::", 1);
test_external_ip("::2", 0);
test_external_ip("2001::", 0);
test_external_ip("ffff::", 0);
test_external_ip("::ffff:0.0.0.0", 1);
test_internal_ip("::ffff:0.0.0.0", 0);
test_internal_ip("::ffff:0.255.255.255", 0);
test_external_ip("::ffff:1.0.0.0", 0);
test_external_ip("::ffff:9.255.255.255", 0);
test_internal_ip("::ffff:10.0.0.0", 0);
test_internal_ip("::ffff:10.255.255.255", 0);
test_external_ip("::ffff:11.0.0.0", 0);
test_external_ip("::ffff:126.255.255.255", 0);
test_internal_ip("::ffff:127.0.0.0", 0);
test_internal_ip("::ffff:127.255.255.255", 0);
test_external_ip("::ffff:128.0.0.0", 0);
test_external_ip("::ffff:172.15.255.255", 0);
test_internal_ip("::ffff:172.16.0.0", 0);
test_internal_ip("::ffff:172.31.255.255", 0);
test_external_ip("::ffff:172.32.0.0", 0);
test_external_ip("::ffff:192.167.255.255", 0);
test_internal_ip("::ffff:192.168.0.0", 0);
test_internal_ip("::ffff:192.168.255.255", 0);
test_external_ip("::ffff:192.169.0.0", 0);
test_external_ip("::ffff:169.253.255.255", 0);
test_internal_ip("::ffff:169.254.0.0", 0);
test_internal_ip("::ffff:169.254.255.255", 0);
test_external_ip("::ffff:169.255.0.0", 0);
test_assert(is_internal_IP(0x7f000001, 0));
/* tor_addr_compare(tor_addr_t x2) */
test_addr_compare("ffff::", ==, "ffff::0");
test_addr_compare("0::3:2:1", <, "0::ffff:0.3.2.1");
test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
/* test compare_masked */
test_addr_compare_masked("ffff::", ==, "ffff::0", 128);
test_addr_compare_masked("ffff::", ==, "ffff::0", 64);
test_addr_compare_masked("0::2:2:1", <, "0::8000:2:1", 81);
test_addr_compare_masked("0::2:2:1", ==, "0::8000:2:1", 80);
/* Test decorated addr_to_string. */
test_eq(AF_INET6, tor_addr_from_str(&t1, "[123:45:6789::5005:11]"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "[123:45:6789::5005:11]");
test_eq(AF_INET, tor_addr_from_str(&t1, "18.0.0.1"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "18.0.0.1");
/* Test tor_addr_parse_reverse_lookup_name */
i = tor_addr_parse_reverse_lookup_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
test_eq(0, i);
i = tor_addr_parse_reverse_lookup_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
test_eq(0, i);
i = tor_addr_parse_reverse_lookup_name(&t1, "1.0.168.192.in-addr.arpa",
AF_UNSPEC, 1);
test_eq(1, i);
test_eq(tor_addr_family(&t1), AF_INET);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "192.168.0.1");
i = tor_addr_parse_reverse_lookup_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
test_eq(0, i);
i = tor_addr_parse_reverse_lookup_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
test_eq(1, i);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "192.168.0.99");
memset(&t1, 0, sizeof(t1));
i = tor_addr_parse_reverse_lookup_name(&t1,
"0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(1, i);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
test_streq(p1, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
/* Failing cases. */
i = tor_addr_parse_reverse_lookup_name(&t1,
"6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1,
"6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1, "32.1.1.in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1, ".in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_UNSPEC, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_INET6, 0);
test_eq(i, -1);
i = tor_addr_parse_reverse_lookup_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_INET, 0);
test_eq(i, -1);
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
//test_addr_parse("[::fefe:4.1.1.7/120]:999-1000");
//test_addr_parse_check("::fefe:401:107", 120, 999, 1000);
test_addr_mask_ports_parse("[::ffff:4.1.1.7]/120:443", AF_INET6,
0, 0, 0x0000ffff, 0x04010107, 120, 443, 443);
test_addr_mask_ports_parse("[abcd:2::44a:0]:2-65000", AF_INET6,
0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);
r=tor_addr_parse_mask_ports("[fefef::]/112", &t1, NULL, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("efef::/112", &t1, NULL, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]", &t1, NULL, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
test_assert(r == -1);
/* Test for V4-mapped address with mask < 96. (arguably not valid) */
r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]", &t1, &mask, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("1.1.2.2/33", &t1, &mask, NULL, NULL);
test_assert(r == -1);
r=tor_addr_parse_mask_ports("1.1.2.2/31", &t1, &mask, NULL, NULL);
test_assert(r == AF_INET);
r=tor_addr_parse_mask_ports("[efef::]/112", &t1, &mask, &port1, &port2);
test_assert(r == AF_INET6);
test_assert(port1 == 1);
test_assert(port2 == 65535);
/* make sure inet address lengths >= max */
test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
test_assert(TOR_ADDR_BUF_LEN >=
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));
test_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));
/* get interface addresses */
r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
#if 0
tor_inet_ntop(AF_INET, &t1.sa.sin_addr, buf, sizeof(buf));
printf("\nv4 address: %s (family=%i)", buf, IN_FAMILY(&t1));
tor_inet_ntop(AF_INET6, &t2.sa6.sin6_addr, buf, sizeof(buf));
printf("\nv6 address: %s (family=%i)", buf, IN_FAMILY(&t2));
#endif
done:
;
}
#define ADDR_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
END_OF_TESTCASES
};

719
src/test/test_containers.c Normal file
View File

@ -0,0 +1,719 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
#include "test.h"
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>. */
static int
_compare_strs(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
}
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>, excluding a's first character, and ignoring case. */
static int
_compare_without_first_ch(const void *a, const void **b)
{
const char *s1 = a, *s2 = *b;
return strcasecmp(s1+1, s2);
}
/** Run unit tests for basic dynamic-sized array functionality. */
static void
test_container_smartlist_basic(void)
{
smartlist_t *sl;
/* XXXX test sort_digests, uniq_strings, uniq_digests */
/* Test smartlist add, del_keeporder, insert, get. */
sl = smartlist_create();
smartlist_add(sl, (void*)1);
smartlist_add(sl, (void*)2);
smartlist_add(sl, (void*)3);
smartlist_add(sl, (void*)4);
smartlist_del_keeporder(sl, 1);
smartlist_insert(sl, 1, (void*)22);
smartlist_insert(sl, 0, (void*)0);
smartlist_insert(sl, 5, (void*)555);
test_eq_ptr((void*)0, smartlist_get(sl,0));
test_eq_ptr((void*)1, smartlist_get(sl,1));
test_eq_ptr((void*)22, smartlist_get(sl,2));
test_eq_ptr((void*)3, smartlist_get(sl,3));
test_eq_ptr((void*)4, smartlist_get(sl,4));
test_eq_ptr((void*)555, smartlist_get(sl,5));
/* Try deleting in the middle. */
smartlist_del(sl, 1);
test_eq_ptr((void*)555, smartlist_get(sl, 1));
/* Try deleting at the end. */
smartlist_del(sl, 4);
test_eq(4, smartlist_len(sl));
/* test isin. */
test_assert(smartlist_isin(sl, (void*)3));
test_assert(!smartlist_isin(sl, (void*)99));
done:
smartlist_free(sl);
}
/** Run unit tests for smartlist-of-strings functionality. */
static void
test_container_smartlist_strings(void)
{
smartlist_t *sl = smartlist_create();
char *cp=NULL, *cp_alloc=NULL;
size_t sz;
/* Test split and join */
test_eq(0, smartlist_len(sl));
smartlist_split_string(sl, "abc", ":", 0, 0);
test_eq(1, smartlist_len(sl));
test_streq("abc", smartlist_get(sl, 0));
smartlist_split_string(sl, "a::bc::", "::", 0, 0);
test_eq(4, smartlist_len(sl));
test_streq("a", smartlist_get(sl, 1));
test_streq("bc", smartlist_get(sl, 2));
test_streq("", smartlist_get(sl, 3));
cp_alloc = smartlist_join_strings(sl, "", 0, NULL);
test_streq(cp_alloc, "abcabc");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "!", 0, NULL);
test_streq(cp_alloc, "abc!a!bc!");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL);
test_streq(cp_alloc, "abcXYaXYbcXY");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL);
test_streq(cp_alloc, "abcXYaXYbcXYXY");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "", 1, NULL);
test_streq(cp_alloc, "abcabc");
tor_free(cp_alloc);
smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0);
test_eq(8, smartlist_len(sl));
test_streq("", smartlist_get(sl, 4));
test_streq("def", smartlist_get(sl, 5));
test_streq(" ", smartlist_get(sl, 6));
test_streq("ghijk", smartlist_get(sl, 7));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0);
test_eq(3, smartlist_len(sl));
test_streq("a", smartlist_get(sl,0));
test_streq("bbd", smartlist_get(sl,1));
test_streq("cdef", smartlist_get(sl,2));
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE, 0);
test_eq(8, smartlist_len(sl));
test_streq("z", smartlist_get(sl,3));
test_streq("zhasd", smartlist_get(sl,4));
test_streq("", smartlist_get(sl,5));
test_streq("bnud", smartlist_get(sl,6));
test_streq("", smartlist_get(sl,7));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, " ab\tc \td ef ", NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
test_eq(4, smartlist_len(sl));
test_streq("ab", smartlist_get(sl,0));
test_streq("c", smartlist_get(sl,1));
test_streq("d", smartlist_get(sl,2));
test_streq("ef", smartlist_get(sl,3));
smartlist_split_string(sl, "ghi\tj", NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
test_eq(6, smartlist_len(sl));
test_streq("ghi", smartlist_get(sl,4));
test_streq("j", smartlist_get(sl,5));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL);
test_streq(cp_alloc, "");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL);
test_streq(cp_alloc, "XY");
tor_free(cp_alloc);
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
test_eq(3, smartlist_len(sl));
test_streq("z", smartlist_get(sl, 0));
test_streq("zhasd", smartlist_get(sl, 1));
test_streq("bnud", smartlist_get(sl, 2));
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
test_eq(5, smartlist_len(sl));
test_streq("z", smartlist_get(sl, 3));
test_streq("zhasd <> <> bnud<>", smartlist_get(sl, 4));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, "abcd\n", "\n",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
test_eq(1, smartlist_len(sl));
test_streq("abcd", smartlist_get(sl, 0));
smartlist_split_string(sl, "efgh", "\n",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
test_eq(2, smartlist_len(sl));
test_streq("efgh", smartlist_get(sl, 1));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Test swapping, shuffling, and sorting. */
smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0);
test_eq(7, smartlist_len(sl));
smartlist_sort(sl, _compare_strs);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the");
tor_free(cp_alloc);
smartlist_swap(sl, 1, 5);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"and,router,by,nickm,onion,arma,the");
tor_free(cp_alloc);
smartlist_shuffle(sl);
test_eq(7, smartlist_len(sl));
test_assert(smartlist_string_isin(sl, "and"));
test_assert(smartlist_string_isin(sl, "router"));
test_assert(smartlist_string_isin(sl, "by"));
test_assert(smartlist_string_isin(sl, "nickm"));
test_assert(smartlist_string_isin(sl, "onion"));
test_assert(smartlist_string_isin(sl, "arma"));
test_assert(smartlist_string_isin(sl, "the"));
/* Test bsearch. */
smartlist_sort(sl, _compare_strs);
test_streq("nickm", smartlist_bsearch(sl, "zNicKM",
_compare_without_first_ch));
test_streq("and", smartlist_bsearch(sl, " AND", _compare_without_first_ch));
test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", _compare_without_first_ch));
/* Test bsearch_idx */
{
int f;
test_eq(0, smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f));
test_eq(f, 0);
test_eq(0, smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f));
test_eq(f, 1);
test_eq(1, smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f));
test_eq(f, 0);
test_eq(1, smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f));
test_eq(f, 1);
test_eq(2, smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f));
test_eq(f, 0);
test_eq(7, smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f));
test_eq(f, 0);
}
/* Test reverse() and pop_last() */
smartlist_reverse(sl);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"the,router,onion,nickm,by,arma,and");
tor_free(cp_alloc);
cp_alloc = smartlist_pop_last(sl);
test_streq(cp_alloc, "and");
tor_free(cp_alloc);
test_eq(smartlist_len(sl), 6);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_pop_last(sl);
test_eq(cp_alloc, NULL);
/* Test uniq() */
smartlist_split_string(sl,
"50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50",
",", 0, 0);
smartlist_sort(sl, _compare_strs);
smartlist_uniq(sl, _compare_strs, _tor_free);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp_alloc);
/* Test string_isin and isin_case and num_isin */
test_assert(smartlist_string_isin(sl, "noon"));
test_assert(!smartlist_string_isin(sl, "noonoon"));
test_assert(smartlist_string_isin_case(sl, "nOOn"));
test_assert(!smartlist_string_isin_case(sl, "nooNooN"));
test_assert(smartlist_string_num_isin(sl, 50));
test_assert(!smartlist_string_num_isin(sl, 60));
/* Test smartlist_choose */
{
int i;
int allsame = 1;
int allin = 1;
void *first = smartlist_choose(sl);
test_assert(smartlist_isin(sl, first));
for (i = 0; i < 100; ++i) {
void *second = smartlist_choose(sl);
if (second != first)
allsame = 0;
if (!smartlist_isin(sl, second))
allin = 0;
}
test_assert(!allsame);
test_assert(allin);
}
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Test string_remove and remove and join_strings2 */
smartlist_split_string(sl,
"Some say the Earth will end in ice and some in fire",
" ", 0, 0);
cp = smartlist_get(sl, 4);
test_streq(cp, "will");
smartlist_add(sl, cp);
smartlist_remove(sl, cp);
tor_free(cp);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc, "Some,say,the,Earth,fire,end,in,ice,and,some,in");
tor_free(cp_alloc);
smartlist_string_remove(sl, "in");
cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz);
test_streq(cp_alloc, "Some+say+the+Earth+fire+end+some+ice+and");
test_eq((int)sz, 40);
done:
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
tor_free(cp_alloc);
}
/** Run unit tests for smartlist set manipulation functions. */
static void
test_container_smartlist_overlap(void)
{
smartlist_t *sl = smartlist_create();
smartlist_t *ints = smartlist_create();
smartlist_t *odds = smartlist_create();
smartlist_t *evens = smartlist_create();
smartlist_t *primes = smartlist_create();
int i;
for (i=1; i < 10; i += 2)
smartlist_add(odds, (void*)(uintptr_t)i);
for (i=0; i < 10; i += 2)
smartlist_add(evens, (void*)(uintptr_t)i);
/* add_all */
smartlist_add_all(ints, odds);
smartlist_add_all(ints, evens);
test_eq(smartlist_len(ints), 10);
smartlist_add(primes, (void*)2);
smartlist_add(primes, (void*)3);
smartlist_add(primes, (void*)5);
smartlist_add(primes, (void*)7);
/* overlap */
test_assert(smartlist_overlap(ints, odds));
test_assert(smartlist_overlap(odds, primes));
test_assert(smartlist_overlap(evens, primes));
test_assert(!smartlist_overlap(odds, evens));
/* intersect */
smartlist_add_all(sl, odds);
smartlist_intersect(sl, primes);
test_eq(smartlist_len(sl), 3);
test_assert(smartlist_isin(sl, (void*)3));
test_assert(smartlist_isin(sl, (void*)5));
test_assert(smartlist_isin(sl, (void*)7));
/* subtract */
smartlist_add_all(sl, primes);
smartlist_subtract(sl, odds);
test_eq(smartlist_len(sl), 1);
test_assert(smartlist_isin(sl, (void*)2));
done:
smartlist_free(odds);
smartlist_free(evens);
smartlist_free(ints);
smartlist_free(primes);
smartlist_free(sl);
}
/** Run unit tests for smartlist-of-digests functions. */
static void
test_container_smartlist_digests(void)
{
smartlist_t *sl = smartlist_create();
/* digest_isin. */
smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
test_eq(0, smartlist_digest_isin(NULL, "AAAAAAAAAAAAAAAAAAAA"));
test_assert(smartlist_digest_isin(sl, "AAAAAAAAAAAAAAAAAAAA"));
test_assert(smartlist_digest_isin(sl, "\00090AAB2AAAAaasdAAAAA"));
test_eq(0, smartlist_digest_isin(sl, "\00090AAB2AAABaasdAAAAA"));
/* sort digests */
smartlist_sort_digests(sl);
test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
test_memeq(smartlist_get(sl, 1), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
test_memeq(smartlist_get(sl, 2), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
test_eq(3, smartlist_len(sl));
/* uniq_digests */
smartlist_uniq_digests(sl);
test_eq(2, smartlist_len(sl));
test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
test_memeq(smartlist_get(sl, 1), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
done:
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
}
/** Run unit tests for concatenate-a-smartlist-of-strings functions. */
static void
test_container_smartlist_join(void)
{
smartlist_t *sl = smartlist_create();
smartlist_t *sl2 = smartlist_create(), *sl3 = smartlist_create(),
*sl4 = smartlist_create();
char *joined=NULL;
/* unique, sorted. */
smartlist_split_string(sl,
"Abashments Ambush Anchorman Bacon Banks Borscht "
"Bunks Inhumane Insurance Knish Know Manners "
"Maraschinos Stamina Sunbonnets Unicorns Wombats",
" ", 0, 0);
/* non-unique, sorted. */
smartlist_split_string(sl2,
"Ambush Anchorman Anchorman Anemias Anemias Bacon "
"Crossbowmen Inhumane Insurance Knish Know Manners "
"Manners Maraschinos Wombats Wombats Work",
" ", 0, 0);
SMARTLIST_FOREACH_JOIN(sl, char *, cp1,
sl2, char *, cp2,
strcmp(cp1,cp2),
smartlist_add(sl3, cp2)) {
test_streq(cp1, cp2);
smartlist_add(sl4, cp1);
} SMARTLIST_FOREACH_JOIN_END(cp1, cp2);
SMARTLIST_FOREACH(sl3, const char *, cp,
test_assert(smartlist_isin(sl2, cp) &&
!smartlist_string_isin(sl, cp)));
SMARTLIST_FOREACH(sl4, const char *, cp,
test_assert(smartlist_isin(sl, cp) &&
smartlist_string_isin(sl2, cp)));
joined = smartlist_join_strings(sl3, ",", 0, NULL);
test_streq(joined, "Anemias,Anemias,Crossbowmen,Work");
tor_free(joined);
joined = smartlist_join_strings(sl4, ",", 0, NULL);
test_streq(joined, "Ambush,Anchorman,Anchorman,Bacon,Inhumane,Insurance,"
"Knish,Know,Manners,Manners,Maraschinos,Wombats,Wombats");
tor_free(joined);
done:
smartlist_free(sl4);
smartlist_free(sl3);
SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp));
smartlist_free(sl2);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
tor_free(joined);
}
/** Run unit tests for bitarray code */
static void
test_container_bitarray(void)
{
bitarray_t *ba = NULL;
int i, j, ok=1;
ba = bitarray_init_zero(1);
test_assert(ba);
test_assert(! bitarray_is_set(ba, 0));
bitarray_set(ba, 0);
test_assert(bitarray_is_set(ba, 0));
bitarray_clear(ba, 0);
test_assert(! bitarray_is_set(ba, 0));
bitarray_free(ba);
ba = bitarray_init_zero(1023);
for (i = 1; i < 64; ) {
for (j = 0; j < 1023; ++j) {
if (j % i)
bitarray_set(ba, j);
else
bitarray_clear(ba, j);
}
for (j = 0; j < 1023; ++j) {
if (!bool_eq(bitarray_is_set(ba, j), j%i))
ok = 0;
}
test_assert(ok);
if (i < 7)
++i;
else if (i == 28)
i = 32;
else
i += 7;
}
done:
if (ba)
bitarray_free(ba);
}
/** Run unit tests for digest set code (implemented as a hashtable or as a
* bloom filter) */
static void
test_container_digestset(void)
{
smartlist_t *included = smartlist_create();
char d[DIGEST_LEN];
int i;
int ok = 1;
int false_positives = 0;
digestset_t *set = NULL;
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
smartlist_add(included, tor_memdup(d, DIGEST_LEN));
}
set = digestset_new(1000);
SMARTLIST_FOREACH(included, const char *, cp,
if (digestset_isin(set, cp))
ok = 0);
test_assert(ok);
SMARTLIST_FOREACH(included, const char *, cp,
digestset_add(set, cp));
SMARTLIST_FOREACH(included, const char *, cp,
if (!digestset_isin(set, cp))
ok = 0);
test_assert(ok);
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
if (digestset_isin(set, d))
++false_positives;
}
test_assert(false_positives < 50); /* Should be far lower. */
done:
if (set)
digestset_free(set);
SMARTLIST_FOREACH(included, char *, cp, tor_free(cp));
smartlist_free(included);
}
/** Helper: return a tristate based on comparing two strings. */
static int
_compare_strings_for_pqueue(const void *s1, const void *s2)
{
return strcmp((const char*)s1, (const char*)s2);
}
/** Run unit tests for heap-based priority queue functions. */
static void
test_container_pqueue(void)
{
smartlist_t *sl = smartlist_create();
int (*cmp)(const void *, const void*);
#define OK() smartlist_pqueue_assert_ok(sl, cmp)
cmp = _compare_strings_for_pqueue;
smartlist_pqueue_add(sl, cmp, (char*)"cows");
smartlist_pqueue_add(sl, cmp, (char*)"zebras");
smartlist_pqueue_add(sl, cmp, (char*)"fish");
smartlist_pqueue_add(sl, cmp, (char*)"frogs");
smartlist_pqueue_add(sl, cmp, (char*)"apples");
smartlist_pqueue_add(sl, cmp, (char*)"squid");
smartlist_pqueue_add(sl, cmp, (char*)"daschunds");
smartlist_pqueue_add(sl, cmp, (char*)"eggplants");
smartlist_pqueue_add(sl, cmp, (char*)"weissbier");
smartlist_pqueue_add(sl, cmp, (char*)"lobsters");
smartlist_pqueue_add(sl, cmp, (char*)"roquefort");
OK();
test_eq(smartlist_len(sl), 11);
test_streq(smartlist_get(sl, 0), "apples");
test_streq(smartlist_pqueue_pop(sl, cmp), "apples");
test_eq(smartlist_len(sl), 10);
OK();
test_streq(smartlist_pqueue_pop(sl, cmp), "cows");
test_streq(smartlist_pqueue_pop(sl, cmp), "daschunds");
smartlist_pqueue_add(sl, cmp, (char*)"chinchillas");
OK();
smartlist_pqueue_add(sl, cmp, (char*)"fireflies");
OK();
test_streq(smartlist_pqueue_pop(sl, cmp), "chinchillas");
test_streq(smartlist_pqueue_pop(sl, cmp), "eggplants");
test_streq(smartlist_pqueue_pop(sl, cmp), "fireflies");
OK();
test_streq(smartlist_pqueue_pop(sl, cmp), "fish");
test_streq(smartlist_pqueue_pop(sl, cmp), "frogs");
test_streq(smartlist_pqueue_pop(sl, cmp), "lobsters");
test_streq(smartlist_pqueue_pop(sl, cmp), "roquefort");
OK();
test_eq(smartlist_len(sl), 3);
test_streq(smartlist_pqueue_pop(sl, cmp), "squid");
test_streq(smartlist_pqueue_pop(sl, cmp), "weissbier");
test_streq(smartlist_pqueue_pop(sl, cmp), "zebras");
test_eq(smartlist_len(sl), 0);
OK();
#undef OK
done:
smartlist_free(sl);
}
/** Run unit tests for string-to-void* map functions */
static void
test_container_strmap(void)
{
strmap_t *map;
strmap_iter_t *iter;
const char *k;
void *v;
char *visited = NULL;
smartlist_t *found_keys = NULL;
map = strmap_new();
test_assert(map);
test_eq(strmap_size(map), 0);
test_assert(strmap_isempty(map));
v = strmap_set(map, "K1", (void*)99);
test_eq(v, NULL);
test_assert(!strmap_isempty(map));
v = strmap_set(map, "K2", (void*)101);
test_eq(v, NULL);
v = strmap_set(map, "K1", (void*)100);
test_eq(v, (void*)99);
test_eq_ptr(strmap_get(map,"K1"), (void*)100);
test_eq_ptr(strmap_get(map,"K2"), (void*)101);
test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
strmap_assert_ok(map);
v = strmap_remove(map,"K2");
strmap_assert_ok(map);
test_eq_ptr(v, (void*)101);
test_eq_ptr(strmap_get(map,"K2"), NULL);
test_eq_ptr(strmap_remove(map,"K2"), NULL);
strmap_set(map, "K2", (void*)101);
strmap_set(map, "K3", (void*)102);
strmap_set(map, "K4", (void*)103);
test_eq(strmap_size(map), 4);
strmap_assert_ok(map);
strmap_set(map, "K5", (void*)104);
strmap_set(map, "K6", (void*)105);
strmap_assert_ok(map);
/* Test iterator. */
iter = strmap_iter_init(map);
found_keys = smartlist_create();
while (!strmap_iter_done(iter)) {
strmap_iter_get(iter,&k,&v);
smartlist_add(found_keys, tor_strdup(k));
test_eq_ptr(v, strmap_get(map, k));
if (!strcmp(k, "K2")) {
iter = strmap_iter_next_rmv(map,iter);
} else {
iter = strmap_iter_next(map,iter);
}
}
/* Make sure we removed K2, but not the others. */
test_eq_ptr(strmap_get(map, "K2"), NULL);
test_eq_ptr(strmap_get(map, "K5"), (void*)104);
/* Make sure we visited everyone once */
smartlist_sort_strings(found_keys);
visited = smartlist_join_strings(found_keys, ":", 0, NULL);
test_streq(visited, "K1:K2:K3:K4:K5:K6");
strmap_assert_ok(map);
/* Clean up after ourselves. */
strmap_free(map, NULL);
map = NULL;
/* Now try some lc functions. */
map = strmap_new();
strmap_set_lc(map,"Ab.C", (void*)1);
test_eq_ptr(strmap_get(map,"ab.c"), (void*)1);
strmap_assert_ok(map);
test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1);
test_eq_ptr(strmap_get(map,"AB.C"), NULL);
test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1);
strmap_assert_ok(map);
test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL);
done:
if (map)
strmap_free(map,NULL);
if (found_keys) {
SMARTLIST_FOREACH(found_keys, char *, cp, tor_free(cp));
smartlist_free(found_keys);
}
tor_free(visited);
}
/** Run unit tests for getting the median of a list. */
static void
test_container_order_functions(void)
{
int lst[25], n = 0;
// int a=12,b=24,c=25,d=60,e=77;
#define median() median_int(lst, n)
lst[n++] = 12;
test_eq(12, median()); /* 12 */
lst[n++] = 77;
//smartlist_shuffle(sl);
test_eq(12, median()); /* 12, 77 */
lst[n++] = 77;
//smartlist_shuffle(sl);
test_eq(77, median()); /* 12, 77, 77 */
lst[n++] = 24;
test_eq(24, median()); /* 12,24,77,77 */
lst[n++] = 60;
lst[n++] = 12;
lst[n++] = 25;
//smartlist_shuffle(sl);
test_eq(25, median()); /* 12,12,24,25,60,77,77 */
#undef median
done:
;
}
#define CONTAINER_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_basic),
CONTAINER_LEGACY(smartlist_strings),
CONTAINER_LEGACY(smartlist_overlap),
CONTAINER_LEGACY(smartlist_digests),
CONTAINER_LEGACY(smartlist_join),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
CONTAINER_LEGACY(strmap),
CONTAINER_LEGACY(pqueue),
CONTAINER_LEGACY(order_functions),
END_OF_TESTCASES
};

772
src/test/test_crypto.c Normal file
View File

@ -0,0 +1,772 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2009, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CRYPTO_PRIVATE
#include "or.h"
#include "test.h"
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void)
{
crypto_dh_env_t *dh1 = crypto_dh_new();
crypto_dh_env_t *dh2 = crypto_dh_new();
char p1[DH_BYTES];
char p2[DH_BYTES];
char s1[DH_BYTES];
char s2[DH_BYTES];
ssize_t s1len, s2len;
test_eq(crypto_dh_get_bytes(dh1), DH_BYTES);
test_eq(crypto_dh_get_bytes(dh2), DH_BYTES);
memset(p1, 0, DH_BYTES);
memset(p2, 0, DH_BYTES);
test_memeq(p1, p2, DH_BYTES);
test_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES));
test_memneq(p1, p2, DH_BYTES);
test_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES));
test_memneq(p1, p2, DH_BYTES);
memset(s1, 0, DH_BYTES);
memset(s2, 0xFF, DH_BYTES);
s1len = crypto_dh_compute_secret(dh1, p2, DH_BYTES, s1, 50);
s2len = crypto_dh_compute_secret(dh2, p1, DH_BYTES, s2, 50);
test_assert(s1len > 0);
test_eq(s1len, s2len);
test_memeq(s1, s2, s1len);
{
/* XXXX Now fabricate some bad values and make sure they get caught,
* Check 0, 1, N-1, >= N, etc.
*/
}
done:
crypto_dh_free(dh1);
crypto_dh_free(dh2);
}
/** Run unit tests for our random number generation function and its wrappers.
*/
static void
test_crypto_rng(void)
{
int i, j, allok;
char data1[100], data2[100];
/* Try out RNG. */
test_assert(! crypto_seed_rng(0));
crypto_rand(data1, 100);
crypto_rand(data2, 100);
test_memneq(data1,data2,100);
allok = 1;
for (i = 0; i < 100; ++i) {
uint64_t big;
char *host;
j = crypto_rand_int(100);
if (i < 0 || i >= 100)
allok = 0;
big = crypto_rand_uint64(U64_LITERAL(1)<<40);
if (big >= (U64_LITERAL(1)<<40))
allok = 0;
big = crypto_rand_uint64(U64_LITERAL(5));
if (big >= 5)
allok = 0;
host = crypto_random_hostname(3,8,"www.",".onion");
if (strcmpstart(host,"www.") ||
strcmpend(host,".onion") ||
strlen(host) < 13 ||
strlen(host) > 18)
allok = 0;
tor_free(host);
}
test_assert(allok);
done:
;
}
/** Run unit tests for our AES functionality */
static void
test_crypto_aes(void)
{
char *data1 = NULL, *data2 = NULL, *data3 = NULL;
crypto_cipher_env_t *env1 = NULL, *env2 = NULL;
int i, j;
char *mem_op_hex_tmp=NULL;
data1 = tor_malloc(1024);
data2 = tor_malloc(1024);
data3 = tor_malloc(1024);
/* Now, test encryption and decryption with stream cipher. */
data1[0]='\0';
for (i = 1023; i>0; i -= 35)
strncat(data1, "Now is the time for all good onions", i);
memset(data2, 0, 1024);
memset(data3, 0, 1024);
env1 = crypto_new_cipher_env();
test_neq(env1, 0);
env2 = crypto_new_cipher_env();
test_neq(env2, 0);
j = crypto_cipher_generate_key(env1);
crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
crypto_cipher_encrypt_init_cipher(env1);
crypto_cipher_decrypt_init_cipher(env2);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
crypto_cipher_decrypt(env2, data3, data2, 512);
test_memeq(data1, data3, 512);
test_memneq(data1, data2, 512);
/* Now encrypt 1 at a time, and get 1 at a time. */
for (j = 512; j < 560; ++j) {
crypto_cipher_encrypt(env1, data2+j, data1+j, 1);
}
for (j = 512; j < 560; ++j) {
crypto_cipher_decrypt(env2, data3+j, data2+j, 1);
}
test_memeq(data1, data3, 560);
/* Now encrypt 3 at a time, and get 5 at a time. */
for (j = 560; j < 1024-5; j += 3) {
crypto_cipher_encrypt(env1, data2+j, data1+j, 3);
}
for (j = 560; j < 1024-5; j += 5) {
crypto_cipher_decrypt(env2, data3+j, data2+j, 5);
}
test_memeq(data1, data3, 1024-5);
/* Now make sure that when we encrypt with different chunk sizes, we get
the same results. */
crypto_free_cipher_env(env2);
env2 = NULL;
memset(data3, 0, 1024);
env2 = crypto_new_cipher_env();
test_neq(env2, 0);
crypto_cipher_set_key(env2, crypto_cipher_get_key(env1));
crypto_cipher_encrypt_init_cipher(env2);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
for (j= 0; j < 1024-16; ++j) {
if (data2[j] != data3[j]) {
printf("%d: %d\t%d\n", j, (int) data2[j], (int) data3[j]);
}
}
test_memeq(data2, data3, 1024-16);
crypto_free_cipher_env(env1);
env1 = NULL;
crypto_free_cipher_env(env2);
env2 = NULL;
/* NIST test vector for aes. */
env1 = crypto_new_cipher_env(); /* IV starts at 0 */
crypto_cipher_set_key(env1, "\x80\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00");
crypto_cipher_encrypt_init_cipher(env1);
crypto_cipher_encrypt(env1, data1,
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00", 16);
test_memeq_hex(data1, "0EDD33D3C621E546455BD8BA1418BEC8");
/* Now test rollover. All these values are originally from a python
* script. */
crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\x00\x00\x00\x00"
"\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "335fe6da56f843199066c14a00a40231"
"cdd0b917dbc7186908a6bfb5ffd574d3");
crypto_cipher_set_iv(env1, "\x00\x00\x00\x00\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "e627c6423fa2d77832a02b2794094b73"
"3e63c721df790d2c6469cc1953a3ffac");
crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
memset(data2, 0, 1024);
crypto_cipher_encrypt(env1, data1, data2, 32);
test_memeq_hex(data1, "2aed2bff0de54f9328efd070bf48f70a"
"0EDD33D3C621E546455BD8BA1418BEC8");
/* Now check rollover on inplace cipher. */
crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
test_memeq_hex(data2, "2aed2bff0de54f9328efd070bf48f70a"
"0EDD33D3C621E546455BD8BA1418BEC8"
"93e2c5243d6839eac58503919192f7ae"
"1908e67cafa08d508816659c2e693191");
crypto_cipher_set_iv(env1, "\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
test_assert(tor_mem_is_zero(data2, 64));
done:
tor_free(mem_op_hex_tmp);
if (env1)
crypto_free_cipher_env(env1);
if (env2)
crypto_free_cipher_env(env2);
tor_free(data1);
tor_free(data2);
tor_free(data3);
}
/** Run unit tests for our SHA-1 functionality */
static void
test_crypto_sha(void)
{
crypto_digest_env_t *d1 = NULL, *d2 = NULL;
int i;
char key[80];
char digest[32];
char data[50];
char d_out1[DIGEST_LEN], d_out2[DIGEST256_LEN];
char *mem_op_hex_tmp=NULL;
/* Test SHA-1 with a test vector from the specification. */
i = crypto_digest(data, "abc", 3);
test_memeq_hex(data, "A9993E364706816ABA3E25717850C26C9CD0D89D");
/* Test SHA-256 with a test vector from the specification. */
i = crypto_digest256(data, "abc", 3, DIGEST_SHA256);
test_memeq_hex(data, "BA7816BF8F01CFEA414140DE5DAE2223B00361A3"
"96177A9CB410FF61F20015AD");
/* Test HMAC-SHA-1 with test cases from RFC2202. */
/* Case 1. */
memset(key, 0x0b, 20);
crypto_hmac_sha1(digest, key, 20, "Hi There", 8);
test_streq(hex_str(digest, 20),
"B617318655057264E28BC0B6FB378C8EF146BE00");
/* Case 2. */
crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28);
test_streq(hex_str(digest, 20),
"EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79");
/* Case 4. */
base16_decode(key, 25,
"0102030405060708090a0b0c0d0e0f10111213141516171819", 50);
memset(data, 0xcd, 50);
crypto_hmac_sha1(digest, key, 25, data, 50);
test_streq(hex_str(digest, 20),
"4C9007F4026250C6BC8414F9BF50C86C2D7235DA");
/* Case 5. */
memset(key, 0xaa, 80);
crypto_hmac_sha1(digest, key, 80,
"Test Using Larger Than Block-Size Key - Hash Key First",
54);
test_streq(hex_str(digest, 20),
"AA4AE5E15272D00E95705637CE8A3B55ED402112");
/* Incremental digest code. */
d1 = crypto_new_digest_env();
test_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
test_assert(d2);
crypto_digest_add_bytes(d2, "ghijkl", 6);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdefghijkl", 12);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_assign(d2, d1);
crypto_digest_add_bytes(d2, "mno", 3);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdefmno", 9);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdef", 6);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_free_digest_env(d1);
crypto_free_digest_env(d2);
/* Incremental digest code with sha256 */
d1 = crypto_new_digest256_env(DIGEST_SHA256);
test_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
test_assert(d2);
crypto_digest_add_bytes(d2, "ghijkl", 6);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefghijkl", 12, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_assign(d2, d1);
crypto_digest_add_bytes(d2, "mno", 3);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefmno", 9, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256);
test_memeq(d_out1, d_out2, DIGEST_LEN);
done:
if (d1)
crypto_free_digest_env(d1);
if (d2)
crypto_free_digest_env(d2);
tor_free(mem_op_hex_tmp);
}
/** Run unit tests for our public key crypto functions */
static void
test_crypto_pk(void)
{
crypto_pk_env_t *pk1 = NULL, *pk2 = NULL;
char *encoded = NULL;
char data1[1024], data2[1024], data3[1024];
size_t size;
int i, j, p, len;
/* Public-key ciphers */
pk1 = pk_generate(0);
pk2 = crypto_new_pk_env();
test_assert(pk1 && pk2);
test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size));
test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
test_eq(128, crypto_pk_keysize(pk1));
test_eq(128, crypto_pk_keysize(pk2));
test_eq(128, crypto_pk_public_encrypt(pk2, data1, "Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING));
test_eq(128, crypto_pk_public_encrypt(pk1, data2, "Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING));
/* oaep padding should make encryption not match */
test_memneq(data1, data2, 128);
test_eq(15, crypto_pk_private_decrypt(pk1, data3, data1, 128,
PK_PKCS1_OAEP_PADDING,1));
test_streq(data3, "Hello whirled.");
memset(data3, 0, 1024);
test_eq(15, crypto_pk_private_decrypt(pk1, data3, data2, 128,
PK_PKCS1_OAEP_PADDING,1));
test_streq(data3, "Hello whirled.");
/* Can't decrypt with public key. */
test_eq(-1, crypto_pk_private_decrypt(pk2, data3, data2, 128,
PK_PKCS1_OAEP_PADDING,1));
/* Try again with bad padding */
memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */
test_eq(-1, crypto_pk_private_decrypt(pk1, data3, data2, 128,
PK_PKCS1_OAEP_PADDING,1));
/* File operations: save and load private key */
test_assert(! crypto_pk_write_private_key_to_filename(pk1,
get_fname("pkey1")));
/* failing case for read: can't read. */
test_assert(crypto_pk_read_private_key_from_filename(pk2,
get_fname("xyzzy")) < 0);
write_str_to_file(get_fname("xyzzy"), "foobar", 6);
/* Failing case for read: no key. */
test_assert(crypto_pk_read_private_key_from_filename(pk2,
get_fname("xyzzy")) < 0);
test_assert(! crypto_pk_read_private_key_from_filename(pk2,
get_fname("pkey1")));
test_eq(15, crypto_pk_private_decrypt(pk2, data3, data1, 128,
PK_PKCS1_OAEP_PADDING,1));
/* Now try signing. */
strlcpy(data1, "Ossifrage", 1024);
test_eq(128, crypto_pk_private_sign(pk1, data2, data1, 10));
test_eq(10, crypto_pk_public_checksig(pk1, data3, data2, 128));
test_streq(data3, "Ossifrage");
/* Try signing digests. */
test_eq(128, crypto_pk_private_sign_digest(pk1, data2, data1, 10));
test_eq(20, crypto_pk_public_checksig(pk1, data3, data2, 128));
test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128));
test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128));
/*XXXX test failed signing*/
/* Try encoding */
crypto_free_pk_env(pk2);
pk2 = NULL;
i = crypto_pk_asn1_encode(pk1, data1, 1024);
test_assert(i>0);
pk2 = crypto_pk_asn1_decode(data1, i);
test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
/* Try with hybrid encryption wrappers. */
crypto_rand(data1, 1024);
for (i = 0; i < 3; ++i) {
for (j = 85; j < 140; ++j) {
memset(data2,0,1024);
memset(data3,0,1024);
if (i == 0 && j < 129)
continue;
p = (i==0)?PK_NO_PADDING:
(i==1)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
len = crypto_pk_public_hybrid_encrypt(pk1,data2,data1,j,p,0);
test_assert(len>=0);
len = crypto_pk_private_hybrid_decrypt(pk1,data3,data2,len,p,1);
test_eq(len,j);
test_memeq(data1,data3,j);
}
}
/* Try copy_full */
crypto_free_pk_env(pk2);
pk2 = crypto_pk_copy_full(pk1);
test_assert(pk2 != NULL);
test_neq_ptr(pk1, pk2);
test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
done:
if (pk1)
crypto_free_pk_env(pk1);
if (pk2)
crypto_free_pk_env(pk2);
tor_free(encoded);
}
/** Run unit tests for misc crypto formatting functionality (base64, base32,
* fingerprints, etc) */
static void
test_crypto_formats(void)
{
char *data1 = NULL, *data2 = NULL, *data3 = NULL;
int i, j, idx;
data1 = tor_malloc(1024);
data2 = tor_malloc(1024);
data3 = tor_malloc(1024);
test_assert(data1 && data2 && data3);
/* Base64 tests */
memset(data1, 6, 1024);
for (idx = 0; idx < 10; ++idx) {
i = base64_encode(data2, 1024, data1, idx);
test_assert(i >= 0);
j = base64_decode(data3, 1024, data2, i);
test_eq(j,idx);
test_memeq(data3, data1, idx);
}
strlcpy(data1, "Test string that contains 35 chars.", 1024);
strlcat(data1, " 2nd string that contains 35 chars.", 1024);
i = base64_encode(data2, 1024, data1, 71);
j = base64_decode(data3, 1024, data2, i);
test_eq(j, 71);
test_streq(data3, data1);
test_assert(data2[i] == '\0');
crypto_rand(data1, DIGEST_LEN);
memset(data2, 100, 1024);
digest_to_base64(data2, data1);
test_eq(BASE64_DIGEST_LEN, strlen(data2));
test_eq(100, data2[BASE64_DIGEST_LEN+2]);
memset(data3, 99, 1024);
test_eq(digest_from_base64(data3, data2), 0);
test_memeq(data1, data3, DIGEST_LEN);
test_eq(99, data3[DIGEST_LEN+1]);
test_assert(digest_from_base64(data3, "###") < 0);
/* Base32 tests */
strlcpy(data1, "5chrs", 1024);
/* bit pattern is: [35 63 68 72 73] ->
* [00110101 01100011 01101000 01110010 01110011]
* By 5s: [00110 10101 10001 10110 10000 11100 10011 10011]
*/
base32_encode(data2, 9, data1, 5);
test_streq(data2, "gvrwq4tt");
strlcpy(data1, "\xFF\xF5\x6D\x44\xAE\x0D\x5C\xC9\x62\xC4", 1024);
base32_encode(data2, 30, data1, 10);
test_streq(data2, "772w2rfobvomsywe");
/* Base16 tests */
strlcpy(data1, "6chrs\xff", 1024);
base16_encode(data2, 13, data1, 6);
test_streq(data2, "3663687273FF");
strlcpy(data1, "f0d678affc000100", 1024);
i = base16_decode(data2, 8, data1, 16);
test_eq(i,0);
test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8);
/* now try some failing base16 decodes */
test_eq(-1, base16_decode(data2, 8, data1, 15)); /* odd input len */
test_eq(-1, base16_decode(data2, 7, data1, 16)); /* dest too short */
strlcpy(data1, "f0dz!8affc000100", 1024);
test_eq(-1, base16_decode(data2, 8, data1, 16));
tor_free(data1);
tor_free(data2);
tor_free(data3);
/* Add spaces to fingerprint */
{
data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000");
test_eq(strlen(data1), 40);
data2 = tor_malloc(FINGERPRINT_LEN+1);
add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1);
test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000");
tor_free(data1);
tor_free(data2);
}
/* Check fingerprint */
{
test_assert(crypto_pk_check_fingerprint_syntax(
"ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000"));
test_assert(!crypto_pk_check_fingerprint_syntax(
"ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 000"));
test_assert(!crypto_pk_check_fingerprint_syntax(
"ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
test_assert(!crypto_pk_check_fingerprint_syntax(
"ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 0000"));
test_assert(!crypto_pk_check_fingerprint_syntax(
"ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 00000"));
test_assert(!crypto_pk_check_fingerprint_syntax(
"ACD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
}
done:
tor_free(data1);
tor_free(data2);
tor_free(data3);
}
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
static void
test_crypto_s2k(void)
{
char buf[29];
char buf2[29];
char *buf3 = NULL;
int i;
memset(buf, 0, sizeof(buf));
memset(buf2, 0, sizeof(buf2));
buf3 = tor_malloc(65536);
memset(buf3, 0, 65536);
secret_to_key(buf+9, 20, "", 0, buf);
crypto_digest(buf2+9, buf3, 1024);
test_memeq(buf, buf2, 29);
memcpy(buf,"vrbacrda",8);
memcpy(buf2,"vrbacrda",8);
buf[8] = 96;
buf2[8] = 96;
secret_to_key(buf+9, 20, "12345678", 8, buf);
for (i = 0; i < 65536; i += 16) {
memcpy(buf3+i, "vrbacrda12345678", 16);
}
crypto_digest(buf2+9, buf3, 65536);
test_memeq(buf, buf2, 29);
done:
tor_free(buf3);
}
/** Test AES-CTR encryption and decryption with IV. */
static void
test_crypto_aes_iv(void)
{
crypto_cipher_env_t *cipher;
char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2;
char plain_1[1], plain_15[15], plain_16[16], plain_17[17];
char key1[16], key2[16];
ssize_t encrypted_size, decrypted_size;
plain = tor_malloc(4095);
encrypted1 = tor_malloc(4095 + 1 + 16);
encrypted2 = tor_malloc(4095 + 1 + 16);
decrypted1 = tor_malloc(4095 + 1);
decrypted2 = tor_malloc(4095 + 1);
crypto_rand(plain, 4095);
crypto_rand(key1, 16);
crypto_rand(key2, 16);
crypto_rand(plain_1, 1);
crypto_rand(plain_15, 15);
crypto_rand(plain_16, 16);
crypto_rand(plain_17, 17);
key1[0] = key2[0] + 128; /* Make sure that contents are different. */
/* Encrypt and decrypt with the same key. */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 4095,
plain, 4095);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 4095);
tor_assert(encrypted_size > 0); /* This is obviously true, since 4111 is
* greater than 0, but its truth is not
* obvious to all analysis tools. */
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(decrypted_size, 4095);
tor_assert(decrypted_size > 0);
test_memeq(plain, decrypted1, 4095);
/* Encrypt a second time (with a new random initialization vector). */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted2, 16 + 4095,
plain, 4095);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 4095);
tor_assert(encrypted_size > 0);
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
encrypted2, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(decrypted_size, 4095);
tor_assert(decrypted_size > 0);
test_memeq(plain, decrypted2, 4095);
test_memneq(encrypted1, encrypted2, encrypted_size);
/* Decrypt with the wrong key. */
cipher = crypto_create_init_cipher(key2, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted2, 4095,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_memneq(plain, decrypted2, encrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 4095,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_memneq(plain, decrypted2, 4095);
/* Special length case: 1. */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 1,
plain_1, 1);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 1);
tor_assert(encrypted_size > 0);
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 1,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(decrypted_size, 1);
tor_assert(decrypted_size > 0);
test_memeq(plain_1, decrypted1, 1);
/* Special length case: 15. */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 15,
plain_15, 15);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 15);
tor_assert(encrypted_size > 0);
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 15,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(decrypted_size, 15);
tor_assert(decrypted_size > 0);
test_memeq(plain_15, decrypted1, 15);
/* Special length case: 16. */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 16,
plain_16, 16);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 16);
tor_assert(encrypted_size > 0);
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 16,
encrypted1, encrypted_size);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(decrypted_size, 16);
tor_assert(decrypted_size > 0);
test_memeq(plain_16, decrypted1, 16);
/* Special length case: 17. */
cipher = crypto_create_init_cipher(key1, 1);
encrypted_size = crypto_cipher_encrypt_with_iv(cipher, encrypted1, 16 + 17,
plain_17, 17);
crypto_free_cipher_env(cipher);
cipher = NULL;
test_eq(encrypted_size, 16 + 17);
tor_assert(encrypted_size > 0);
cipher = crypto_create_init_cipher(key1, 0);
decrypted_size = crypto_cipher_decrypt_with_iv(cipher, decrypted1, 17,
encrypted1, encrypted_size);
test_eq(decrypted_size, 17);
tor_assert(decrypted_size > 0);
test_memeq(plain_17, decrypted1, 17);
done:
/* Free memory. */
tor_free(plain);
tor_free(encrypted1);
tor_free(encrypted2);
tor_free(decrypted1);
tor_free(decrypted2);
if (cipher)
crypto_free_cipher_env(cipher);
}
/** Test base32 decoding. */
static void
test_crypto_base32_decode(void)
{
char plain[60], encoded[96 + 1], decoded[60];
int res;
crypto_rand(plain, 60);
/* Encode and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
res = base32_decode(decoded, 60, encoded, 96);
test_eq(res, 0);
test_memeq(plain, decoded, 60);
/* Encode, uppercase, and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
tor_strupper(encoded);
res = base32_decode(decoded, 60, encoded, 96);
test_eq(res, 0);
test_memeq(plain, decoded, 60);
/* Change encoded string and decode. */
if (encoded[0] == 'A' || encoded[0] == 'a')
encoded[0] = 'B';
else
encoded[0] = 'A';
res = base32_decode(decoded, 60, encoded, 96);
test_eq(res, 0);
test_memneq(plain, decoded, 60);
/* Bad encodings. */
encoded[0] = '!';
res = base32_decode(decoded, 60, encoded, 96);
test_assert(res < 0);
done:
;
}
#define CRYPTO_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_crypto_ ## name }
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
CRYPTO_LEGACY(rng),
CRYPTO_LEGACY(aes),
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
CRYPTO_LEGACY(dh),
CRYPTO_LEGACY(s2k),
CRYPTO_LEGACY(aes_iv),
CRYPTO_LEGACY(base32_decode),
END_OF_TESTCASES
};

1099
src/test/test_dir.c Normal file

File diff suppressed because it is too large Load Diff

1044
src/test/test_util.c Normal file

File diff suppressed because it is too large Load Diff

369
src/test/tinytest.c Normal file
View File

@ -0,0 +1,369 @@
/* tinytest.c -- Copyright 2009 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
#ifndef __GNUC__
#define __attribute__(x)
#endif
#include "tinytest.h"
#include "tinytest_macros.h"
#define LONGEST_TEST_NAME 16384
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
static int n_ok = 0; /**< Number of tests that have passed */
static int n_bad = 0; /**< Number of tests that have failed. */
static int n_skipped = 0; /**< Number of tests that have been skipped. */
static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
const char *verbosity_flag = "";
enum outcome { SKIP=2, OK=1, FAIL=0 };
static enum outcome cur_test_outcome = 0;
const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */
const char *cur_test_name = NULL;
#ifdef WIN32
/** Pointer to argv[0] for win32. */
static const char *commandname = NULL;
#endif
static void usage(struct testgroup_t *groups, int list_groups)
__attribute__((noreturn));
static enum outcome
_testcase_run_bare(const struct testcase_t *testcase)
{
void *env = NULL;
int outcome;
if (testcase->setup) {
env = testcase->setup->setup_fn(testcase);
if (!env)
return FAIL;
else if (env == (void*)TT_SKIP)
return SKIP;
}
cur_test_outcome = OK;
testcase->fn(env);
outcome = cur_test_outcome;
if (testcase->setup) {
if (testcase->setup->cleanup_fn(testcase, env) == 0)
outcome = FAIL;
}
return outcome;
}
#define MAGIC_EXITCODE 42
static enum outcome
_testcase_run_forked(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
#ifdef WIN32
/* Fork? On Win32? How primitive! We'll do what the smart kids do:
we'll invoke our own exe (whose name we recall from the command
line) with a command line that tells it to run just the test we
want, and this time without forking.
(No, threads aren't an option. The whole point of forking is to
share no state between tests.)
*/
int ok;
char buffer[LONGEST_TEST_NAME+256];
STARTUPINFO si;
PROCESS_INFORMATION info;
DWORD exitcode;
if (!in_tinytest_main) {
printf("\nERROR. On Windows, _testcase_run_forked must be"
" called from within tinytest_main.\n");
abort();
}
if (opt_verbosity>0)
printf("[forking] ");
snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
commandname, verbosity_flag, group->prefix, testcase->name);
memset(&si, 0, sizeof(si));
memset(&info, 0, sizeof(info));
si.cb = sizeof(si);
ok = CreateProcess(commandname, buffer, NULL, NULL, 0,
0, NULL, NULL, &si, &info);
if (!ok) {
printf("CreateProcess failed!\n");
return 0;
}
WaitForSingleObject(info.hProcess, INFINITE);
GetExitCodeProcess(info.hProcess, &exitcode);
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
if (exitcode == 0)
return OK;
else if (exitcode == MAGIC_EXITCODE)
return SKIP;
else
return FAIL;
#else
int outcome_pipe[2];
pid_t pid;
(void)group;
if (pipe(outcome_pipe))
perror("opening pipe");
if (opt_verbosity>0)
printf("[forking] ");
pid = fork();
if (!pid) {
/* child. */
int test_r, write_r;
char b[1];
close(outcome_pipe[0]);
test_r = _testcase_run_bare(testcase);
assert(0<=(int)test_r && (int)test_r<=2);
b[0] = "NYS"[test_r];
write_r = (int)write(outcome_pipe[1], b, 1);
if (write_r != 1) {
perror("write outcome to pipe");
exit(1);
}
exit(0);
} else {
/* parent */
int status, r;
char b[1];
/* Close this now, so that if the other side closes it,
* our read fails. */
close(outcome_pipe[1]);
r = (int)read(outcome_pipe[0], b, 1);
if (r == 0) {
printf("[Lost connection!] ");
return 0;
} else if (r != 1) {
perror("read outcome from pipe");
}
waitpid(pid, &status, 0);
close(outcome_pipe[0]);
return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
}
#endif
}
int
testcase_run_one(const struct testgroup_t *group,
const struct testcase_t *testcase)
{
enum outcome outcome;
if (testcase->flags & TT_SKIP) {
if (opt_verbosity>0)
printf("%s%s: SKIPPED\n",
group->prefix, testcase->name);
++n_skipped;
return SKIP;
}
if (opt_verbosity>0 && !opt_forked) {
printf("%s%s: ", group->prefix, testcase->name);
} else {
if (opt_verbosity==0) printf(".");
cur_test_prefix = group->prefix;
cur_test_name = testcase->name;
}
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
outcome = _testcase_run_forked(group, testcase);
} else {
outcome = _testcase_run_bare(testcase);
}
if (outcome == OK) {
++n_ok;
if (opt_verbosity>0 && !opt_forked)
puts(opt_verbosity==1?"OK":"");
} else if (outcome == SKIP) {
++n_skipped;
if (opt_verbosity>0 && !opt_forked)
puts("SKIPPED");
} else {
++n_bad;
if (!opt_forked)
printf("\n [%s FAILED]\n", testcase->name);
}
if (opt_forked) {
exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
} else {
return (int)outcome;
}
}
int
_tinytest_set_flag(struct testgroup_t *groups, const char *arg, unsigned long flag)
{
int i, j;
size_t length = LONGEST_TEST_NAME;
char fullname[LONGEST_TEST_NAME];
int found=0;
if (strstr(arg, ".."))
length = strstr(arg,"..")-arg;
for (i=0; groups[i].prefix; ++i) {
for (j=0; groups[i].cases[j].name; ++j) {
snprintf(fullname, sizeof(fullname), "%s%s",
groups[i].prefix, groups[i].cases[j].name);
if (!flag) /* Hack! */
printf(" %s\n", fullname);
if (!strncmp(fullname, arg, length)) {
groups[i].cases[j].flags |= flag;
++found;
}
}
}
return found;
}
static void
usage(struct testgroup_t *groups, int list_groups)
{
puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
puts(" Specify tests by name, or using a prefix ending with '..'");
puts(" Use --list-tests for a list of tests.");
if (list_groups) {
puts("Known tests are:");
_tinytest_set_flag(groups, "..", 0);
}
exit(0);
}
int
tinytest_main(int c, const char **v, struct testgroup_t *groups)
{
int i, j, n=0;
#ifdef WIN32
commandname = v[0];
#endif
for (i=1; i<c; ++i) {
if (v[i][0] == '-') {
if (!strcmp(v[i], "--RUNNING-FORKED")) {
opt_forked = 1;
} else if (!strcmp(v[i], "--no-fork")) {
opt_nofork = 1;
} else if (!strcmp(v[i], "--quiet")) {
opt_verbosity = -1;
verbosity_flag = "--quiet";
} else if (!strcmp(v[i], "--verbose")) {
opt_verbosity = 2;
verbosity_flag = "--verbose";
} else if (!strcmp(v[i], "--terse")) {
opt_verbosity = 0;
verbosity_flag = "--terse";
} else if (!strcmp(v[i], "--help")) {
usage(groups, 0);
} else if (!strcmp(v[i], "--list-tests")) {
usage(groups, 1);
} else {
printf("Unknown option %s. Try --help\n",v[i]);
return -1;
}
} else {
++n;
if (!_tinytest_set_flag(groups, v[i], _TT_ENABLED)) {
printf("No such test as %s!\n", v[i]);
return -1;
}
}
}
if (!n)
_tinytest_set_flag(groups, "..", _TT_ENABLED);
setvbuf(stdout, NULL, _IONBF, 0);
++in_tinytest_main;
for (i=0; groups[i].prefix; ++i)
for (j=0; groups[i].cases[j].name; ++j)
if (groups[i].cases[j].flags & _TT_ENABLED)
testcase_run_one(&groups[i],
&groups[i].cases[j]);
--in_tinytest_main;
if (opt_verbosity==0)
puts("");
if (n_bad)
printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
n_bad+n_ok,n_skipped);
else if (opt_verbosity >= 1)
printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
return (n_bad == 0) ? 0 : 1;
}
int
_tinytest_get_verbosity(void)
{
return opt_verbosity;
}
void
_tinytest_set_test_failed(void)
{
if (opt_verbosity <= 0 && cur_test_name) {
if (opt_verbosity==0) puts("");
printf("%s%s: ", cur_test_prefix, cur_test_name);
cur_test_name = NULL;
}
cur_test_outcome = 0;
}
void
_tinytest_set_test_skipped(void)
{
if (cur_test_outcome==OK)
cur_test_outcome = SKIP;
}

87
src/test/tinytest.h Normal file
View File

@ -0,0 +1,87 @@
/* tinytest.h -- Copyright 2009 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TINYTEST_H
#define _TINYTEST_H
/** Flag for a test that needs to run in a subprocess. */
#define TT_FORK (1<<0)
/** Runtime flag for a test we've decided to skip. */
#define TT_SKIP (1<<1)
/** Internal runtime flag for a test we've decided to run. */
#define _TT_ENABLED (1<<2)
/** If you add your own flags, make them start at this point. */
#define TT_FIRST_USER_FLAG (1<<3)
typedef void (*testcase_fn)(void *);
struct testcase_t;
/** Functions to initialize/teardown a structure for a testcase. */
struct testcase_setup_t {
/** Return a new structure for use by a given testcase. */
void *(*setup_fn)(const struct testcase_t *);
/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
int (*cleanup_fn)(const struct testcase_t *, void *);
};
/** A single test-case that you can run. */
struct testcase_t {
const char *name; /**< An identifier for this case. */
testcase_fn fn; /**< The function to run to implement this case. */
unsigned long flags; /**< Bitfield of TT_* flags. */
const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
void *setup_data; /**< Extra data usable by setup function */
};
#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
/** A group of tests that are selectable together. */
struct testgroup_t {
const char *prefix; /**< Prefix to prepend to testnames. */
struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
};
#define END_OF_GROUPS { NULL, NULL}
/** Implementation: called from a test to indicate failure, before logging. */
void _tinytest_set_test_failed(void);
/** Implementation: called from a test to indicate that we're skipping. */
void _tinytest_set_test_skipped(void);
/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
int _tinytest_get_verbosity(void);
/** Implementation: Set a flag on tests matching a name; returns number
* of tests that matched. */
int _tinytest_set_flag(struct testgroup_t *, const char *, unsigned long);
/** Set all tests in 'groups' matching the name 'named' to be skipped. */
#define tinytest_skip(groups, named) \
_tinytest_set_flag(groups, named, TT_SKIP)
/** Run a single testcase in a single group. */
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
as selected from the command line. */
int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
#endif

215
src/test/tinytest_demo.c Normal file
View File

@ -0,0 +1,215 @@
/* tinytest_demo.c -- Copyright 2009 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Welcome to the example file for tinytest! I'll show you how to set up
* some simple and not-so-simple testcases. */
/* Make sure you include these headers. */
#include "tinytest.h"
#include "tinytest_macros.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* ============================================================ */
/* First, let's see if strcmp is working. (All your test cases should be
* functions declared to take a single void * as) an argument. */
void
test_strcmp(void *data)
{
(void)data; /* This testcase takes no data. */
/* Let's make sure the empty string is equal to itself */
if (strcmp("","")) {
/* This macro tells tinytest to stop the current test
* and go straight to the "end" label. */
tt_abort_msg("The empty string was not equal to itself");
}
/* Pretty often, calling tt_abort_msg to indicate failure is more
heavy-weight than you want. Instead, just say: */
tt_assert(strcmp("testcase", "testcase") == 0);
/* Occasionally, you don't want to stop the current testcase just
because a single assertion has failed. In that case, use
tt_want: */
tt_want(strcmp("tinytest", "testcase") > 0);
/* You can use the tt_*_op family of macros to compare values and to
fail unless they have the relationship you want. They produce
more useful output than tt_assert, since they display the actual
values of the failing things.
Fail unless strcmp("abc, "abc") == 0 */
tt_int_op(strcmp("abc", "abc"), ==, 0);
/* Fail unless strcmp("abc, "abcd") is less than 0 */
tt_int_op(strcmp("abc", "abcd"), < , 0);
/* Incidentally, there's a test_str_op that uses strcmp internally. */
tt_str_op("abc", <, "abcd");
/* Every test-case function needs to finish with an "end:"
label and (optionally) code to clean up local variables. */
end:
;
}
/* ============================================================ */
/* Now let's mess with setup and teardown functions! These are handy if
you have a bunch of tests that all need a similar environment, and you
wnat to reconstruct that environment freshly for each one. */
/* First you declare a type to hold the environment info, and functions to
set it up and tear it down. */
struct data_buffer {
/* We're just going to have couple of character buffer. Using
setup/teardown functions is probably overkill for this case.
You could also do file descriptors, complicated handles, temporary
files, etc. */
char buffer1[512];
char buffer2[512];
};
/* The setup function needs to take a const struct testcase_t and return
void* */
void *
setup_data_buffer(const struct testcase_t *testcase)
{
struct data_buffer *db = malloc(sizeof(struct data_buffer));
/* If you had a complicated set of setup rules, you might behave
differently here depending on testcase->flags or
testcase->setup_data or even or testcase->name. */
/* Returning a NULL here would mean that we couldn't set up for this
test, so we don't need to test db for null. */
return db;
}
/* The clean function deallocates storage carefully and returns true on
success. */
int
clean_data_buffer(const struct testcase_t *testcase, void *ptr)
{
struct data_buffer *db = ptr;
if (db) {
free(db);
return 1;
}
return 0;
}
/* Finally, declare a testcase_setup_t with these functions. */
struct testcase_setup_t data_buffer_setup = {
setup_data_buffer, clean_data_buffer
};
/* Now let's write our test. */
void
test_memcpy(void *ptr)
{
/* This time, we use the argument. */
struct data_buffer *db = ptr;
/* We'll also introduce a local variable that might need cleaning up. */
char *mem = NULL;
/* Let's make sure that memcpy does what we'd like. */
strcpy(db->buffer1, "String 0");
memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
tt_str_op(db->buffer1, ==, db->buffer2);
/* Now we've allocated memory that's referenced by a local variable.
The end block of the function will clean it up. */
mem = strdup("Hello world.");
tt_assert(mem);
/* Another rather trivial test. */
tt_str_op(db->buffer1, !=, mem);
end:
/* This time our end block has something to do. */
if (mem)
free(mem);
}
/* ============================================================ */
/* Now we need to make sure that our tests get invoked. First, you take
a bunch of related tests and put them into an array of struct testcase_t.
*/
struct testcase_t demo_tests[] = {
/* Here's a really simple test: it has a name you can refer to it
with, and a function to invoke it. */
{ "strcmp", test_strcmp, },
/* The second test has a flag, "TT_FORK", to make it run in a
subprocess, and a pointer to the testcase_setup_t that configures
its environment. */
{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
/* The array has to end with END_OF_TESTCASES. */
END_OF_TESTCASES
};
/* Next, we make an array of testgroups. This is mandatory. Unlike more
heavy-duty testing frameworks, groups can't nest. */
struct testgroup_t groups[] = {
/* Every group has a 'prefix', and an array of tests. That's it. */
{ "demo/", demo_tests },
END_OF_GROUPS
};
int
main(int c, const char **v)
{
/* Finally, just call tinytest_main(). It lets you specify verbose
or quiet output with --verbose and --quiet. You can list
specific tests:
tinytest-demo demo/memcpy
or use a ..-wildcard to select multiple tests with a common
prefix:
tinytest-demo demo/..
If you list no tests, you get them all by default, so that
"tinytest-demo" and "tinytest-demo .." mean the same thing.
*/
return tinytest_main(c, v, groups);
}

167
src/test/tinytest_macros.h Normal file
View File

@ -0,0 +1,167 @@
/* tinytest_macros.h -- Copyright 2009 Nick Mathewson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TINYTEST_MACROS_H
#define _TINYTEST_MACROS_H
/* Helpers for defining statement-like macros */
#define TT_STMT_BEGIN do {
#define TT_STMT_END } while(0)
/* Redefine this if your test functions want to abort with something besides
* "goto end;" */
#ifndef TT_EXIT_TEST_FUNCTION
#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
#endif
/* Redefine this if you want to note success/failure in some different way. */
#ifndef TT_DECLARE
#define TT_DECLARE(prefix, args) \
TT_STMT_BEGIN \
printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
printf args ; \
TT_STMT_END
#endif
/* Announce a failure. Args are parenthesized printf args. */
#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
/* Announce a non-failure if we're verbose. */
#define TT_BLATHER(args) \
TT_STMT_BEGIN \
if (_tinytest_get_verbosity()>1) TT_DECLARE(" OK", args); \
TT_STMT_END
#define TT_DIE(args) \
TT_STMT_BEGIN \
_tinytest_set_test_failed(); \
TT_GRIPE(args); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
#define TT_FAIL(args) \
TT_STMT_BEGIN \
_tinytest_set_test_failed(); \
TT_GRIPE(args); \
TT_STMT_END
/* Fail and abort the current test for the reason in msg */
#define tt_abort_printf(msg) TT_DIE(msg)
#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
#define tt_abort_msg(msg) TT_DIE(("%s", msg))
#define tt_abort() TT_DIE(("%s", "(Failed.)"))
/* Fail but do not abort the current test for the reason in msg. */
#define tt_fail_printf(msg) TT_FAIL(msg)
#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
/* End the current test, and indicate we are skipping it. */
#define tt_skip() \
TT_STMT_BEGIN \
_tinytest_set_test_skipped(); \
TT_EXIT_TEST_FUNCTION; \
TT_STMT_END
#define _tt_want(b, msg, fail) \
TT_STMT_BEGIN \
if (!(b)) { \
_tinytest_set_test_failed(); \
TT_GRIPE((msg)); \
fail; \
} else { \
TT_BLATHER((msg)); \
} \
TT_STMT_END
/* Assert b, but do not stop the test if b fails. Log msg on failure. */
#define tt_want_msg(b, msg) \
_tt_want(b, msg, );
/* Assert b and stop the test if b fails. Log msg on failure. */
#define tt_assert_msg(b, msg) \
_tt_want(b, msg, TT_EXIT_TEST_FUNCTION);
/* Assert b, but do not stop the test if b fails. */
#define tt_want(b) tt_want_msg( (b), "want("#b")")
/* Assert b, and stop the test if b fails. */
#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
setup_block,cleanup_block) \
TT_STMT_BEGIN \
type _val1 = (type)(a); \
type _val2 = (type)(b); \
int _tt_status = (test); \
if (!_tt_status || _tinytest_get_verbosity()>1) { \
printf_type _print; \
printf_type _print1; \
printf_type _print2; \
type _value = _val1; \
setup_block; \
_print1 = _print; \
_value = _val2; \
setup_block; \
_print2 = _print; \
TT_DECLARE(_tt_status?" OK":"FAIL", \
("assert(%s): "printf_fmt" vs "printf_fmt, \
str_test, _print1, _print2)); \
_print = _print1; \
cleanup_block; \
_print = _print2; \
cleanup_block; \
if (!_tt_status) { \
_tinytest_set_test_failed(); \
TT_EXIT_TEST_FUNCTION; \
} \
} \
TT_STMT_END
#define tt_assert_test_type(a,b,str_test,type,test,fmt) \
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
{_print=_value;},{})
/* Helper: assert that a op b, when cast to type. Format the values with
* printf format fmt on failure. */
#define tt_assert_op_type(a,op,b,type,fmt) \
tt_assert_test_type(a,b,#a" "#op" "#b,type,(_val1 op _val2),fmt)
#define tt_int_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,long,(_val1 op _val2),"%ld")
#define tt_uint_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
(_val1 op _val2),"%lu")
#define tt_ptr_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
(_val1 op _val2),"%p")
#define tt_str_op(a,op,b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
(strcmp(_val1,_val2) op 0),"<%s>")
#endif

View File

@ -226,5 +226,5 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
#define VERSION "0.2.2.3-alpha"
#define VERSION "0.2.2.4-alpha"